diff options
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/modals/ChangeEmail.tsx | 268 | ||||
-rw-r--r-- | src/view/com/modals/Modal.tsx | 8 | ||||
-rw-r--r-- | src/view/com/modals/Modal.web.tsx | 6 | ||||
-rw-r--r-- | src/view/com/modals/VerifyEmail.tsx | 342 |
4 files changed, 0 insertions, 624 deletions
diff --git a/src/view/com/modals/ChangeEmail.tsx b/src/view/com/modals/ChangeEmail.tsx deleted file mode 100644 index 003d3630e..000000000 --- a/src/view/com/modals/ChangeEmail.tsx +++ /dev/null @@ -1,268 +0,0 @@ -import {useState} from 'react' -import {ActivityIndicator, SafeAreaView, StyleSheet, View} from 'react-native' -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 {isWeb} from '#/platform/detection' -import {useModalControls} from '#/state/modals' -import {useAgent, useSession} from '#/state/session' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {Button} from '../util/forms/Button' -import {Text} from '../util/text/Text' -import * as Toast from '../util/Toast' -import {ScrollView, TextInput} from './util' - -enum Stages { - InputEmail, - ConfirmCode, - Done, -} - -export const snapPoints = ['90%'] - -export function Component() { - const pal = usePalette('default') - const {currentAccount} = useSession() - const agent = useAgent() - const {_} = useLingui() - const [stage, setStage] = useState<Stages>(Stages.InputEmail) - const [email, setEmail] = useState<string>(currentAccount?.email || '') - const [confirmationCode, setConfirmationCode] = useState<string>('') - const [isProcessing, setIsProcessing] = useState<boolean>(false) - const [error, setError] = useState<string>('') - const {isMobile} = useWebMediaQueries() - const {openModal, closeModal} = useModalControls() - - const onRequestChange = async () => { - if (email === currentAccount?.email) { - setError(_(msg`Enter your new email above`)) - return - } - setError('') - setIsProcessing(true) - try { - const res = await agent.com.atproto.server.requestEmailUpdate() - if (res.data.tokenRequired) { - setStage(Stages.ConfirmCode) - } else { - await agent.com.atproto.server.updateEmail({email: email.trim()}) - await agent.resumeSession(agent.session!) - Toast.show(_(msg({message: 'Email updated', context: 'toast'}))) - setStage(Stages.Done) - } - } catch (e) { - let err = cleanError(String(e)) - // TEMP - // while rollout is occuring, we're giving a temporary error message - // you can remove this any time after Oct2023 - // -prf - if (err === 'email must be confirmed (temporary)') { - err = _( - msg`Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed.`, - ) - } - setError(err) - } finally { - setIsProcessing(false) - } - } - - const onConfirm = async () => { - setError('') - setIsProcessing(true) - try { - await agent.com.atproto.server.updateEmail({ - email: email.trim(), - token: confirmationCode.trim(), - }) - await agent.resumeSession(agent.session!) - Toast.show(_(msg({message: 'Email updated', context: 'toast'}))) - setStage(Stages.Done) - } catch (e) { - setError(cleanError(String(e))) - } finally { - setIsProcessing(false) - } - } - - const onVerify = async () => { - closeModal() - openModal({name: 'verify-email'}) - } - - return ( - <SafeAreaView style={[pal.view, s.flex1]}> - <ScrollView - testID="changeEmailModal" - style={[s.flex1, isMobile && {paddingHorizontal: 18}]}> - <View style={styles.titleSection}> - <Text type="title-lg" style={[pal.text, styles.title]}> - {stage === Stages.InputEmail ? _(msg`Change Your Email`) : ''} - {stage === Stages.ConfirmCode ? _(msg`Security Step Required`) : ''} - {stage === Stages.Done ? _(msg`Email Updated`) : ''} - </Text> - </View> - - <Text type="lg" style={[pal.textLight, {marginBottom: 10}]}> - {stage === Stages.InputEmail ? ( - <Trans>Enter your new email address below.</Trans> - ) : stage === Stages.ConfirmCode ? ( - <Trans> - An email has been sent to your previous address,{' '} - {currentAccount?.email || '(no email)'}. It includes a - confirmation code which you can enter below. - </Trans> - ) : ( - <Trans> - Your email has been updated but not verified. As a next step, - please verify your new email. - </Trans> - )} - </Text> - - {stage === Stages.InputEmail && ( - <TextInput - testID="emailInput" - style={[styles.textInput, pal.border, pal.text]} - placeholder="alice@mail.com" - placeholderTextColor={pal.colors.textLight} - value={email} - onChangeText={setEmail} - accessible={true} - accessibilityLabel={_(msg`Email`)} - accessibilityHint="" - autoCapitalize="none" - autoComplete="email" - autoCorrect={false} - /> - )} - {stage === Stages.ConfirmCode && ( - <TextInput - testID="confirmCodeInput" - style={[styles.textInput, pal.border, pal.text]} - placeholder="XXXXX-XXXXX" - placeholderTextColor={pal.colors.textLight} - value={confirmationCode} - onChangeText={setConfirmationCode} - accessible={true} - accessibilityLabel={_(msg`Confirmation code`)} - accessibilityHint="" - autoCapitalize="none" - autoComplete="off" - autoCorrect={false} - /> - )} - - {error ? ( - <ErrorMessage message={error} style={styles.error} /> - ) : undefined} - - <View style={[styles.btnContainer]}> - {isProcessing ? ( - <View style={styles.btn}> - <ActivityIndicator color="#fff" /> - </View> - ) : ( - <View style={{gap: 6}}> - {stage === Stages.InputEmail && ( - <Button - testID="requestChangeBtn" - type="primary" - onPress={onRequestChange} - accessibilityLabel={_(msg`Request Change`)} - accessibilityHint="" - label={_(msg`Request Change`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - )} - {stage === Stages.ConfirmCode && ( - <Button - testID="confirmBtn" - type="primary" - onPress={onConfirm} - accessibilityLabel={_(msg`Confirm Change`)} - accessibilityHint="" - label={_(msg`Confirm Change`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - )} - {stage === Stages.Done && ( - <Button - testID="verifyBtn" - type="primary" - onPress={onVerify} - accessibilityLabel={_(msg`Verify New Email`)} - accessibilityHint="" - label={_(msg`Verify New Email`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - )} - <Button - testID="cancelBtn" - type="default" - onPress={() => { - closeModal() - }} - accessibilityLabel={_(msg`Cancel`)} - accessibilityHint="" - label={_(msg`Cancel`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - </View> - )} - </View> - </ScrollView> - </SafeAreaView> - ) -} - -const styles = StyleSheet.create({ - titleSection: { - paddingTop: isWeb ? 0 : 4, - paddingBottom: isWeb ? 14 : 10, - }, - title: { - textAlign: 'center', - fontWeight: '600', - marginBottom: 5, - }, - error: { - borderRadius: 6, - marginTop: 10, - }, - emailContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - borderWidth: 1, - borderRadius: 6, - paddingHorizontal: 14, - paddingVertical: 12, - }, - textInput: { - borderWidth: 1, - borderRadius: 6, - paddingHorizontal: 14, - paddingVertical: 10, - fontSize: 16, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - backgroundColor: colors.blue3, - }, - btnContainer: { - paddingTop: 20, - }, -}) diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index b4572172c..d0b50c857 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -7,7 +7,6 @@ import {usePalette} from '#/lib/hooks/usePalette' import {useModalControls, useModals} from '#/state/modals' import {FullWindowOverlay} from '#/components/FullWindowOverlay' import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' -import * as ChangeEmailModal from './ChangeEmail' import * as ChangePasswordModal from './ChangePassword' import * as CreateOrEditListModal from './CreateOrEditList' import * as DeleteAccountModal from './DeleteAccount' @@ -18,7 +17,6 @@ import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguages import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings' import * as LinkWarningModal from './LinkWarning' import * as UserAddRemoveListsModal from './UserAddRemoveLists' -import * as VerifyEmailModal from './VerifyEmail' const DEFAULT_SNAPPOINTS = ['90%'] const HANDLE_HEIGHT = 24 @@ -72,12 +70,6 @@ export function ModalsContainer() { } else if (activeModal?.name === 'post-languages-settings') { snapPoints = PostLanguagesSettingsModal.snapPoints element = <PostLanguagesSettingsModal.Component /> - } else if (activeModal?.name === 'verify-email') { - snapPoints = VerifyEmailModal.snapPoints - element = <VerifyEmailModal.Component {...activeModal} /> - } else if (activeModal?.name === 'change-email') { - snapPoints = ChangeEmailModal.snapPoints - element = <ChangeEmailModal.Component /> } else if (activeModal?.name === 'change-password') { snapPoints = ChangePasswordModal.snapPoints element = <ChangePasswordModal.Component /> diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index 74ee7c210..524780099 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -6,7 +6,6 @@ import {usePalette} from '#/lib/hooks/usePalette' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {type Modal as ModalIface} from '#/state/modals' import {useModalControls, useModals} from '#/state/modals' -import * as ChangeEmailModal from './ChangeEmail' import * as ChangePasswordModal from './ChangePassword' import * as CreateOrEditListModal from './CreateOrEditList' import * as CropImageModal from './CropImage.web' @@ -17,7 +16,6 @@ import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguages import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings' import * as LinkWarningModal from './LinkWarning' import * as UserAddRemoveLists from './UserAddRemoveLists' -import * as VerifyEmailModal from './VerifyEmail' export function ModalsContainer() { const {isModalActive, activeModals} = useModals() @@ -74,10 +72,6 @@ function Modal({modal}: {modal: ModalIface}) { element = <ContentLanguagesSettingsModal.Component /> } else if (modal.name === 'post-languages-settings') { element = <PostLanguagesSettingsModal.Component /> - } else if (modal.name === 'verify-email') { - element = <VerifyEmailModal.Component {...modal} /> - } else if (modal.name === 'change-email') { - element = <ChangeEmailModal.Component /> } else if (modal.name === 'change-password') { element = <ChangePasswordModal.Component /> } else if (modal.name === 'link-warning') { diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx deleted file mode 100644 index 45444843a..000000000 --- a/src/view/com/modals/VerifyEmail.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import React, {useState} from 'react' -import { - ActivityIndicator, - Pressable, - SafeAreaView, - StyleSheet, - View, -} from 'react-native' -import {Circle, Path, Svg} from 'react-native-svg' -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 {ErrorMessage} from '../util/error/ErrorMessage' -import {Button} from '../util/forms/Button' -import {Text} from '../util/text/Text' -import * as Toast from '../util/Toast' -import {ScrollView, TextInput} from './util' - -export const snapPoints = ['90%'] - -enum Stages { - Reminder, - Email, - ConfirmCode, -} - -export function Component({ - showReminder, - onSuccess, -}: { - showReminder?: boolean - onSuccess?: () => void -}) { - const pal = usePalette('default') - const agent = useAgent() - const {currentAccount} = useSession() - const {_} = useLingui() - const [stage, setStage] = useState<Stages>( - showReminder ? Stages.Reminder : Stages.Email, - ) - const [confirmationCode, setConfirmationCode] = useState<string>('') - const [isProcessing, setIsProcessing] = useState<boolean>(false) - const [error, setError] = useState<string>('') - const {isMobile} = useWebMediaQueries() - const {openModal, closeModal} = useModalControls() - - React.useEffect(() => { - if (!currentAccount) { - logger.error(`VerifyEmail modal opened without currentAccount`) - closeModal() - } - }, [currentAccount, closeModal]) - - const onSendEmail = async () => { - setError('') - setIsProcessing(true) - try { - await agent.com.atproto.server.requestEmailConfirmation() - setStage(Stages.ConfirmCode) - } catch (e) { - setError(cleanError(String(e))) - } finally { - setIsProcessing(false) - } - } - - const onConfirm = async () => { - setError('') - setIsProcessing(true) - try { - await agent.com.atproto.server.confirmEmail({ - email: (currentAccount?.email || '').trim(), - token: confirmationCode.trim(), - }) - await agent.resumeSession(agent.session!) - Toast.show(_(msg({message: 'Email verified', context: 'toast'}))) - closeModal() - onSuccess?.() - } catch (e) { - setError(cleanError(String(e))) - } finally { - setIsProcessing(false) - } - } - - const onEmailIncorrect = () => { - closeModal() - openModal({name: 'change-email'}) - } - - return ( - <SafeAreaView style={[pal.view, s.flex1]}> - <ScrollView - testID="verifyEmailModal" - style={[s.flex1, isMobile && {paddingHorizontal: 18}]}> - {stage === Stages.Reminder && <ReminderIllustration />} - <View style={styles.titleSection}> - <Text type="title-lg" style={[pal.text, styles.title]}> - {stage === Stages.Reminder ? ( - <Trans>Please Verify Your Email</Trans> - ) : stage === Stages.Email ? ( - <Trans>Verify Your Email</Trans> - ) : stage === Stages.ConfirmCode ? ( - <Trans>Enter Confirmation Code</Trans> - ) : ( - '' - )} - </Text> - </View> - - <Text type="lg" style={[pal.textLight, {marginBottom: 10}]}> - {stage === Stages.Reminder ? ( - <Trans> - Your email has not yet been verified. This is an important - security step which we recommend. - </Trans> - ) : stage === Stages.Email ? ( - <Trans> - This is important in case you ever need to change your email or - reset your password. - </Trans> - ) : stage === Stages.ConfirmCode ? ( - <Trans> - An email has been sent to {currentAccount?.email || '(no email)'}. - It includes a confirmation code which you can enter below. - </Trans> - ) : ( - '' - )} - </Text> - - {stage === Stages.Email ? ( - <> - <View style={styles.emailContainer}> - <FontAwesomeIcon - icon="envelope" - color={pal.colors.text} - size={16} - /> - <Text type="xl-medium" style={[pal.text, s.flex1, {minWidth: 0}]}> - {currentAccount?.email || _(msg`(no email)`)} - </Text> - </View> - <Pressable - accessibilityRole="link" - accessibilityLabel={_(msg`Change my email`)} - accessibilityHint="" - onPress={onEmailIncorrect} - style={styles.changeEmailLink}> - <Text type="lg" style={pal.link}> - <Trans>Change</Trans> - </Text> - </Pressable> - </> - ) : stage === Stages.ConfirmCode ? ( - <TextInput - testID="confirmCodeInput" - style={[styles.textInput, pal.border, pal.text]} - placeholder="XXXXX-XXXXX" - placeholderTextColor={pal.colors.textLight} - value={confirmationCode} - onChangeText={setConfirmationCode} - accessible={true} - accessibilityLabel={_(msg`Confirmation code`)} - accessibilityHint="" - autoCapitalize="none" - autoComplete="one-time-code" - autoCorrect={false} - /> - ) : undefined} - - {error ? ( - <ErrorMessage message={error} style={styles.error} /> - ) : undefined} - - <View style={[styles.btnContainer]}> - {isProcessing ? ( - <View style={styles.btn}> - <ActivityIndicator color="#fff" /> - </View> - ) : ( - <View style={{gap: 6}}> - {stage === Stages.Reminder && ( - <Button - testID="getStartedBtn" - type="primary" - onPress={() => setStage(Stages.Email)} - accessibilityLabel={_(msg`Get Started`)} - accessibilityHint="" - label={_(msg`Get Started`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - )} - {stage === Stages.Email && ( - <> - <Button - testID="sendEmailBtn" - type="primary" - onPress={onSendEmail} - accessibilityLabel={_(msg`Send Confirmation Email`)} - accessibilityHint="" - label={_(msg`Send Confirmation Email`)} - labelContainerStyle={{ - justifyContent: 'center', - padding: 4, - }} - labelStyle={[s.f18]} - /> - <Button - testID="haveCodeBtn" - type="default" - accessibilityLabel={_(msg`I have a code`)} - accessibilityHint="" - label={_(msg`I have a confirmation code`)} - labelContainerStyle={{ - justifyContent: 'center', - padding: 4, - }} - labelStyle={[s.f18]} - onPress={() => setStage(Stages.ConfirmCode)} - /> - </> - )} - {stage === Stages.ConfirmCode && ( - <Button - testID="confirmBtn" - type="primary" - onPress={onConfirm} - accessibilityLabel={_(msg`Confirm`)} - accessibilityHint="" - label={_(msg`Confirm`)} - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - )} - <Button - testID="cancelBtn" - type="default" - onPress={() => { - closeModal() - }} - accessibilityLabel={ - stage === Stages.Reminder - ? _(msg`Not right now`) - : _(msg`Cancel`) - } - accessibilityHint="" - label={ - stage === Stages.Reminder - ? _(msg`Not right now`) - : _(msg`Cancel`) - } - labelContainerStyle={{justifyContent: 'center', padding: 4}} - labelStyle={[s.f18]} - /> - </View> - )} - </View> - </ScrollView> - </SafeAreaView> - ) -} - -function ReminderIllustration() { - const pal = usePalette('default') - const palInverted = usePalette('inverted') - return ( - <View style={[pal.viewLight, {borderRadius: 8, marginBottom: 20}]}> - <Svg viewBox="0 0 112 84" fill="none" height={200}> - <Path - fillRule="evenodd" - clipRule="evenodd" - d="M26 26.4264V55C26 60.5229 30.4772 65 36 65H76C81.5228 65 86 60.5229 86 55V27.4214L63.5685 49.8528C59.6633 53.7581 53.3316 53.7581 49.4264 49.8528L26 26.4264Z" - fill={palInverted.colors.background} - /> - <Path - fillRule="evenodd" - clipRule="evenodd" - d="M83.666 19.5784C85.47 21.7297 84.4897 24.7895 82.5044 26.7748L60.669 48.6102C58.3259 50.9533 54.5269 50.9533 52.1838 48.6102L29.9502 26.3766C27.8241 24.2505 26.8952 20.8876 29.0597 18.8005C30.8581 17.0665 33.3045 16 36 16H76C79.0782 16 81.8316 17.3908 83.666 19.5784Z" - fill={palInverted.colors.background} - /> - <Circle cx="82" cy="61" r="13" fill="#20BC07" /> - <Path d="M75 61L80 66L89 57" stroke="white" strokeWidth="2" /> - </Svg> - </View> - ) -} - -const styles = StyleSheet.create({ - titleSection: { - paddingTop: isWeb ? 0 : 4, - paddingBottom: isWeb ? 14 : 10, - }, - title: { - textAlign: 'center', - fontWeight: '600', - marginBottom: 5, - }, - error: { - borderRadius: 6, - marginTop: 10, - }, - emailContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - paddingHorizontal: 14, - marginTop: 10, - }, - changeEmailLink: { - marginHorizontal: 12, - marginBottom: 12, - }, - textInput: { - borderWidth: 1, - borderRadius: 6, - paddingHorizontal: 14, - paddingVertical: 10, - fontSize: 16, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - backgroundColor: colors.blue3, - }, - btnContainer: { - paddingTop: 20, - }, -}) |