Files
bsky-social-app/src/screens/Messages/components/ChatStatusInfo.tsx
T
2026-08-13 12:26:23 -07:00

167 lines
5.1 KiB
TypeScript

import {useCallback, useMemo} from 'react'
import {View} from 'react-native'
import {LinearGradient} from 'expo-linear-gradient'
import {moderateProfile} from '@bsky/sdk/moderation'
import {Trans, useLingui} from '@lingui/react/macro'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {sanitizeHandle} from '#/lib/strings/handles'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {type ActiveConvoStates} from '#/state/messages/convo'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme, web} from '#/alf'
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
import {KnownFollowers} from '#/components/KnownFollowers'
import {ProfileBadges} from '#/components/ProfileBadges'
import {usePromptControl} from '#/components/Prompt'
import {Text} from '#/components/Typography'
import type * as bsky from '#/types/bsky'
import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons'
export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
const t = useTheme()
const {t: l} = useLingui()
const moderationOpts = useModerationOpts()
const leaveConvoControl = usePromptControl()
const onAcceptChat = useCallback(() => {
convoState.markConvoAccepted()
}, [convoState])
// either the other person, or the chat owner
// if we ever allow someone other than the owner to invite people, this will need to change
const otherUser = convoState.convo.primaryMember
if (!moderationOpts) {
return null
}
return (
<View style={[a.gap_md, a.p_2xl, t.atoms.bg]}>
<LinearGradient
colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.08)']}
style={[a.absolute, {top: -16, left: 0, right: 0, height: 16}]}
pointerEvents="none"
/>
{otherUser && (
<InviterHeader profile={otherUser} moderationOpts={moderationOpts} />
)}
{otherUser && (
<KnownFollowers
profile={otherUser}
moderationOpts={moderationOpts}
minimal
showIfEmpty
/>
)}
<View style={[a.flex_row, a.gap_md, a.w_full, otherUser && a.pt_sm]}>
{otherUser && (
<RejectMenu
label={l`Block or report`}
icon={true}
convo={convoState.convo}
profile={otherUser}
color="negative_subtle"
size="large"
currentScreen="conversation"
style={[a.flex_1]}
/>
)}
<DeleteChatButton
label={l({
message: 'Leave',
comment: 'Leave a conversation (reject a chat invitation)',
context: 'Button',
})}
icon={true}
convo={convoState.convo.view}
color="secondary"
size="large"
currentScreen="conversation"
style={[a.flex_1]}
onPress={leaveConvoControl.open}
/>
<LeaveConvoPrompt
convoId={convoState.convo.view.id}
control={leaveConvoControl}
currentScreen="conversation"
hasMessages={false}
/>
</View>
<View style={[a.w_full, a.flex_row]}>
<AcceptChatButton
icon={true}
onAcceptConvo={onAcceptChat}
convo={convoState.convo.view}
color="primary"
size="large"
currentScreen="conversation"
style={[a.flex_1]}
/>
</View>
</View>
)
}
function InviterHeader({
profile: profileUnshadowed,
moderationOpts,
}: {
profile: bsky.profile.AnyProfileView
moderationOpts: NonNullable<ReturnType<typeof useModerationOpts>>
}) {
const t = useTheme()
const profile = useProfileShadow(profileUnshadowed)
const moderation = useMemo(
() => moderateProfile(profile, moderationOpts),
[profile, moderationOpts],
)
const displayName = createSanitizedDisplayName(
profile,
true,
moderation.ui('displayName'),
)
return (
<View style={[a.flex_row, a.align_center, a.gap_sm]}>
<PreviewableUserAvatar
profile={profile}
size={42}
moderation={moderation.ui('avatar')}
/>
<View style={[a.flex_1]}>
<Text style={[a.flex_row, a.align_center]}>
<Trans comment="Text identifying the person who added you to a group chat">
<Text
style={[
a.text_md,
a.leading_snug,
a.font_semi_bold,
t.atoms.text,
]}
numberOfLines={1}>
{displayName}
</Text>
<ProfileBadges profile={profile} size="sm" style={[a.pl_xs]} />
<Text
style={[
a.text_md,
a.leading_snug,
a.font_semi_bold,
t.atoms.text,
]}
numberOfLines={1}>
{' '}
added you
</Text>
</Trans>
</Text>
<Text style={[web(a.pt_xs), a.text_sm, t.atoms.text_contrast_high]}>
{sanitizeHandle(profile.handle, '@')}
</Text>
</View>
</View>
)
}