From 95bea8bf6a7b8521d3d5c78d00044327975a7e8b Mon Sep 17 00:00:00 2001 From: Hailey Date: Wed, 9 Oct 2024 13:53:14 -0700 Subject: [PATCH] alf email confirmation dialog --- src/components/dialogs/VerifyEmailDialog.tsx | 218 +++++++++++++++++++ src/view/com/modals/VerifyEmail.tsx | 10 +- src/view/screens/Settings/index.tsx | 6 +- 3 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 src/components/dialogs/VerifyEmailDialog.tsx diff --git a/src/components/dialogs/VerifyEmailDialog.tsx b/src/components/dialogs/VerifyEmailDialog.tsx new file mode 100644 index 0000000000..86838f8f6a --- /dev/null +++ b/src/components/dialogs/VerifyEmailDialog.tsx @@ -0,0 +1,218 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {cleanError} from '#/lib/strings/errors' +import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' +import {useAgent, useSession} from '#/state/session' +import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' +import {atoms as a} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import * as TextField from '#/components/forms/TextField' +import {Loader} from '#/components/Loader' +import {Text} from '#/components/Typography' + +export function VerifyEmailDialog({ + control, +}: { + control: Dialog.DialogControlProps +}) { + return ( + + + + + ) +} + +export function Inner({control}: {control: Dialog.DialogControlProps}) { + const {_} = useLingui() + const {currentAccount} = useSession() + const agent = useAgent() + const {openModal} = useModalControls() + + const [currentStep, setCurrentStep] = React.useState< + 'StepOne' | 'StepTwo' | 'StepThree' + >('StepOne') + const [confirmationCode, setConfirmationCode] = React.useState('') + const [isProcessing, setIsProcessing] = React.useState(false) + const [error, setError] = React.useState('') + + const uiStrings = { + StepOne: { + title: _(msg`Verify Your Email`), + message: '', + }, + StepTwo: { + title: _(msg`Enter Code`), + message: _( + msg`An email has been sent! Please enter the confirmation code included in the email below.`, + ), + }, + StepThree: { + title: _(msg`Success!`), + message: _(msg`Thank you! Your email has been successfully verified.`), + }, + } + + const onSendEmail = async () => { + setError('') + setIsProcessing(true) + try { + await agent.com.atproto.server.requestEmailConfirmation() + setCurrentStep('StepTwo') + } catch (e: unknown) { + setError(cleanError(e)) + } finally { + setIsProcessing(false) + } + } + + const onVerifyEmail = async () => { + setError('') + setIsProcessing(true) + try { + await agent.com.atproto.server.confirmEmail({ + email: (currentAccount?.email || '').trim(), + token: confirmationCode.trim(), + }) + } catch (e: unknown) { + setError(cleanError(String(e))) + setIsProcessing(false) + return + } + + try { + await agent.resumeSession(agent.session!) + } catch (e: unknown) { + setError(cleanError(String(e))) + setIsProcessing(false) + logger.error(String(e)) + return + } + + setIsProcessing(false) + setCurrentStep('StepThree') + } + + return ( + + + + + {uiStrings[currentStep].title} + + {error ? ( + + + + ) : null} + + {currentStep === 'StepOne' ? ( + + You'll receive an email at{' '} + + {currentAccount?.email} + {' '} + to verify it is you. + + ) : ( + uiStrings[currentStep].message + )} + + + {currentStep === 'StepTwo' ? ( + + + Confirmation Code + + + + + + ) : null} + + {currentStep === 'StepOne' ? ( + <> + + + + ) : currentStep === 'StepTwo' ? ( + <> + + + + ) : currentStep === 'StepThree' ? ( + + ) : null} + + + + ) +} diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx index 8fdec7d5df..fce1275fe7 100644 --- a/src/view/com/modals/VerifyEmail.tsx +++ b/src/view/com/modals/VerifyEmail.tsx @@ -11,14 +11,14 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {usePalette} from '#/lib/hooks/usePalette' +import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' +import {cleanError} from '#/lib/strings/errors' +import {colors, s} from '#/lib/styles' import {logger} from '#/logger' +import {isWeb} from '#/platform/detection' import {useModalControls} from '#/state/modals' import {useAgent, useSession} from '#/state/session' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {cleanError} from 'lib/strings/errors' -import {colors, s} from 'lib/styles' -import {isWeb} from 'platform/detection' import {ErrorMessage} from '../util/error/ErrorMessage' import {Button} from '../util/forms/Button' import {Text} from '../util/text/Text' diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx index a2b7670979..a40cc4f26a 100644 --- a/src/view/screens/Settings/index.tsx +++ b/src/view/screens/Settings/index.tsx @@ -56,6 +56,7 @@ import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateA import {atoms as a, useTheme} from '#/alf' import {useDialogControl} from '#/components/Dialog' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' +import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' import {Email2FAToggle} from './Email2FAToggle' import {ExportCarDialog} from './ExportCarDialog' @@ -927,7 +928,7 @@ function EmailConfirmationNotice() { const palInverted = usePalette('inverted') const {_} = useLingui() const {isMobile} = useWebMediaQueries() - const {openModal} = useModalControls() + const verifyEmailDialogControl = useDialogControl() return ( @@ -959,7 +960,7 @@ function EmailConfirmationNotice() { accessibilityRole="button" accessibilityLabel={_(msg`Verify my email`)} accessibilityHint={_(msg`Opens modal for email verification`)} - onPress={() => openModal({name: 'verify-email'})}> + onPress={() => verifyEmailDialogControl.open()}> Protect your account by verifying your email. + ) }