mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-03-25 10:02:27 -04:00
* Fixed Type errors * Added Database checks to the onboarding flow * Updated Onboarding flow Changed type ChildrenExpectation so that it can be used for database verification * 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 * Apply suggestions from code review --------- Co-authored-by: Martin Braquet <martin.braquet@gmail.com>
270 lines
9.7 KiB
TypeScript
270 lines
9.7 KiB
TypeScript
import {
|
|
EllipsisHorizontalIcon,
|
|
EyeIcon,
|
|
LockClosedIcon,
|
|
PencilIcon,
|
|
} from '@heroicons/react/24/outline'
|
|
import clsx from 'clsx'
|
|
import {debug} from 'common/logger'
|
|
import {Profile} from 'common/profiles/profile'
|
|
import {User, UserActivity} from 'common/user'
|
|
import {capitalize} from 'lodash'
|
|
import Link from 'next/link'
|
|
import Router from 'next/router'
|
|
import React, {useState} from 'react'
|
|
import toast from 'react-hot-toast'
|
|
import {Button} from 'web/components/buttons/button'
|
|
import {MoreOptionsUserButton} from 'web/components/buttons/more-options-user-button'
|
|
import DropdownMenu from 'web/components/comments/dropdown-menu'
|
|
import {Col} from 'web/components/layout/col'
|
|
import {Row} from 'web/components/layout/row'
|
|
import {SendMessageButton} from 'web/components/messaging/send-message-button'
|
|
import HideProfileButton from 'web/components/widgets/hide-profile-button'
|
|
import {linkClass} from 'web/components/widgets/site-link'
|
|
import {StarButton} from 'web/components/widgets/star-button'
|
|
import {Tooltip} from 'web/components/widgets/tooltip'
|
|
import {useUser} from 'web/hooks/use-user'
|
|
import {updateProfile} from 'web/lib/api'
|
|
import {useT} from 'web/lib/locale'
|
|
import {track} from 'web/lib/service/analytics'
|
|
import {disableProfile} from 'web/lib/util/disable'
|
|
|
|
import {ShareProfileButton} from '../widgets/share-profile-button'
|
|
import ProfilePrimaryInfo from './profile-primary-info'
|
|
import {VisibilityConfirmationModal} from './visibility-confirmation-modal'
|
|
|
|
export default function ProfileHeader(props: {
|
|
user: User
|
|
userActivity?: UserActivity
|
|
profile: Profile
|
|
simpleView?: boolean
|
|
starredUserIds: string[]
|
|
refreshStars: () => Promise<void>
|
|
isHiddenFromMe: boolean | undefined
|
|
showMessageButton: boolean
|
|
refreshProfile: () => void
|
|
}) {
|
|
const {
|
|
user,
|
|
profile,
|
|
userActivity,
|
|
simpleView,
|
|
starredUserIds,
|
|
refreshStars,
|
|
showMessageButton,
|
|
refreshProfile,
|
|
isHiddenFromMe,
|
|
} = props
|
|
const currentUser = useUser()
|
|
const isCurrentUser = currentUser?.id === user.id
|
|
const [showVisibilityModal, setShowVisibilityModal] = useState(false)
|
|
const disabled = profile.disabled
|
|
const t = useT()
|
|
|
|
debug('ProfileProfileHeader', {
|
|
user,
|
|
profile,
|
|
userActivity,
|
|
currentUser,
|
|
})
|
|
|
|
let tooltipText = undefined
|
|
if (!profile.allow_direct_messaging) {
|
|
tooltipText = t(
|
|
'profile.header.tooltip.direct_messaging_off',
|
|
'{name} turned off direct messaging',
|
|
{
|
|
name: user.name,
|
|
},
|
|
)
|
|
}
|
|
if (!profile.allow_direct_messaging && profile.allow_interest_indicating) {
|
|
tooltipText =
|
|
tooltipText +
|
|
t(
|
|
'profile.header.tooltip.can_express_interest',
|
|
', but you can still express interest at the end of the profile',
|
|
)
|
|
}
|
|
return (
|
|
<Col className="w-full">
|
|
{currentUser && !isCurrentUser && isHiddenFromMe && (
|
|
<div className="guidance">
|
|
{t(
|
|
'profile_grid.hidden_notice',
|
|
"You hid this person, so they don't appear in your search results.",
|
|
)}
|
|
</div>
|
|
)}
|
|
{currentUser && isCurrentUser && disabled && (
|
|
<div className="text-red-500">
|
|
{t(
|
|
'profile.header.disabled_notice',
|
|
'You disabled your profile, so no one else can access it.',
|
|
)}
|
|
</div>
|
|
)}
|
|
<Row className={clsx('flex-wrap justify-between gap-2 py-1')}>
|
|
<Row className="items-center gap-1">
|
|
<Col className="gap-1">
|
|
<Row className="items-center gap-1 text-xl" data-testid="profile-display-name-age">
|
|
{/*{!isCurrentUser && <OnlineIcon last_online_time={userActivity?.last_online_time}/>}*/}
|
|
<span>
|
|
{simpleView ? (
|
|
<Link className={linkClass} href={`/${user.username}`}>
|
|
<span className="font-semibold">{user.name}</span>
|
|
</Link>
|
|
) : (
|
|
<span className="font-semibold">{user.name}</span>
|
|
)}
|
|
{profile.age && `, ${t('profile.header.age', '{age}', {age: profile.age})}`}
|
|
</span>
|
|
</Row>
|
|
<ProfilePrimaryInfo profile={profile} />
|
|
</Col>
|
|
</Row>
|
|
{currentUser && isCurrentUser ? (
|
|
<Row className={'items-center gap-4'}>
|
|
<ShareProfileButton className="sm:flex" username={user.username} />
|
|
<Tooltip text={t('more_options_user.edit_profile', 'Edit profile')} noTap>
|
|
<Button
|
|
data-testid="profile-edit"
|
|
color={'gray-outline'}
|
|
onClick={() => {
|
|
track('editprofile', {userId: user.id})
|
|
Router.push('profile')
|
|
}}
|
|
size="sm"
|
|
>
|
|
<PencilIcon className=" h-4 w-4" />
|
|
</Button>
|
|
</Tooltip>
|
|
|
|
<Tooltip
|
|
text={t('more_options_user.profile_options', 'Profile options')}
|
|
noTap
|
|
testId="profile-options"
|
|
>
|
|
<DropdownMenu
|
|
menuWidth={'w-52'}
|
|
icon={<EllipsisHorizontalIcon className="h-5 w-5" aria-hidden="true" />}
|
|
items={[
|
|
{
|
|
name:
|
|
profile.visibility === 'member'
|
|
? t('profile.header.menu.list_public', 'List Profile Publicly')
|
|
: t('profile.header.menu.limit_members', 'Limit to Members Only'),
|
|
icon:
|
|
profile.visibility === 'member' ? (
|
|
<EyeIcon className="h-4 w-4" />
|
|
) : (
|
|
<LockClosedIcon className="h-4 w-4" />
|
|
),
|
|
onClick: () => setShowVisibilityModal(true),
|
|
},
|
|
{
|
|
name: disabled
|
|
? t('profile.header.menu.enable_profile', 'Enable profile')
|
|
: t('profile.header.menu.disable_profile', 'Disable profile'),
|
|
icon: null,
|
|
onClick: async () => {
|
|
const confirmed = true // confirm(
|
|
// 'Are you sure you want to disable your profile? This will hide your profile from searches and listings..'
|
|
// )
|
|
if (confirmed) {
|
|
toast
|
|
.promise(disableProfile(!disabled), {
|
|
loading: disabled
|
|
? t('profile.header.toast.enabling', 'Enabling profile...')
|
|
: t('profile.header.toast.disabling', 'Disabling profile...'),
|
|
success: () => {
|
|
return disabled
|
|
? t('profile.header.toast.enabled', 'Profile enabled')
|
|
: t('profile.header.toast.disabled', 'Profile disabled')
|
|
},
|
|
error: () => {
|
|
return disabled
|
|
? t(
|
|
'profile.header.toast.failed_enable',
|
|
'Failed to enable profile',
|
|
)
|
|
: t(
|
|
'profile.header.toast.failed_disable',
|
|
'Failed to disable profile',
|
|
)
|
|
},
|
|
})
|
|
.then(() => {
|
|
refreshProfile()
|
|
})
|
|
.catch(() => {
|
|
// return false
|
|
})
|
|
}
|
|
},
|
|
},
|
|
]}
|
|
/>
|
|
</Tooltip>
|
|
</Row>
|
|
) : (
|
|
<Row className="items-center gap-1 sm:gap-2">
|
|
{currentUser && !isCurrentUser && <HideProfileButton hiddenUserId={user.id} />}
|
|
<ShareProfileButton className="sm:flex" username={user.username} />
|
|
{currentUser && (
|
|
<StarButton
|
|
targetProfile={profile}
|
|
isStarred={starredUserIds.includes(user.id)}
|
|
refresh={refreshStars}
|
|
/>
|
|
)}
|
|
{currentUser && showMessageButton && (
|
|
<SendMessageButton
|
|
toUser={user}
|
|
currentUser={currentUser}
|
|
tooltipText={tooltipText}
|
|
disabled={!profile.allow_direct_messaging}
|
|
/>
|
|
)}
|
|
<MoreOptionsUserButton user={user} />
|
|
</Row>
|
|
)}
|
|
</Row>
|
|
|
|
{/*<Row className="justify-end sm:hidden">*/}
|
|
{/* <ShareProfileButton username={user.username} />*/}
|
|
{/*</Row>*/}
|
|
|
|
<VisibilityConfirmationModal
|
|
open={showVisibilityModal}
|
|
setOpen={setShowVisibilityModal}
|
|
currentVisibility={profile.visibility}
|
|
onConfirm={async () => {
|
|
const newVisibility = profile.visibility === 'member' ? 'public' : 'member'
|
|
await updateProfile({visibility: newVisibility})
|
|
refreshProfile()
|
|
}}
|
|
/>
|
|
{profile.headline && (
|
|
<div className="italic max-w-3xl px-4 py-3" data-testid="profile-headline">
|
|
{profile.headline}
|
|
</div>
|
|
)}
|
|
<Row className={'px-4 gap-2 flex-wrap py-2'} data-testid="profile-keywords">
|
|
{profile.keywords?.map(capitalize)?.map((tag, i) => (
|
|
<span
|
|
key={i}
|
|
className={'bg-canvas-100'}
|
|
style={{
|
|
padding: '6px 16px',
|
|
borderRadius: '20px',
|
|
}}
|
|
>
|
|
{tag.trim()}
|
|
</span>
|
|
))}
|
|
</Row>
|
|
</Col>
|
|
)
|
|
}
|