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