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 <Text style={[a.text_md, a.leading_snug]}>
150 {currentStep === 'StepOne' ? (
151 <>
152 {!reasonText ? (
153 <>
154 <Trans>
155 You'll receive an email at{' '}
156 <Text style={[a.text_md, a.leading_snug, a.font_bold]}>
157 {currentAccount?.email}
158 </Text>{' '}
159 to verify it's you.
160 </Trans>{' '}
161 <InlineLinkText
162 to="#"
163 label={_(msg`Change email address`)}
164 style={[a.text_md, a.leading_snug]}
165 onPress={e => {
166 e.preventDefault()
167 control.close(() => {
168 openModal({name: 'change-email'})
169 })
170 return false
171 }}>
172 <Trans>Need to change it?</Trans>
173 </InlineLinkText>
174 </>
175 ) : (
176 reasonText
177 )}
178 </>
179 ) : (
180 uiStrings[currentStep].message
181 )}
182 </Text>
183 </View>
184 {currentStep === 'StepTwo' ? (
185 <View>
186 <TextField.LabelText>
187 <Trans>Confirmation Code</Trans>
188 </TextField.LabelText>
189 <TextField.Root>
190 <TextField.Input
191 label={_(msg`Confirmation code`)}
192 placeholder="XXXXX-XXXXX"
193 onChangeText={setConfirmationCode}
194 />
195 </TextField.Root>
196 </View>
197 ) : null}
198 <View style={[a.gap_sm, gtMobile && [a.flex_row_reverse, a.ml_auto]]}>
199 {currentStep === 'StepOne' ? (
200 <>
201 <Button
202 label={_(msg`Send confirmation email`)}
203 variant="solid"
204 color="primary"
205 size="large"
206 disabled={isProcessing}
207 onPress={onSendEmail}>
208 <ButtonText>
209 <Trans>Send Confirmation</Trans>
210 </ButtonText>
211 {isProcessing ? (
212 <Loader size="sm" style={[{color: 'white'}]} />
213 ) : null}
214 </Button>
215 <Button
216 label={_(msg`I Have a Code`)}
217 variant="solid"
218 color="secondary"
219 size="large"
220 disabled={isProcessing}
221 onPress={() => setCurrentStep('StepTwo')}>
222 <ButtonText>
223 <Trans>I Have a Code</Trans>
224 </ButtonText>
225 </Button>
226 </>
227 ) : currentStep === 'StepTwo' ? (
228 <>
229 <Button
230 label={_(msg`Confirm`)}
231 variant="solid"
232 color="primary"
233 size="large"
234 disabled={isProcessing}
235 onPress={onVerifyEmail}>
236 <ButtonText>
237 <Trans>Confirm</Trans>
238 </ButtonText>
239 {isProcessing ? (
240 <Loader size="sm" style={[{color: 'white'}]} />
241 ) : null}
242 </Button>
243 <Button
244 label={_(msg`Resend Email`)}
245 variant="solid"
246 color="secondary"
247 size="large"
248 disabled={isProcessing}
249 onPress={() => {
250 setConfirmationCode('')
251 setCurrentStep('StepOne')
252 }}>
253 <ButtonText>
254 <Trans>Resend Email</Trans>
255 </ButtonText>
256 </Button>
257 </>
258 ) : currentStep === 'StepThree' ? (
259 <Button
260 label={_(msg`Confirm`)}
261 variant="solid"
262 color="primary"
263 size="large"
264 onPress={() => control.close()}>
265 <ButtonText>
266 <Trans>Close</Trans>
267 </ButtonText>
268 </Button>
269 ) : null}
270 </View>
271 </View>
272 </Dialog.ScrollableInner>
273 )
274}