Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

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

at main 211 lines 7.7 kB view raw
1import {View} from 'react-native' 2import {msg, Trans} from '@lingui/macro' 3import {useLingui} from '@lingui/react' 4 5import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 6import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' 7import {Admonition} from '#/components/Admonition' 8import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog' 9import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' 10import {AgeAssuranceConfigUnavailableError} from '#/components/ageAssurance/AgeAssuranceErrors' 11import { 12 AgeAssuranceInitDialog, 13 useDialogControl, 14} from '#/components/ageAssurance/AgeAssuranceInitDialog' 15import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' 16import {Button, ButtonText} from '#/components/Button' 17import * as Dialog from '#/components/Dialog' 18import {DeviceLocationRequestDialog} from '#/components/dialogs/DeviceLocationRequestDialog' 19import {Divider} from '#/components/Divider' 20import {createStaticClick, InlineLinkText} from '#/components/Link' 21import * as Toast from '#/components/Toast' 22import {Text} from '#/components/Typography' 23import {useAgeAssurance} from '#/ageAssurance' 24import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess' 25import {useAnalytics} from '#/analytics' 26import {IS_NATIVE} from '#/env' 27import {useDeviceGeolocationApi} from '#/geolocation' 28 29export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) { 30 const aa = useAgeAssurance() 31 if (aa.state.access === aa.Access.Full) return null 32 if (aa.state.error === 'config') { 33 return ( 34 <View style={style}> 35 <AgeAssuranceConfigUnavailableError /> 36 </View> 37 ) 38 } 39 return <Inner style={style} /> 40} 41 42function Inner({style}: ViewStyleProp & {}) { 43 const t = useTheme() 44 const {_, i18n} = useLingui() 45 const ax = useAnalytics() 46 const control = useDialogControl() 47 const appealControl = Dialog.useDialogControl() 48 const locationControl = Dialog.useDialogControl() 49 const getTimeAgo = useGetTimeAgo() 50 const {gtPhone} = useBreakpoints() 51 const {setDeviceGeolocation} = useDeviceGeolocationApi() 52 const computeAgeAssuranceRegionAccess = useComputeAgeAssuranceRegionAccess() 53 54 const copy = useAgeAssuranceCopy() 55 const aa = useAgeAssurance() 56 const {status, lastInitiatedAt} = aa.state 57 const isBlocked = status === aa.Status.Blocked 58 const hasInitiated = !!lastInitiatedAt 59 const timeAgo = lastInitiatedAt 60 ? getTimeAgo(lastInitiatedAt, new Date()) 61 : null 62 const diff = lastInitiatedAt 63 ? dateDiff(lastInitiatedAt, new Date(), 'down') 64 : null 65 66 return ( 67 <> 68 <AgeAssuranceInitDialog control={control} /> 69 <AgeAssuranceAppealDialog control={appealControl} /> 70 71 <View style={style}> 72 <View 73 style={[a.p_lg, a.rounded_md, a.border, t.atoms.border_contrast_low]}> 74 <View 75 style={[ 76 a.flex_row, 77 a.justify_between, 78 a.align_center, 79 a.gap_lg, 80 a.pb_md, 81 a.z_10, 82 ]}> 83 <View style={[a.align_start]}> 84 <AgeAssuranceBadge /> 85 </View> 86 </View> 87 88 <View style={[a.pb_md, a.gap_xs]}> 89 <Text style={[a.text_sm, a.leading_snug]}>{copy.notice}</Text> 90 91 {IS_NATIVE && ( 92 <> 93 <Text style={[a.text_sm, a.leading_snug]}> 94 <Trans> 95 Is your location not accurate?{' '} 96 <InlineLinkText 97 label={_(msg`Confirm your location`)} 98 {...createStaticClick(() => { 99 locationControl.open() 100 })}> 101 Tap here to confirm your location. 102 </InlineLinkText>{' '} 103 </Trans> 104 </Text> 105 106 <DeviceLocationRequestDialog 107 control={locationControl} 108 onLocationAcquired={props => { 109 const access = computeAgeAssuranceRegionAccess( 110 props.geolocation, 111 ) 112 if (access !== aa.Access.Full) { 113 props.disableDialogAction() 114 props.setDialogError( 115 _( 116 msg`We're sorry, but based on your device's location, you are currently located in a region that requires age assurance.`, 117 ), 118 ) 119 } else { 120 props.closeDialog(() => { 121 // set this after close! 122 setDeviceGeolocation(props.geolocation) 123 Toast.show(_(msg`Thanks! You're all set.`), { 124 type: 'success', 125 }) 126 }) 127 } 128 }} 129 /> 130 </> 131 )} 132 </View> 133 134 {isBlocked ? ( 135 <Admonition type="warning"> 136 <Trans> 137 You are currently unable to access Bluesky's Age Assurance flow. 138 Please{' '} 139 <InlineLinkText 140 label={_(msg`Contact our moderation team`)} 141 {...createStaticClick(() => { 142 appealControl.open() 143 ax.metric('ageAssurance:appealDialogOpen', {}) 144 })}> 145 contact our moderation team 146 </InlineLinkText>{' '} 147 if you believe this is an error. 148 </Trans> 149 </Admonition> 150 ) : ( 151 <> 152 <Divider /> 153 <View 154 style={[ 155 a.pt_md, 156 gtPhone 157 ? [ 158 a.flex_row_reverse, 159 a.gap_xl, 160 a.justify_between, 161 a.align_center, 162 ] 163 : [a.gap_md], 164 ]}> 165 <Button 166 label={_(msg`Verify now`)} 167 size="small" 168 variant="solid" 169 color={hasInitiated ? 'secondary' : 'primary'} 170 onPress={() => { 171 control.open() 172 ax.metric('ageAssurance:initDialogOpen', { 173 hasInitiatedPreviously: hasInitiated, 174 }) 175 }}> 176 <ButtonText> 177 {hasInitiated ? ( 178 <Trans>Verify again</Trans> 179 ) : ( 180 <Trans>Verify now</Trans> 181 )} 182 </ButtonText> 183 </Button> 184 185 {lastInitiatedAt && timeAgo && diff ? ( 186 <Text 187 style={[a.text_sm, a.italic, t.atoms.text_contrast_medium]} 188 title={i18n.date(lastInitiatedAt, { 189 dateStyle: 'medium', 190 timeStyle: 'medium', 191 })}> 192 {diff.value === 0 ? ( 193 <Trans>Last initiated just now</Trans> 194 ) : ( 195 <Trans>Last initiated {timeAgo} ago</Trans> 196 )} 197 </Text> 198 ) : ( 199 <Text 200 style={[a.text_sm, a.italic, t.atoms.text_contrast_medium]}> 201 <Trans>Age assurance only takes a few minutes</Trans> 202 </Text> 203 )} 204 </View> 205 </> 206 )} 207 </View> 208 </View> 209 </> 210 ) 211}