diff options
author | Eric Bailey <git@esb.lol> | 2025-06-17 18:12:37 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-17 18:12:37 -0500 |
commit | 619fa0d0bbac80100aefeb926ca7098f0644d0d8 (patch) | |
tree | 40729c362c6412c88ba6c9887bdff1bf65891d7f | |
parent | 9cf457acf8495c1287e366f677e1516847e4d739 (diff) | |
download | voidsky-619fa0d0bbac80100aefeb926ca7098f0644d0d8.tar.zst |
Delete some old dialogs (#8512)
* Delete old EditProfile dialog * Delete old email verification dialogs
-rw-r--r-- | src/components/dialogs/ChangeEmailDialog.tsx | 259 | ||||
-rw-r--r-- | src/components/dialogs/VerifyEmailDialog.tsx | 360 | ||||
-rw-r--r-- | src/view/com/modals/EditProfile.tsx | 335 |
3 files changed, 0 insertions, 954 deletions
diff --git a/src/components/dialogs/ChangeEmailDialog.tsx b/src/components/dialogs/ChangeEmailDialog.tsx deleted file mode 100644 index 93397bae9..000000000 --- a/src/components/dialogs/ChangeEmailDialog.tsx +++ /dev/null @@ -1,259 +0,0 @@ -import {useState} 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 {useAgent, useSession} from '#/state/session' -import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' -import {atoms as a, useBreakpoints, web} 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 ChangeEmailDialog({ - control, - verifyEmailControl, -}: { - control: Dialog.DialogControlProps - verifyEmailControl: Dialog.DialogControlProps -}) { - return ( - <Dialog.Outer control={control}> - <Dialog.Handle /> - <Inner verifyEmailControl={verifyEmailControl} /> - </Dialog.Outer> - ) -} - -export function Inner({ - verifyEmailControl, -}: { - verifyEmailControl: Dialog.DialogControlProps -}) { - const {_} = useLingui() - const {currentAccount} = useSession() - const agent = useAgent() - const control = Dialog.useDialogContext() - const {gtMobile} = useBreakpoints() - - const [currentStep, setCurrentStep] = useState< - 'StepOne' | 'StepTwo' | 'StepThree' - >('StepOne') - const [email, setEmail] = useState('') - const [confirmationCode, setConfirmationCode] = useState('') - const [isProcessing, setIsProcessing] = useState(false) - const [error, setError] = useState('') - - const currentEmail = currentAccount?.email || '(no email)' - const uiStrings = { - StepOne: { - title: _(msg`Change Your Email`), - message: '', - }, - StepTwo: { - title: _(msg`Security Step Required`), - message: _( - msg`An email has been sent to your previous address, ${currentEmail}. It includes a confirmation code which you can enter below.`, - ), - }, - StepThree: { - title: _(msg`Email Updated!`), - message: _( - msg`Your email address has been updated but it is not yet verified. As a next step, please verify your new email.`, - ), - }, - } - - const onRequestChange = async () => { - if (email === currentAccount?.email) { - setError( - _( - msg`The email address you entered is the same as your current email address.`, - ), - ) - return - } - setError('') - setIsProcessing(true) - try { - const res = await agent.com.atproto.server.requestEmailUpdate() - if (res.data.tokenRequired) { - setCurrentStep('StepTwo') - } else { - await agent.com.atproto.server.updateEmail({email: email.trim()}) - await agent.resumeSession(agent.session!) - setCurrentStep('StepThree') - } - } catch (e) { - setError(cleanError(String(e))) - } 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!) - setCurrentStep('StepThree') - } catch (e) { - setError(cleanError(String(e))) - } finally { - setIsProcessing(false) - } - } - - const onVerify = async () => { - control.close(() => { - verifyEmailControl.open() - }) - } - - return ( - <Dialog.ScrollableInner - label={_(msg`Verify email dialog`)} - style={web({maxWidth: 450})}> - <Dialog.Close /> - <View style={[a.gap_xl]}> - <View style={[a.gap_sm]}> - <Text style={[a.font_heavy, a.text_2xl]}> - {uiStrings[currentStep].title} - </Text> - {error ? ( - <View style={[a.rounded_sm, a.overflow_hidden]}> - <ErrorMessage message={error} /> - </View> - ) : null} - {currentStep === 'StepOne' ? ( - <View> - <TextField.LabelText> - <Trans>Enter your new email address below.</Trans> - </TextField.LabelText> - <TextField.Root> - <TextField.Input - label={_(msg`New email address`)} - placeholder={_(msg`alice@example.com`)} - defaultValue={email} - onChangeText={setEmail} - keyboardType="email-address" - autoComplete="email" - /> - </TextField.Root> - </View> - ) : ( - <Text style={[a.text_md, a.leading_snug]}> - {uiStrings[currentStep].message} - </Text> - )} - </View> - {currentStep === 'StepTwo' ? ( - <View> - <TextField.LabelText> - <Trans>Confirmation code</Trans> - </TextField.LabelText> - <TextField.Root> - <TextField.Input - label={_(msg`Confirmation code`)} - placeholder="XXXXX-XXXXX" - onChangeText={setConfirmationCode} - /> - </TextField.Root> - </View> - ) : null} - <View style={[a.gap_sm, gtMobile && [a.flex_row_reverse, a.ml_auto]]}> - {currentStep === 'StepOne' ? ( - <> - <Button - label={_(msg`Request change`)} - variant="solid" - color="primary" - size="large" - disabled={isProcessing} - onPress={onRequestChange}> - <ButtonText> - <Trans>Request change</Trans> - </ButtonText> - {isProcessing ? ( - <Loader size="sm" style={[{color: 'white'}]} /> - ) : null} - </Button> - <Button - label={_(msg`I have a code`)} - variant="solid" - color="secondary" - size="large" - disabled={isProcessing} - onPress={() => setCurrentStep('StepTwo')}> - <ButtonText> - <Trans>I have a code</Trans> - </ButtonText> - </Button> - </> - ) : currentStep === 'StepTwo' ? ( - <> - <Button - label={_(msg`Confirm`)} - variant="solid" - color="primary" - size="large" - disabled={isProcessing} - onPress={onConfirm}> - <ButtonText> - <Trans>Confirm</Trans> - </ButtonText> - {isProcessing ? ( - <Loader size="sm" style={[{color: 'white'}]} /> - ) : null} - </Button> - <Button - label={_(msg`Resend email`)} - variant="solid" - color="secondary" - size="large" - disabled={isProcessing} - onPress={() => { - setConfirmationCode('') - setCurrentStep('StepOne') - }}> - <ButtonText> - <Trans>Resend email</Trans> - </ButtonText> - </Button> - </> - ) : currentStep === 'StepThree' ? ( - <> - <Button - label={_(msg`Verify email`)} - variant="solid" - color="primary" - size="large" - onPress={onVerify}> - <ButtonText> - <Trans>Verify email</Trans> - </ButtonText> - </Button> - <Button - label={_(msg`Close`)} - variant="solid" - color="secondary" - size="large" - onPress={() => control.close()}> - <ButtonText> - <Trans>Close</Trans> - </ButtonText> - </Button> - </> - ) : null} - </View> - </View> - </Dialog.ScrollableInner> - ) -} diff --git a/src/components/dialogs/VerifyEmailDialog.tsx b/src/components/dialogs/VerifyEmailDialog.tsx deleted file mode 100644 index b8d1cd192..000000000 --- a/src/components/dialogs/VerifyEmailDialog.tsx +++ /dev/null @@ -1,360 +0,0 @@ -import {useState} 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 {useAgent, useSession} from '#/state/session' -import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' -import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' -import {Button, ButtonText} from '#/components/Button' -import * as Dialog from '#/components/Dialog' -import * as TextField from '#/components/forms/TextField' -import {Envelope_Filled_Stroke2_Corner0_Rounded as EnvelopeIcon} from '#/components/icons/Envelope' -import {InlineLinkText} from '#/components/Link' -import {Loader} from '#/components/Loader' -import {Text} from '#/components/Typography' -import {ChangeEmailDialog} from './ChangeEmailDialog' - -export function VerifyEmailDialog({ - control, - onCloseWithoutVerifying, - onCloseAfterVerifying, - reasonText, - changeEmailControl, - reminder, -}: { - control: Dialog.DialogControlProps - onCloseWithoutVerifying?: () => void - onCloseAfterVerifying?: () => void - reasonText?: string - /** - * if a changeEmailControl for a ChangeEmailDialog is not provided, - * this component will create one for you. Using this prop - * helps reduce duplication, since these dialogs are often used together. - */ - changeEmailControl?: Dialog.DialogControlProps - reminder?: boolean -}) { - const agent = useAgent() - const fallbackChangeEmailControl = Dialog.useDialogControl() - - const [didVerify, setDidVerify] = useState(false) - - return ( - <> - <Dialog.Outer - control={control} - onClose={async () => { - if (!didVerify) { - onCloseWithoutVerifying?.() - return - } - - try { - await agent.resumeSession(agent.session!) - onCloseAfterVerifying?.() - } catch (e: unknown) { - logger.error(String(e)) - return - } - }}> - <Dialog.Handle /> - <Inner - setDidVerify={setDidVerify} - reasonText={reasonText} - changeEmailControl={changeEmailControl ?? fallbackChangeEmailControl} - reminder={reminder} - /> - </Dialog.Outer> - {!changeEmailControl && ( - <ChangeEmailDialog - control={fallbackChangeEmailControl} - verifyEmailControl={control} - /> - )} - </> - ) -} - -export function Inner({ - setDidVerify, - reasonText, - changeEmailControl, - reminder, -}: { - setDidVerify: (value: boolean) => void - reasonText?: string - changeEmailControl: Dialog.DialogControlProps - reminder?: boolean -}) { - const control = Dialog.useDialogContext() - const {_} = useLingui() - const {currentAccount} = useSession() - const agent = useAgent() - const {gtMobile} = useBreakpoints() - const t = useTheme() - - const [currentStep, setCurrentStep] = useState< - 'Reminder' | 'StepOne' | 'StepTwo' | 'StepThree' - >(reminder ? 'Reminder' : 'StepOne') - const [confirmationCode, setConfirmationCode] = useState('') - const [isProcessing, setIsProcessing] = useState(false) - const [error, setError] = useState('') - - const uiStrings = { - Reminder: { - title: _(msg`Please Verify Your Email`), - message: _( - msg`Your email has not yet been verified. This is an important security step which we recommend.`, - ), - }, - 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 - } - - setIsProcessing(false) - setDidVerify(true) - setCurrentStep('StepThree') - } - - return ( - <Dialog.ScrollableInner - label={_(msg`Verify email dialog`)} - style={web({maxWidth: 450})}> - <View style={[a.gap_xl]}> - {currentStep === 'Reminder' && ( - <View - style={[ - a.rounded_sm, - a.align_center, - a.justify_center, - {height: 150}, - t.atoms.bg_contrast_100, - ]}> - <EnvelopeIcon width={64} fill="white" /> - </View> - )} - <View style={[a.gap_sm]}> - <Text style={[a.font_heavy, a.text_2xl]}> - {uiStrings[currentStep].title} - </Text> - {error ? ( - <View style={[a.rounded_sm, a.overflow_hidden]}> - <ErrorMessage message={error} /> - </View> - ) : null} - {currentStep === 'StepOne' ? ( - <View> - {reasonText ? ( - <View style={[a.gap_sm]}> - <Text style={[a.text_md, a.leading_snug]}>{reasonText}</Text> - <Text style={[a.text_md, a.leading_snug]}> - Don't have access to{' '} - <Text style={[a.text_md, a.leading_snug, a.font_bold]}> - {currentAccount?.email} - </Text> - ?{' '} - <InlineLinkText - to="#" - label={_(msg`Change email address`)} - style={[a.text_md, a.leading_snug]} - onPress={e => { - e.preventDefault() - control.close(() => { - changeEmailControl.open() - }) - return false - }}> - <Trans>Change your email address</Trans> - </InlineLinkText> - . - </Text> - </View> - ) : ( - <Text style={[a.text_md, a.leading_snug]}> - <Trans> - You'll receive an email at{' '} - <Text style={[a.text_md, a.leading_snug, a.font_bold]}> - {currentAccount?.email} - </Text>{' '} - to verify it's you. - </Trans>{' '} - <InlineLinkText - to="#" - label={_(msg`Change email address`)} - style={[a.text_md, a.leading_snug]} - onPress={e => { - e.preventDefault() - control.close(() => { - changeEmailControl.open() - }) - return false - }}> - <Trans>Need to change it?</Trans> - </InlineLinkText> - </Text> - )} - </View> - ) : ( - <Text style={[a.text_md, a.leading_snug]}> - {uiStrings[currentStep].message} - </Text> - )} - </View> - {currentStep === 'StepTwo' ? ( - <View> - <TextField.LabelText> - <Trans>Confirmation Code</Trans> - </TextField.LabelText> - <TextField.Root> - <TextField.Input - label={_(msg`Confirmation code`)} - placeholder="XXXXX-XXXXX" - onChangeText={setConfirmationCode} - /> - </TextField.Root> - </View> - ) : null} - <View style={[a.gap_sm, gtMobile && [a.flex_row_reverse, a.ml_auto]]}> - {currentStep === 'Reminder' ? ( - <> - <Button - label={_(msg`Get started`)} - variant="solid" - color="primary" - size="large" - onPress={() => setCurrentStep('StepOne')}> - <ButtonText> - <Trans>Get started</Trans> - </ButtonText> - </Button> - <Button - label={_(msg`Maybe later`)} - accessibilityHint={_(msg`Snoozes the reminder`)} - variant="ghost" - color="secondary" - size="large" - disabled={isProcessing} - onPress={() => control.close()}> - <ButtonText> - <Trans>Maybe later</Trans> - </ButtonText> - </Button> - </> - ) : currentStep === 'StepOne' ? ( - <> - <Button - label={_(msg`Send confirmation email`)} - variant="solid" - color="primary" - size="large" - disabled={isProcessing} - onPress={onSendEmail}> - <ButtonText> - <Trans>Send confirmation</Trans> - </ButtonText> - {isProcessing ? ( - <Loader size="sm" style={[{color: 'white'}]} /> - ) : null} - </Button> - <Button - label={_(msg`I have a code`)} - variant="solid" - color="secondary" - size="large" - disabled={isProcessing} - onPress={() => setCurrentStep('StepTwo')}> - <ButtonText> - <Trans>I have a code</Trans> - </ButtonText> - </Button> - </> - ) : currentStep === 'StepTwo' ? ( - <> - <Button - label={_(msg`Confirm`)} - variant="solid" - color="primary" - size="large" - disabled={isProcessing} - onPress={onVerifyEmail}> - <ButtonText> - <Trans>Confirm</Trans> - </ButtonText> - {isProcessing ? ( - <Loader size="sm" style={[{color: 'white'}]} /> - ) : null} - </Button> - <Button - label={_(msg`Resend email`)} - variant="solid" - color="secondary" - size="large" - disabled={isProcessing} - onPress={() => { - setConfirmationCode('') - setCurrentStep('StepOne') - }}> - <ButtonText> - <Trans>Resend email</Trans> - </ButtonText> - </Button> - </> - ) : currentStep === 'StepThree' ? ( - <Button - label={_(msg`Close`)} - variant="solid" - color="primary" - size="large" - onPress={() => control.close()}> - <ButtonText> - <Trans>Close</Trans> - </ButtonText> - </Button> - ) : null} - </View> - </View> - </Dialog.ScrollableInner> - ) -} diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx deleted file mode 100644 index cb1552fe5..000000000 --- a/src/view/com/modals/EditProfile.tsx +++ /dev/null @@ -1,335 +0,0 @@ -import {useCallback, useState} from 'react' -import { - ActivityIndicator, - KeyboardAvoidingView, - ScrollView, - StyleSheet, - TextInput, - TouchableOpacity, - View, -} from 'react-native' -import Animated, {FadeOut} from 'react-native-reanimated' -import {LinearGradient} from 'expo-linear-gradient' -import {type AppBskyActorDefs} from '@atproto/api' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' - -import {MAX_DESCRIPTION, MAX_DISPLAY_NAME, urls} from '#/lib/constants' -import {usePalette} from '#/lib/hooks/usePalette' -import {compressIfNeeded} from '#/lib/media/manip' -import {type PickerImage} from '#/lib/media/picker.shared' -import {cleanError} from '#/lib/strings/errors' -import {enforceLen} from '#/lib/strings/helpers' -import {colors, gradients, s} from '#/lib/styles' -import {useTheme} from '#/lib/ThemeContext' -import {logger} from '#/logger' -import {isWeb} from '#/platform/detection' -import {useModalControls} from '#/state/modals' -import {useProfileUpdateMutation} from '#/state/queries/profile' -import {Text} from '#/view/com/util/text/Text' -import * as Toast from '#/view/com/util/Toast' -import {EditableUserAvatar} from '#/view/com/util/UserAvatar' -import {UserBanner} from '#/view/com/util/UserBanner' -import {Admonition} from '#/components/Admonition' -import {InlineLinkText} from '#/components/Link' -import {useSimpleVerificationState} from '#/components/verification' -import {ErrorMessage} from '../util/error/ErrorMessage' - -const AnimatedTouchableOpacity = - Animated.createAnimatedComponent(TouchableOpacity) - -export const snapPoints = ['fullscreen'] - -export function Component({ - profile, - onUpdate, -}: { - profile: AppBskyActorDefs.ProfileViewDetailed - onUpdate?: () => void -}) { - const pal = usePalette('default') - const theme = useTheme() - const {_} = useLingui() - const {closeModal} = useModalControls() - const updateMutation = useProfileUpdateMutation() - const [imageError, setImageError] = useState<string>('') - const initialDisplayName = profile.displayName || '' - const [displayName, setDisplayName] = useState<string>( - profile.displayName || '', - ) - const [description, setDescription] = useState<string>( - profile.description || '', - ) - const [userBanner, setUserBanner] = useState<string | undefined | null>( - profile.banner, - ) - const [userAvatar, setUserAvatar] = useState<string | undefined | null>( - profile.avatar, - ) - const [newUserBanner, setNewUserBanner] = useState< - PickerImage | undefined | null - >() - const [newUserAvatar, setNewUserAvatar] = useState< - PickerImage | undefined | null - >() - const onPressCancel = () => { - closeModal() - } - const onSelectNewAvatar = useCallback( - async (img: PickerImage | null) => { - setImageError('') - if (img === null) { - setNewUserAvatar(null) - setUserAvatar(null) - return - } - try { - const finalImg = await compressIfNeeded(img, 1000000) - setNewUserAvatar(finalImg) - setUserAvatar(finalImg.path) - } catch (e: any) { - setImageError(cleanError(e)) - } - }, - [setNewUserAvatar, setUserAvatar, setImageError], - ) - - const onSelectNewBanner = useCallback( - async (img: PickerImage | null) => { - setImageError('') - if (!img) { - setNewUserBanner(null) - setUserBanner(null) - return - } - try { - const finalImg = await compressIfNeeded(img, 1000000) - setNewUserBanner(finalImg) - setUserBanner(finalImg.path) - } catch (e: any) { - setImageError(cleanError(e)) - } - }, - [setNewUserBanner, setUserBanner, setImageError], - ) - - const onPressSave = useCallback(async () => { - setImageError('') - try { - await updateMutation.mutateAsync({ - profile, - updates: { - displayName, - description, - }, - newUserAvatar, - newUserBanner, - }) - Toast.show(_(msg({message: 'Profile updated', context: 'toast'}))) - onUpdate?.() - closeModal() - } catch (e: any) { - logger.error('Failed to update user profile', {message: String(e)}) - } - }, [ - updateMutation, - profile, - onUpdate, - closeModal, - displayName, - description, - newUserAvatar, - newUserBanner, - setImageError, - _, - ]) - const verification = useSimpleVerificationState({ - profile, - }) - - return ( - <KeyboardAvoidingView style={s.flex1} behavior="height"> - <ScrollView style={[pal.view]} testID="editProfileModal"> - <Text style={[styles.title, pal.text]}> - <Trans>Edit my profile</Trans> - </Text> - <View style={styles.photos}> - <UserBanner - banner={userBanner} - onSelectNewBanner={onSelectNewBanner} - /> - <View style={[styles.avi, {borderColor: pal.colors.background}]}> - <EditableUserAvatar - size={80} - avatar={userAvatar} - onSelectNewAvatar={onSelectNewAvatar} - /> - </View> - </View> - {updateMutation.isError && ( - <View style={styles.errorContainer}> - <ErrorMessage message={cleanError(updateMutation.error)} /> - </View> - )} - {imageError !== '' && ( - <View style={styles.errorContainer}> - <ErrorMessage message={imageError} /> - </View> - )} - <View style={styles.form}> - <View> - <Text style={[styles.label, pal.text]}> - <Trans>Display Name</Trans> - </Text> - <TextInput - testID="editProfileDisplayNameInput" - style={[styles.textInput, pal.border, pal.text]} - placeholder={_(msg`e.g. Alice Roberts`)} - placeholderTextColor={colors.gray4} - value={displayName} - onChangeText={v => - setDisplayName(enforceLen(v, MAX_DISPLAY_NAME)) - } - accessible={true} - accessibilityLabel={_(msg`Display name`)} - accessibilityHint={_(msg`Edit your display name`)} - /> - - {verification.isVerified && - verification.role === 'default' && - displayName !== initialDisplayName && ( - <View style={{paddingTop: 8}}> - <Admonition type="error"> - <Trans> - You are verified. You will lose your verification status - if you change your display name.{' '} - <InlineLinkText - label={_(msg`Learn more`)} - to={urls.website.blog.initialVerificationAnnouncement}> - <Trans>Learn more.</Trans> - </InlineLinkText> - </Trans> - </Admonition> - </View> - )} - </View> - <View style={s.pb10}> - <Text style={[styles.label, pal.text]}> - <Trans>Description</Trans> - </Text> - <TextInput - testID="editProfileDescriptionInput" - style={[styles.textArea, pal.border, pal.text]} - placeholder={_(msg`e.g. Artist, dog-lover, and avid reader.`)} - placeholderTextColor={colors.gray4} - keyboardAppearance={theme.colorScheme} - multiline - value={description} - onChangeText={v => setDescription(enforceLen(v, MAX_DESCRIPTION))} - accessible={true} - accessibilityLabel={_(msg`Description`)} - accessibilityHint={_(msg`Edit your profile description`)} - /> - </View> - {updateMutation.isPending ? ( - <View style={[styles.btn, s.mt10, {backgroundColor: colors.gray2}]}> - <ActivityIndicator /> - </View> - ) : ( - <TouchableOpacity - testID="editProfileSaveBtn" - style={s.mt10} - onPress={onPressSave} - accessibilityRole="button" - accessibilityLabel={_(msg`Save`)} - accessibilityHint={_(msg`Saves any changes to your profile`)}> - <LinearGradient - colors={[gradients.blueLight.start, gradients.blueLight.end]} - start={{x: 0, y: 0}} - end={{x: 1, y: 1}} - style={[styles.btn]}> - <Text style={[s.white, s.bold]}> - <Trans>Save Changes</Trans> - </Text> - </LinearGradient> - </TouchableOpacity> - )} - {!updateMutation.isPending && ( - <AnimatedTouchableOpacity - exiting={!isWeb ? FadeOut : undefined} - testID="editProfileCancelBtn" - style={s.mt5} - onPress={onPressCancel} - accessibilityRole="button" - accessibilityLabel={_(msg`Cancel profile editing`)} - accessibilityHint="" - onAccessibilityEscape={onPressCancel}> - <View style={[styles.btn]}> - <Text style={[s.black, s.bold, pal.text]}> - <Trans>Cancel</Trans> - </Text> - </View> - </AnimatedTouchableOpacity> - )} - </View> - </ScrollView> - </KeyboardAvoidingView> - ) -} - -const styles = StyleSheet.create({ - title: { - textAlign: 'center', - fontWeight: '600', - fontSize: 24, - marginBottom: 18, - }, - label: { - fontWeight: '600', - paddingHorizontal: 4, - paddingBottom: 4, - marginTop: 20, - }, - form: { - paddingHorizontal: 14, - }, - textInput: { - borderWidth: 1, - borderRadius: 6, - paddingHorizontal: 14, - paddingVertical: 10, - fontSize: 16, - }, - textArea: { - borderWidth: 1, - borderRadius: 6, - paddingHorizontal: 12, - paddingTop: 10, - fontSize: 16, - height: 120, - textAlignVertical: 'top', - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: 32, - padding: 10, - marginBottom: 10, - }, - avi: { - position: 'absolute', - top: 80, - left: 24, - width: 84, - height: 84, - borderWidth: 2, - borderRadius: 42, - }, - photos: { - marginBottom: 36, - marginHorizontal: -14, - }, - errorContainer: {marginTop: 20}, -}) |