mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-08-01 02:42:05 -04:00
* Added Database checks to the onboarding flow * Added compatibility page setup Added more compatibility questions * Finished up the onboarding flow suite Added compatibility question tests and verifications Updated tests to cover Keywords and Headline changes recently made Updated tests to cover all of the big5 personality traits * . * Fix: Merge conflict * . * Fix: Added fix for None discriptive error issue #36 Updated signUp.spec.ts to use new fixture Updated Account information variable names Deleted "deleteUserFixture.ts" as it was incorporated into the "base.ts" file * Linting and Prettier * Minor cleaning * Added Google account to the Onboarding flow * Added account cleanup for google accounts * Started work on Sign-in tests Updated seedDatabase.ts to throw an error if the user already exists, to also add display names and usernames so they seedUser func acts like a normal basic user Some organising of the google auth code * Linting and Prettier * Added checks to the deleteUser func to check if the accout exists Added account deletion checks * Linting and Prettier * Formatting update, fixed homePage locator for signin * . * . * . * Coderabbitai fix's * Fix * Improve test utilities and stabilize onboarding flow tests * Changes requested * Changed POM/Fixture structure to use an app class to instantiate the page objects * Apply suggestion from @MartinBraquet * Delete .vscode/settings.json * Apply suggestion from @MartinBraquet * Apply suggestion from @MartinBraquet * Apply suggestion from @MartinBraquet * Linting and Prettier * Updated People page * Fix app.ts * Updated peoplePage.ts: continued adding functions to use filters Updated filters.tsx: added data testid * Coderabbitai fix's * . * Updated People page Added data test attributes to search.tsx and profile-grid.tsx * Lint and Prettier * . * Continued work on filter tests Added testid attributes to people page so the info from the results can be accessed * Added more filter tests * Added tests for hiding profiles * Added a context manager to test with multiple accounts interacting with each other Added an option to verify the users email when creating an account * Added Tests for sending/recieving messages Added tests for staring/favoriting profiles Added testIds where necessary Added messagesPage.ts Updated peoplePage.ts * Linting and Prettier * Coderabbit suggestions * CodeRabbit suggestion #2 * Fix #1 * Minor fixes * TC fix --------- Co-authored-by: MartinBraquet <martin.braquet@gmail.com>
194 lines
7.1 KiB
TypeScript
194 lines
7.1 KiB
TypeScript
import clsx from 'clsx'
|
|
import {ChatMessage} from 'common/chat-message'
|
|
import {PrivateMessageChannel} from 'common/supabase/private-messages'
|
|
import {User} from 'common/user'
|
|
import {parseJsonContentToText} from 'common/util/parse'
|
|
import Link from 'next/link'
|
|
import {Col} from 'web/components/layout/col'
|
|
import {Row} from 'web/components/layout/row'
|
|
import {EmailVerificationPrompt} from 'web/components/messaging/email-verification-prompt'
|
|
import NewMessageButton from 'web/components/messaging/new-message-button'
|
|
import {MultipleOrSingleAvatars} from 'web/components/multiple-or-single-avatars'
|
|
import {PageBase} from 'web/components/page-base'
|
|
import {RelativeTimestamp} from 'web/components/relative-timestamp'
|
|
import {SEO} from 'web/components/SEO'
|
|
import {Avatar} from 'web/components/widgets/avatar'
|
|
import {BannedBadge} from 'web/components/widgets/user-link'
|
|
import {useFirebaseUser} from 'web/hooks/use-firebase-user'
|
|
import {useLastPrivateMessages} from 'web/hooks/use-last-private-messages'
|
|
import {
|
|
useSortedPrivateMessageMemberships,
|
|
useUnseenPrivateMessageChannels,
|
|
} from 'web/hooks/use-private-messages'
|
|
import {useRedirectIfSignedOut} from 'web/hooks/use-redirect-if-signed-out'
|
|
import {useUser} from 'web/hooks/use-user'
|
|
import {useUsersInStore} from 'web/hooks/use-user-supabase'
|
|
import {useT} from 'web/lib/locale'
|
|
|
|
export default function MessagesPage() {
|
|
useRedirectIfSignedOut()
|
|
|
|
const currentUser = useUser()
|
|
const firebaseUser = useFirebaseUser()
|
|
const t = useT()
|
|
return (
|
|
<PageBase trackPageView={'messages page'} className={'py-2 px-2 xl:!px-6'}>
|
|
<SEO
|
|
title={t('messages.title', 'Messages')}
|
|
description={t('messages.seo.description', 'Your Messages')}
|
|
url={`/messages`}
|
|
/>
|
|
{currentUser &&
|
|
firebaseUser &&
|
|
(firebaseUser?.emailVerified ? (
|
|
<MessagesContent currentUser={currentUser} />
|
|
) : (
|
|
<EmailVerificationPrompt t={t} />
|
|
))}
|
|
</PageBase>
|
|
)
|
|
}
|
|
|
|
export function MessagesContent(props: {currentUser: User}) {
|
|
const {currentUser} = props
|
|
const t = useT()
|
|
const {channels, memberIdsByChannelId} = useSortedPrivateMessageMemberships(currentUser.id)
|
|
const {lastSeenChatTimeByChannelId} = useUnseenPrivateMessageChannels(true)
|
|
const lastMessages = useLastPrivateMessages(currentUser.id)
|
|
|
|
return (
|
|
<>
|
|
<Row className="justify-between items-center mb-4">
|
|
<h1 className="font-cormorant text-4xl font-medium text-ink-900">
|
|
{t('messages.title', 'Messages')}
|
|
</h1>
|
|
<NewMessageButton />
|
|
</Row>
|
|
<Col className={'w-full overflow-hidden gap-2'} data-testid="messages-table">
|
|
{channels && channels.length === 0 && (
|
|
<div className="bg-canvas-50 border border-canvas-200 rounded-xl p-8 text-center mt-4">
|
|
<p className="text-ink-500 text-sm mb-1">
|
|
{t('messages.empty', 'You have no messages, yet.')}
|
|
</p>
|
|
<p className="text-ink-300 text-xs">
|
|
{t(
|
|
'messages.empty_hint',
|
|
'Start a conversation with someone who resonates with you.',
|
|
)}
|
|
</p>
|
|
</div>
|
|
)}
|
|
{channels?.map((channel) => {
|
|
const userIds = memberIdsByChannelId?.[channel.channel_id]?.map((m) => m) || []
|
|
return (
|
|
<MessageChannelRow
|
|
key={channel.channel_id}
|
|
otherUserIds={userIds}
|
|
currentUser={currentUser}
|
|
channel={channel}
|
|
lastSeenTime={lastSeenChatTimeByChannelId[channel.channel_id]}
|
|
lastMessage={lastMessages[channel.channel_id]}
|
|
/>
|
|
)
|
|
})}
|
|
</Col>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export const MessageChannelRow = (props: {
|
|
otherUserIds: string[]
|
|
currentUser: User
|
|
channel: PrivateMessageChannel
|
|
lastSeenTime: Date | undefined
|
|
lastMessage?: ChatMessage
|
|
}) => {
|
|
const {otherUserIds, lastSeenTime, currentUser, channel, lastMessage} = props
|
|
const channelId = channel.channel_id
|
|
const otherUsers = useUsersInStore(otherUserIds, `${channelId}`, 100)
|
|
const unseen = lastSeenTime ? new Date(lastMessage?.createdTime ?? 0) > lastSeenTime : false
|
|
const numOthers = otherUsers?.length ?? 0
|
|
const t = useT()
|
|
|
|
const isBanned = otherUsers?.length == 1 && otherUsers[0].isBannedFromPosting
|
|
return (
|
|
<Row
|
|
className={
|
|
'items-center gap-3 bg-canvas-50 border border-canvas-200 rounded-xl p-3 transition-all hover:border-primary-300 hover:shadow-sm hover:bg-canvas-100'
|
|
}
|
|
data-testid="messages-row"
|
|
>
|
|
{otherUsers && otherUsers.length > 0 ? (
|
|
<MultipleOrSingleAvatars
|
|
size="md"
|
|
spacing={numOthers === 2 ? 0.3 : 0.15}
|
|
startLeft={numOthers === 2 ? 2.2 : 1.2}
|
|
avatars={otherUsers}
|
|
className={numOthers > 1 ? '-ml-2' : ''}
|
|
/>
|
|
) : (
|
|
<Avatar size="md" username="?" noLink />
|
|
)}
|
|
<Link className="w-full group" key={channelId} href={'/messages/' + channelId}>
|
|
<Col className={'gap-1'}>
|
|
<Row className={'items-center justify-between'}>
|
|
<span
|
|
className={
|
|
'font-medium text-ink-900 text-sm group-hover:text-primary-600 transition-colors'
|
|
}
|
|
data-testid="messages-username"
|
|
>
|
|
{otherUsers && otherUsers.length > 0 ? (
|
|
<span>
|
|
{otherUsers
|
|
.map((user) =>
|
|
user.name
|
|
? user.name.split(' ')[0].trim()
|
|
: t('messages.deleted_user', 'Deleted user'),
|
|
)
|
|
.slice(0, 2)
|
|
.join(', ')}
|
|
{otherUsers.length > 2 && (
|
|
<>
|
|
{` & ${otherUsers.length - 2}`}
|
|
{t('messages.more', ' more')}
|
|
</>
|
|
)}
|
|
</span>
|
|
) : (
|
|
otherUserIds.length == 0 && (
|
|
<span className="italic text-ink-500">
|
|
{t('messages.deleted_user', 'Deleted user')}
|
|
</span>
|
|
)
|
|
)}
|
|
{isBanned && <BannedBadge />}
|
|
</span>
|
|
<span className={'text-ink-300 text-xs'} data-testid="messages-timestamp">
|
|
{lastMessage && <RelativeTimestamp time={lastMessage.createdTime} />}
|
|
</span>
|
|
</Row>
|
|
<Row className="items-center justify-between gap-1">
|
|
<span
|
|
className={clsx(
|
|
'line-clamp-1 text-sm',
|
|
unseen ? 'text-ink-900 font-medium' : 'text-ink-500',
|
|
)}
|
|
>
|
|
{lastMessage && (
|
|
<>
|
|
{lastMessage.userId == currentUser.id && (
|
|
<span className="text-ink-300">{t('messages.you_prefix', 'You: ')}</span>
|
|
)}
|
|
{parseJsonContentToText(lastMessage.content)}
|
|
</>
|
|
)}
|
|
</span>
|
|
{unseen && <div className="bg-primary-500 h-2.5 w-2.5 rounded-full shrink-0" />}
|
|
</Row>
|
|
</Col>
|
|
</Link>
|
|
</Row>
|
|
)
|
|
}
|