mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {View} from 'react-native'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {cleanError} from '#/lib/strings/errors'
7import {logger} from '#/logger'
8import {useModalControls} from '#/state/modals'
9import {useAgent, useSession} from '#/state/session'
10import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
11import {atoms as a, useBreakpoints} from '#/alf'
12import {Button, ButtonText} from '#/components/Button'
13import * as Dialog from '#/components/Dialog'
14import * as TextField from '#/components/forms/TextField'
15import {InlineLinkText} from '#/components/Link'
16import {Loader} from '#/components/Loader'
17import {Text} from '#/components/Typography'
18
19export function VerifyEmailDialog({
20 control,
21 onCloseWithoutVerifying,
22 onCloseAfterVerifying,
23 reasonText,
24}: {
25 control: Dialog.DialogControlProps
26 onCloseWithoutVerifying?: () => void
27 onCloseAfterVerifying?: () => void
28 reasonText?: string
29}) {
30 const agent = useAgent()
31
32 const [didVerify, setDidVerify] = React.useState(false)
33
34 return (
35 <Dialog.Outer
36 control={control}
37 onClose={async () => {
38 if (!didVerify) {
39 onCloseWithoutVerifying?.()
40 return
41 }
42
43 try {
44 await agent.resumeSession(agent.session!)
45 onCloseAfterVerifying?.()
46 } catch (e: unknown) {
47 logger.error(String(e))
48 return
49 }
50 }}>
51 <Dialog.Handle />
52 <Inner
53 control={control}
54 setDidVerify={setDidVerify}
55 reasonText={reasonText}
56 />
57 </Dialog.Outer>
58 )
59}
60
61export function Inner({
62 control,
63 setDidVerify,
64 reasonText,
65}: {
66 control: Dialog.DialogControlProps
67 setDidVerify: (value: boolean) => void
68 reasonText?: string
69}) {
70 const {_} = useLingui()
71 const {currentAccount} = useSession()
72 const agent = useAgent()
73 const {openModal} = useModalControls()
74 const {gtMobile} = useBreakpoints()
75
76 const [currentStep, setCurrentStep] = React.useState<
77 'StepOne' | 'StepTwo' | 'StepThree'
78 >('StepOne')
79 const [confirmationCode, setConfirmationCode] = React.useState('')
80 const [isProcessing, setIsProcessing] = React.useState(false)
81 const [error, setError] = React.useState('')
82
83 const uiStrings = {
84 StepOne: {
85 title: _(msg`Verify Your Email`),
86 message: '',
87 },
88 StepTwo: {
89 title: _(msg`Enter Code`),
90 message: _(
91 msg`An email has been sent! Please enter the confirmation code included in the email below.`,
92 ),
93 },
94 StepThree: {
95 title: _(msg`Success!`),
96 message: _(msg`Thank you! Your email has been successfully verified.`),
97 },
98 }
99
100 const onSendEmail = async () => {
101 setError('')
102 setIsProcessing(true)
103 try {
104 await agent.com.atproto.server.requestEmailConfirmation()
105 setCurrentStep('StepTwo')
106 } catch (e: unknown) {
107 setError(cleanError(e))
108 } finally {
109 setIsProcessing(false)
110 }
111 }
112
113 const onVerifyEmail = async () => {
114 setError('')
115 setIsProcessing(true)
116 try {
117 await agent.com.atproto.server.confirmEmail({
118 email: (currentAccount?.email || '').trim(),
119 token: confirmationCode.trim(),
120 })
121 } catch (e: unknown) {
122 setError(cleanError(String(e)))
123 setIsProcessing(false)
124 return
125 }
126
127 setIsProcessing(false)
128 setDidVerify(true)
129 setCurrentStep('StepThree')
130 }
131
132 return (
133 <Dialog.ScrollableInner
134 label={_(msg`Verify email dialog`)}
135 style={[
136 gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
137 ]}>
138 <Dialog.Close />
139 <View style={[a.gap_xl]}>
140 <View style={[a.gap_sm]}>
141 <Text style={[a.font_heavy, a.text_2xl]}>
142 {uiStrings[currentStep].title}
143 </Text>
144 {error ? (
145 <View style={[a.rounded_sm, a.overflow_hidden]}>
146 <ErrorMessage message={error} />
147 </View>
148 ) : null}
149 {currentStep === 'StepOne' ? (
150 <View>
151 {reasonText ? (
152 <View style={[a.gap_sm]}>
153 <Text style={[a.text_md, a.leading_snug]}>{reasonText}</Text>
154 <Text style={[a.text_md, a.leading_snug]}>
155 Don't have access to{' '}
156 <Text style={[a.text_md, a.leading_snug, a.font_bold]}>
157 {currentAccount?.email}
158 </Text>
159 ?{' '}
160 <InlineLinkText
161 to="#"
162 label={_(msg`Change email address`)}
163 style={[a.text_md, a.leading_snug]}
164 onPress={e => {
165 e.preventDefault()
166 control.close(() => {
167 openModal({name: 'change-email'})
168 })
169 return false
170 }}>
171 <Trans>Change your email address</Trans>
172 </InlineLinkText>
173 .
174 </Text>
175 </View>
176 ) : (
177 <Text style={[a.text_md, a.leading_snug]}>
178 <Trans>
179 You'll receive an email at{' '}
180 <Text style={[a.text_md, a.leading_snug, a.font_bold]}>
181 {currentAccount?.email}
182 </Text>{' '}
183 to verify it's you.
184 </Trans>{' '}
185 <InlineLinkText
186 to="#"
187 label={_(msg`Change email address`)}
188 style={[a.text_md, a.leading_snug]}
189 onPress={e => {
190 e.preventDefault()
191 control.close(() => {
192 openModal({name: 'change-email'})
193 })
194 return false
195 }}>
196 <Trans>Need to change it?</Trans>
197 </InlineLinkText>
198 </Text>
199 )}
200 </View>
201 ) : (
202 <Text style={[a.text_md, a.leading_snug]}>
203 {uiStrings[currentStep].message}
204 </Text>
205 )}
206 </View>
207 {currentStep === 'StepTwo' ? (
208 <View>
209 <TextField.LabelText>
210 <Trans>Confirmation Code</Trans>
211 </TextField.LabelText>
212 <TextField.Root>
213 <TextField.Input
214 label={_(msg`Confirmation code`)}
215 placeholder="XXXXX-XXXXX"
216 onChangeText={setConfirmationCode}
217 />
218 </TextField.Root>
219 </View>
220 ) : null}
221 <View style={[a.gap_sm, gtMobile && [a.flex_row_reverse, a.ml_auto]]}>
222 {currentStep === 'StepOne' ? (
223 <>
224 <Button
225 label={_(msg`Send confirmation email`)}
226 variant="solid"
227 color="primary"
228 size="large"
229 disabled={isProcessing}
230 onPress={onSendEmail}>
231 <ButtonText>
232 <Trans>Send Confirmation</Trans>
233 </ButtonText>
234 {isProcessing ? (
235 <Loader size="sm" style={[{color: 'white'}]} />
236 ) : null}
237 </Button>
238 <Button
239 label={_(msg`I Have a Code`)}
240 variant="solid"
241 color="secondary"
242 size="large"
243 disabled={isProcessing}
244 onPress={() => setCurrentStep('StepTwo')}>
245 <ButtonText>
246 <Trans>I Have a Code</Trans>
247 </ButtonText>
248 </Button>
249 </>
250 ) : currentStep === 'StepTwo' ? (
251 <>
252 <Button
253 label={_(msg`Confirm`)}
254 variant="solid"
255 color="primary"
256 size="large"
257 disabled={isProcessing}
258 onPress={onVerifyEmail}>
259 <ButtonText>
260 <Trans>Confirm</Trans>
261 </ButtonText>
262 {isProcessing ? (
263 <Loader size="sm" style={[{color: 'white'}]} />
264 ) : null}
265 </Button>
266 <Button
267 label={_(msg`Resend Email`)}
268 variant="solid"
269 color="secondary"
270 size="large"
271 disabled={isProcessing}
272 onPress={() => {
273 setConfirmationCode('')
274 setCurrentStep('StepOne')
275 }}>
276 <ButtonText>
277 <Trans>Resend Email</Trans>
278 </ButtonText>
279 </Button>
280 </>
281 ) : currentStep === 'StepThree' ? (
282 <Button
283 label={_(msg`Confirm`)}
284 variant="solid"
285 color="primary"
286 size="large"
287 onPress={() => control.close()}>
288 <ButtonText>
289 <Trans>Close</Trans>
290 </ButtonText>
291 </Button>
292 ) : null}
293 </View>
294 </View>
295 </Dialog.ScrollableInner>
296 )
297}