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

Configure Feed

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

at 3814f6b46054e082a4e28f04b257a9af4b3e7fd9 247 lines 6.7 kB view raw
1import {useEffect, useRef, useState} from 'react' 2import {View} from 'react-native' 3import {msg, Trans} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import {retry} from '#/lib/async/retry' 7import {wait} from '#/lib/async/wait' 8import {isNative} from '#/platform/detection' 9import {useAgent} from '#/state/session' 10import {atoms as a, useTheme, web} from '#/alf' 11import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' 12import {Button, ButtonText} from '#/components/Button' 13import * as Dialog from '#/components/Dialog' 14import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 15import {CheckThick_Stroke2_Corner0_Rounded as SuccessIcon} from '#/components/icons/Check' 16import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' 17import {Loader} from '#/components/Loader' 18import {Text} from '#/components/Typography' 19import {refetchAgeAssuranceServerState} from '#/ageAssurance' 20import {logger} from '#/ageAssurance' 21 22export type AgeAssuranceRedirectDialogState = { 23 result: 'success' | 'unknown' 24 actorDid: string 25} 26 27/** 28 * Validate and parse the query parameters returned from the age assurance 29 * redirect. If not valid, returns `undefined` and the dialog will not open. 30 */ 31export function parseAgeAssuranceRedirectDialogState( 32 state: { 33 result?: string 34 actorDid?: string 35 } = {}, 36): AgeAssuranceRedirectDialogState | undefined { 37 let result: AgeAssuranceRedirectDialogState['result'] = 'unknown' 38 const actorDid = state.actorDid 39 40 switch (state.result) { 41 case 'success': 42 result = 'success' 43 break 44 case 'unknown': 45 default: 46 result = 'unknown' 47 break 48 } 49 50 if (result && actorDid) { 51 return { 52 result, 53 actorDid, 54 } 55 } 56} 57 58export function useAgeAssuranceRedirectDialogControl() { 59 return useGlobalDialogsControlContext().ageAssuranceRedirectDialogControl 60} 61 62export function AgeAssuranceRedirectDialog() { 63 const {_} = useLingui() 64 const control = useAgeAssuranceRedirectDialogControl() 65 66 // for testing 67 // Dialog.useAutoOpen(control.control, 3e3) 68 69 return ( 70 <Dialog.Outer control={control.control} onClose={() => control.clear()}> 71 <Dialog.Handle /> 72 73 <Dialog.ScrollableInner 74 label={_(msg`Verifying your age assurance status`)} 75 style={[web({maxWidth: 400})]}> 76 <Inner optimisticState={control.value} /> 77 </Dialog.ScrollableInner> 78 </Dialog.Outer> 79 ) 80} 81 82export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) { 83 const t = useTheme() 84 const {_} = useLingui() 85 const agent = useAgent() 86 const polling = useRef(false) 87 const unmounted = useRef(false) 88 const control = useAgeAssuranceRedirectDialogControl() 89 const [error, setError] = useState(false) 90 const [success, setSuccess] = useState(false) 91 92 useEffect(() => { 93 if (polling.current) return 94 95 polling.current = true 96 97 logger.metric('ageAssurance:redirectDialogOpen', {}) 98 99 wait( 100 3e3, 101 retry( 102 5, 103 () => true, 104 async () => { 105 if (!agent.session) return 106 if (unmounted.current) return 107 108 const data = await refetchAgeAssuranceServerState({agent}) 109 110 if (data?.state.status !== 'assured') { 111 throw new Error( 112 `Polling for age assurance state did not receive assured status`, 113 ) 114 } 115 116 return data 117 }, 118 1e3, 119 ), 120 ) 121 .then(async data => { 122 if (!data) return 123 if (!agent.session) return 124 if (unmounted.current) return 125 126 setSuccess(true) 127 128 logger.metric('ageAssurance:redirectDialogSuccess', {}) 129 }) 130 .catch(() => { 131 if (unmounted.current) return 132 setError(true) 133 logger.metric('ageAssurance:redirectDialogFail', {}) 134 }) 135 136 return () => { 137 unmounted.current = true 138 } 139 }, [agent, control]) 140 141 if (success) { 142 return ( 143 <> 144 <View style={[a.align_start, a.w_full]}> 145 <AgeAssuranceBadge /> 146 147 <View 148 style={[ 149 a.flex_row, 150 a.justify_between, 151 a.align_center, 152 a.gap_sm, 153 a.pt_lg, 154 a.pb_md, 155 ]}> 156 <SuccessIcon size="sm" fill={t.palette.positive_500} /> 157 <Text style={[a.text_xl, a.font_bold]}> 158 <Trans>Success</Trans> 159 </Text> 160 </View> 161 162 <Text style={[a.text_md, a.leading_snug]}> 163 <Trans> 164 We've confirmed your age assurance status. You can now close this 165 dialog. 166 </Trans> 167 </Text> 168 169 {isNative && ( 170 <View style={[a.w_full, a.pt_lg]}> 171 <Button 172 label={_(msg`Close`)} 173 size="large" 174 variant="solid" 175 color="secondary" 176 onPress={() => control.control.close()}> 177 <ButtonText> 178 <Trans>Close</Trans> 179 </ButtonText> 180 </Button> 181 </View> 182 )} 183 </View> 184 185 <Dialog.Close /> 186 </> 187 ) 188 } 189 190 return ( 191 <> 192 <View style={[a.align_start, a.w_full]}> 193 <AgeAssuranceBadge /> 194 195 <View 196 style={[ 197 a.flex_row, 198 a.justify_between, 199 a.align_center, 200 a.gap_sm, 201 a.pt_lg, 202 a.pb_md, 203 ]}> 204 {error && <ErrorIcon size="md" fill={t.palette.negative_500} />} 205 206 <Text style={[a.text_xl, a.font_bold]}> 207 {error ? <Trans>Connection issue</Trans> : <Trans>Verifying</Trans>} 208 </Text> 209 210 {!error && <Loader size="md" />} 211 </View> 212 213 <Text style={[a.text_md, a.leading_snug]}> 214 {error ? ( 215 <Trans> 216 We were unable to receive the verification due to a connection 217 issue. It may arrive later. If it does, your account will update 218 automatically. 219 </Trans> 220 ) : ( 221 <Trans> 222 We're confirming your age assurance status with our servers. This 223 should only take a few seconds. 224 </Trans> 225 )} 226 </Text> 227 228 {error && isNative && ( 229 <View style={[a.w_full, a.pt_lg]}> 230 <Button 231 label={_(msg`Close`)} 232 size="large" 233 variant="solid" 234 color="secondary" 235 onPress={() => control.control.close()}> 236 <ButtonText> 237 <Trans>Close</Trans> 238 </ButtonText> 239 </Button> 240 </View> 241 )} 242 </View> 243 244 {error && <Dialog.Close />} 245 </> 246 ) 247}