mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at remove-hackfix 171 lines 5.1 kB view raw
1import {useState} from 'react' 2import {View} from 'react-native' 3import {msg, Trans} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import {wait} from '#/lib/async/wait' 7import {isNetworkError, useCleanError} from '#/lib/hooks/useCleanError' 8import {logger} from '#/logger' 9import {isWeb} from '#/platform/detection' 10import { 11 computeGeolocationStatus, 12 type GeolocationStatus, 13 useGeolocationConfig, 14} from '#/state/geolocation' 15import {useRequestDeviceLocation} from '#/state/geolocation/useRequestDeviceLocation' 16import {atoms as a, useTheme, web} from '#/alf' 17import {Admonition} from '#/components/Admonition' 18import {Button, ButtonIcon, ButtonText} from '#/components/Button' 19import * as Dialog from '#/components/Dialog' 20import {PinLocation_Stroke2_Corner0_Rounded as LocationIcon} from '#/components/icons/PinLocation' 21import {Loader} from '#/components/Loader' 22import {Text} from '#/components/Typography' 23 24export type Props = { 25 onLocationAcquired?: (props: { 26 geolocationStatus: GeolocationStatus 27 setDialogError: (error: string) => void 28 disableDialogAction: () => void 29 closeDialog: (callback?: () => void) => void 30 }) => void 31} 32 33export function DeviceLocationRequestDialog({ 34 control, 35 onLocationAcquired, 36}: Props & { 37 control: Dialog.DialogOuterProps['control'] 38}) { 39 const {_} = useLingui() 40 return ( 41 <Dialog.Outer control={control}> 42 <Dialog.Handle /> 43 44 <Dialog.ScrollableInner 45 label={_(msg`Confirm your location`)} 46 style={[web({maxWidth: 380})]}> 47 <DeviceLocationRequestDialogInner 48 onLocationAcquired={onLocationAcquired} 49 /> 50 <Dialog.Close /> 51 </Dialog.ScrollableInner> 52 </Dialog.Outer> 53 ) 54} 55 56function DeviceLocationRequestDialogInner({onLocationAcquired}: Props) { 57 const t = useTheme() 58 const {_} = useLingui() 59 const {close} = Dialog.useDialogContext() 60 const requestDeviceLocation = useRequestDeviceLocation() 61 const {config} = useGeolocationConfig() 62 const cleanError = useCleanError() 63 64 const [isRequesting, setIsRequesting] = useState(false) 65 const [error, setError] = useState<string>('') 66 const [dialogDisabled, setDialogDisabled] = useState(false) 67 68 const onPressConfirm = async () => { 69 setError('') 70 setIsRequesting(true) 71 72 try { 73 const req = await wait(1e3, requestDeviceLocation()) 74 75 if (req.granted) { 76 const location = req.location 77 78 if (location && location.countryCode) { 79 const geolocationStatus = computeGeolocationStatus(location, config) 80 onLocationAcquired?.({ 81 geolocationStatus, 82 setDialogError: setError, 83 disableDialogAction: () => setDialogDisabled(true), 84 closeDialog: close, 85 }) 86 } else { 87 setError(_(msg`Failed to resolve location. Please try again.`)) 88 } 89 } else { 90 setError( 91 _( 92 msg`Unable to access location. You'll need to visit your system settings to enable location services for Bluesky.`, 93 ), 94 ) 95 } 96 } catch (e: any) { 97 const {clean, raw} = cleanError(e) 98 setError(clean || raw || e.message) 99 if (!isNetworkError(e)) { 100 logger.error(`blockedGeoOverlay: unexpected error`, { 101 safeMessage: e.message, 102 }) 103 } 104 } finally { 105 setIsRequesting(false) 106 } 107 } 108 109 return ( 110 <View style={[a.gap_md]}> 111 <Text style={[a.text_xl, a.font_bold]}> 112 <Trans>Confirm your location</Trans> 113 </Text> 114 <View style={[a.gap_sm, a.pb_xs]}> 115 <Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}> 116 <Trans> 117 Tap below to allow Bluesky to access your GPS location. We will then 118 use that data to more accurately determine the content and features 119 available in your region. 120 </Trans> 121 </Text> 122 123 <Text 124 style={[ 125 a.text_md, 126 a.leading_snug, 127 t.atoms.text_contrast_medium, 128 a.pb_xs, 129 ]}> 130 <Trans> 131 Your location data is not tracked and does not leave your device. 132 </Trans> 133 </Text> 134 </View> 135 136 {error && ( 137 <View style={[a.pb_xs]}> 138 <Admonition type="error">{error}</Admonition> 139 </View> 140 )} 141 142 <View style={[a.gap_sm]}> 143 {!dialogDisabled && ( 144 <Button 145 disabled={isRequesting} 146 label={_(msg`Allow location access`)} 147 onPress={onPressConfirm} 148 size={isWeb ? 'small' : 'large'} 149 color="primary"> 150 <ButtonIcon icon={isRequesting ? Loader : LocationIcon} /> 151 <ButtonText> 152 <Trans>Allow location access</Trans> 153 </ButtonText> 154 </Button> 155 )} 156 157 {!isWeb && ( 158 <Button 159 label={_(msg`Cancel`)} 160 onPress={() => close()} 161 size={isWeb ? 'small' : 'large'} 162 color="secondary"> 163 <ButtonText> 164 <Trans>Cancel</Trans> 165 </ButtonText> 166 </Button> 167 )} 168 </View> 169 </View> 170 ) 171}