this repo has no description
0
fork

Configure Feed

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

at e28f6d2f370b4e882ed6f23d08ca0f8d94dbac5f 280 lines 8.7 kB view raw
1import {View} from 'react-native' 2import {type AppBskyActorDefs} from '@atproto/api' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6 7import {urls} from '#/lib/constants' 8import {getUserDisplayName} from '#/lib/getUserDisplayName' 9import {useModerationOpts} from '#/state/preferences/moderation-opts' 10import {useProfileQuery} from '#/state/queries/profile' 11import {useSession} from '#/state/session' 12import {atoms as a, useBreakpoints, useTheme} from '#/alf' 13import {Admonition} from '#/components/Admonition' 14import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15import * as Dialog from '#/components/Dialog' 16import {useDialogControl} from '#/components/Dialog' 17import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 18import {Link} from '#/components/Link' 19import * as ProfileCard from '#/components/ProfileCard' 20import {Text} from '#/components/Typography' 21import {type FullVerificationState} from '#/components/verification' 22import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt' 23import {useAnalytics} from '#/analytics' 24import type * as bsky from '#/types/bsky' 25 26export {useDialogControl} from '#/components/Dialog' 27 28export function VerificationsDialog({ 29 control, 30 profile, 31 verificationState, 32}: { 33 control: Dialog.DialogControlProps 34 profile: bsky.profile.AnyProfileView 35 verificationState: FullVerificationState 36}) { 37 return ( 38 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 39 <Dialog.Handle /> 40 <Inner 41 control={control} 42 profile={profile} 43 verificationState={verificationState} 44 /> 45 </Dialog.Outer> 46 ) 47} 48 49function Inner({ 50 profile, 51 control, 52 verificationState: state, 53}: { 54 control: Dialog.DialogControlProps 55 profile: bsky.profile.AnyProfileView 56 verificationState: FullVerificationState 57}) { 58 const t = useTheme() 59 const ax = useAnalytics() 60 const {_} = useLingui() 61 const {gtMobile} = useBreakpoints() 62 63 const userName = getUserDisplayName(profile) 64 const label = state.profile.isViewer 65 ? state.profile.isVerified 66 ? _(msg`You are verified`) 67 : _(msg`Your verifications`) 68 : state.profile.isVerified 69 ? _(msg`${userName} is verified`) 70 : _( 71 msg({ 72 message: `${userName}'s verifications`, 73 comment: `Possessive, meaning "the verifications of {userName}"`, 74 }), 75 ) 76 77 return ( 78 <Dialog.ScrollableInner 79 label={label} 80 style={[ 81 gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full, 82 ]}> 83 <View style={[a.gap_sm, a.pb_lg]}> 84 <Text style={[a.text_2xl, a.font_semi_bold, a.pr_4xl, a.leading_tight]}> 85 {label} 86 </Text> 87 <Text style={[a.text_md, a.leading_snug]}> 88 {state.profile.isVerified ? ( 89 <Trans> 90 This account has a checkmark because it's been verified by trusted 91 sources. 92 </Trans> 93 ) : ( 94 <Trans> 95 This account has one or more attempted verifications, but it is 96 not currently verified. 97 </Trans> 98 )} 99 </Text> 100 </View> 101 102 {profile.verification ? ( 103 <View style={[a.pb_xl, a.gap_md]}> 104 <Text style={[a.text_sm, t.atoms.text_contrast_medium]}> 105 <Trans>Verified by:</Trans> 106 </Text> 107 108 <View style={[a.gap_lg]}> 109 {profile.verification.verifications.map(v => ( 110 <VerifierCard 111 key={v.uri} 112 verification={v} 113 subject={profile} 114 outerDialogControl={control} 115 /> 116 ))} 117 </View> 118 119 {profile.verification.verifications.some(v => !v.isValid) && 120 state.profile.isViewer && ( 121 <Admonition type="warning" style={[a.mt_xs]}> 122 <Trans>Some of your verifications are invalid.</Trans> 123 </Admonition> 124 )} 125 </View> 126 ) : null} 127 128 <View 129 style={[ 130 a.w_full, 131 a.gap_sm, 132 a.justify_end, 133 gtMobile 134 ? [a.flex_row, a.flex_row_reverse, a.justify_start] 135 : [a.flex_col], 136 ]}> 137 <Button 138 label={_(msg`Close dialog`)} 139 size="small" 140 variant="solid" 141 color="primary" 142 onPress={() => { 143 control.close() 144 }}> 145 <ButtonText> 146 <Trans>Close</Trans> 147 </ButtonText> 148 </Button> 149 <Link 150 overridePresentation 151 to={urls.website.blog.initialVerificationAnnouncement} 152 label={_( 153 msg({ 154 message: `Learn more about verification on Bluesky`, 155 context: `english-only-resource`, 156 }), 157 )} 158 size="small" 159 variant="solid" 160 color="secondary" 161 style={[a.justify_center]} 162 onPress={() => { 163 ax.metric('verification:learn-more', { 164 location: 'verificationsDialog', 165 }) 166 }}> 167 <ButtonText> 168 <Trans context="english-only-resource">Learn more</Trans> 169 </ButtonText> 170 </Link> 171 </View> 172 173 <Dialog.Close /> 174 </Dialog.ScrollableInner> 175 ) 176} 177 178function VerifierCard({ 179 verification, 180 subject, 181 outerDialogControl, 182}: { 183 verification: AppBskyActorDefs.VerificationView 184 subject: bsky.profile.AnyProfileView 185 outerDialogControl: Dialog.DialogControlProps 186}) { 187 const t = useTheme() 188 const {_, i18n} = useLingui() 189 const {currentAccount} = useSession() 190 const moderationOpts = useModerationOpts() 191 const {data: profile, error} = useProfileQuery({did: verification.issuer}) 192 const verificationRemovePromptControl = useDialogControl() 193 const canAdminister = verification.issuer === currentAccount?.did 194 195 return ( 196 <View 197 style={{ 198 opacity: verification.isValid ? 1 : 0.5, 199 }}> 200 <ProfileCard.Outer> 201 <ProfileCard.Header> 202 {error ? ( 203 <> 204 <ProfileCard.AvatarPlaceholder /> 205 <View style={[a.flex_1]}> 206 <Text 207 style={[a.text_md, a.font_semi_bold, a.leading_snug]} 208 numberOfLines={1}> 209 <Trans>Unknown verifier</Trans> 210 </Text> 211 <Text 212 emoji 213 style={[a.leading_snug, t.atoms.text_contrast_medium]} 214 numberOfLines={1}> 215 {verification.issuer} 216 </Text> 217 </View> 218 </> 219 ) : profile && moderationOpts ? ( 220 <> 221 <ProfileCard.Link 222 profile={profile} 223 style={[a.flex_row, a.align_center, a.gap_sm, a.flex_1]} 224 onPress={() => { 225 outerDialogControl.close() 226 }}> 227 <ProfileCard.Avatar 228 profile={profile} 229 moderationOpts={moderationOpts} 230 disabledPreview 231 /> 232 <View style={[a.flex_1]}> 233 <ProfileCard.Name 234 profile={profile} 235 moderationOpts={moderationOpts} 236 /> 237 <Text 238 emoji 239 style={[a.leading_snug, t.atoms.text_contrast_medium]} 240 numberOfLines={1}> 241 {i18n.date(new Date(verification.createdAt), { 242 dateStyle: 'long', 243 })} 244 </Text> 245 </View> 246 </ProfileCard.Link> 247 {canAdminister && ( 248 <View> 249 <Button 250 label={_(msg`Remove verification`)} 251 size="small" 252 variant="outline" 253 color="negative" 254 shape="round" 255 onPress={() => { 256 verificationRemovePromptControl.open() 257 }}> 258 <ButtonIcon icon={TrashIcon} /> 259 </Button> 260 </View> 261 )} 262 </> 263 ) : ( 264 <> 265 <ProfileCard.AvatarPlaceholder /> 266 <ProfileCard.NameAndHandlePlaceholder /> 267 </> 268 )} 269 </ProfileCard.Header> 270 </ProfileCard.Outer> 271 272 <VerificationRemovePrompt 273 control={verificationRemovePromptControl} 274 profile={subject} 275 verifications={[verification]} 276 onConfirm={() => outerDialogControl.close()} 277 /> 278 </View> 279 ) 280}