this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at e28f6d2f370b4e882ed6f23d08ca0f8d94dbac5f 215 lines 6.5 kB view raw
1import {useMemo} from 'react' 2import {View} from 'react-native' 3import { 4 type AppBskyActorDefs, 5 type ModerationCause, 6 type ModerationDecision, 7} from '@atproto/api' 8import {msg} from '@lingui/core/macro' 9import {useLingui} from '@lingui/react' 10 11import {makeProfileLink} from '#/lib/routes/links' 12import {sanitizeDisplayName} from '#/lib/strings/display-names' 13import {type Shadow} from '#/state/cache/profile-shadow' 14import {isConvoActive, useConvo} from '#/state/messages/convo' 15import {type ConvoItem} from '#/state/messages/convo/types' 16import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' 17import {atoms as a, useTheme, web} from '#/alf' 18import {ConvoMenu} from '#/components/dms/ConvoMenu' 19import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2' 20import * as Layout from '#/components/Layout' 21import {Link} from '#/components/Link' 22import {PostAlerts} from '#/components/moderation/PostAlerts' 23import {ProfileBadges} from '#/components/ProfileBadges' 24import {Text} from '#/components/Typography' 25import {IS_WEB} from '#/env' 26 27const PFP_SIZE = IS_WEB ? 40 : Layout.HEADER_SLOT_SIZE 28 29export function MessagesListHeader({ 30 profile, 31 moderation, 32}: { 33 profile?: Shadow<AppBskyActorDefs.ProfileViewDetailed> 34 moderation?: ModerationDecision 35}) { 36 const t = useTheme() 37 38 const blockInfo = useMemo(() => { 39 if (!moderation) return 40 const modui = moderation.ui('profileView') 41 const blocks = modui.alerts.filter(alert => alert.type === 'blocking') 42 const listBlocks = blocks.filter(alert => alert.source.type === 'list') 43 const userBlock = blocks.find(alert => alert.source.type === 'user') 44 return { 45 listBlocks, 46 userBlock, 47 } 48 }, [moderation]) 49 50 return ( 51 <Layout.Header.Outer> 52 <View style={[a.w_full, a.flex_row, a.gap_xs, a.align_start]}> 53 <View style={[{minHeight: PFP_SIZE}, a.justify_center]}> 54 <Layout.Header.BackButton /> 55 </View> 56 {profile && moderation && blockInfo ? ( 57 <HeaderReady 58 profile={profile} 59 moderation={moderation} 60 blockInfo={blockInfo} 61 /> 62 ) : ( 63 <> 64 <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}> 65 <View 66 style={[ 67 {width: PFP_SIZE, height: PFP_SIZE}, 68 a.rounded_full, 69 t.atoms.bg_contrast_25, 70 ]} 71 /> 72 <View style={a.gap_xs}> 73 <View 74 style={[ 75 {width: 120, height: 16}, 76 a.rounded_xs, 77 t.atoms.bg_contrast_25, 78 a.mt_xs, 79 ]} 80 /> 81 <View 82 style={[ 83 {width: 175, height: 12}, 84 a.rounded_xs, 85 t.atoms.bg_contrast_25, 86 ]} 87 /> 88 </View> 89 </View> 90 91 <Layout.Header.Slot /> 92 </> 93 )} 94 </View> 95 </Layout.Header.Outer> 96 ) 97} 98 99function HeaderReady({ 100 profile, 101 moderation, 102 blockInfo, 103}: { 104 profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> 105 moderation: ModerationDecision 106 blockInfo: { 107 listBlocks: ModerationCause[] 108 userBlock?: ModerationCause 109 } 110}) { 111 const {_} = useLingui() 112 const t = useTheme() 113 const convoState = useConvo() 114 115 const isDeletedAccount = profile?.handle === 'missing.invalid' 116 const displayName = isDeletedAccount 117 ? _(msg`Deleted Account`) 118 : sanitizeDisplayName( 119 profile.displayName || profile.handle, 120 moderation.ui('displayName'), 121 ) 122 123 // @ts-ignore findLast is polyfilled - esb 124 const latestMessageFromOther = convoState.items.findLast( 125 (item: ConvoItem) => 126 item.type === 'message' && item.message.sender.did === profile.did, 127 ) 128 129 const latestReportableMessage = 130 latestMessageFromOther?.type === 'message' 131 ? latestMessageFromOther.message 132 : undefined 133 134 return ( 135 <View style={[a.flex_1]}> 136 <View style={[a.w_full, a.flex_row, a.align_center, a.justify_between]}> 137 <Link 138 label={_(msg`View ${displayName}'s profile`)} 139 style={[a.flex_row, a.align_start, a.gap_md, a.flex_1, a.pr_md]} 140 to={makeProfileLink(profile)}> 141 <PreviewableUserAvatar 142 size={PFP_SIZE} 143 profile={profile} 144 moderation={moderation.ui('avatar')} 145 disableHoverCard={moderation.blocked} 146 /> 147 <View style={[a.flex_1]}> 148 <View style={[a.flex_row, a.align_center]}> 149 <Text 150 emoji 151 style={[ 152 a.text_md, 153 a.font_semi_bold, 154 a.self_start, 155 web(a.leading_normal), 156 ]} 157 numberOfLines={1}> 158 {displayName} 159 </Text> 160 <ProfileBadges profile={profile} size="md" style={[a.pl_xs]} /> 161 </View> 162 {!isDeletedAccount && ( 163 <Text 164 style={[ 165 t.atoms.text_contrast_medium, 166 a.text_xs, 167 web([a.leading_normal, {marginTop: -2}]), 168 ]} 169 numberOfLines={1}> 170 @{profile.handle} 171 {convoState.convo?.muted && ( 172 <> 173 {' '} 174 &middot;{' '} 175 <BellStroke 176 size="xs" 177 style={t.atoms.text_contrast_medium} 178 /> 179 </> 180 )} 181 </Text> 182 )} 183 </View> 184 </Link> 185 186 <View style={[{minHeight: PFP_SIZE}, a.justify_center]}> 187 <Layout.Header.Slot> 188 {isConvoActive(convoState) && ( 189 <ConvoMenu 190 convo={convoState.convo} 191 profile={profile} 192 currentScreen="conversation" 193 blockInfo={blockInfo} 194 latestReportableMessage={latestReportableMessage} 195 /> 196 )} 197 </Layout.Header.Slot> 198 </View> 199 </View> 200 201 <View 202 style={[ 203 { 204 paddingLeft: PFP_SIZE + a.gap_md.gap, 205 }, 206 ]}> 207 <PostAlerts 208 modui={moderation.ui('contentList')} 209 size="lg" 210 style={[a.pt_xs]} 211 /> 212 </View> 213 </View> 214 ) 215}