diff --git a/src/components/dialogs/EmailDialog/components/TokenField.tsx b/src/components/dialogs/EmailDialog/components/TokenField.tsx index e949a289a5..26a51e4853 100644 --- a/src/components/dialogs/EmailDialog/components/TokenField.tsx +++ b/src/components/dialogs/EmailDialog/components/TokenField.tsx @@ -8,7 +8,11 @@ import {Shield_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/Shiel export function normalizeCode(value: string) { const normalized = value.toUpperCase().replace(/[^A-Z2-7]/g, '') if (normalized.length <= 5) return normalized - return `${normalized.slice(0, 5)}-${normalized.slice(5, 10)}` + return `${normalized.slice(0, 5)}-${normalized.slice(5)}` +} + +export function isValidCode(value?: string) { + return Boolean(value && /^[A-Z2-7]{5}-[A-Z2-7]{5}$/.test(value)) } export function TokenField({ @@ -17,6 +21,7 @@ export function TokenField({ onSubmitEditing, }: Pick) { const {_} = useLingui() + const isInvalid = Boolean(value && value.length > 10 && !isValidCode(value)) const handleOnChangeText = (v: string) => { onChangeText?.(normalizeCode(v)) @@ -27,6 +32,7 @@ export function TokenField({ { + if (!isValidCode(token)) { + dispatch({ + type: 'setError', + error: _(msg`Please enter a valid code.`), + }) + return + } + dispatch({type: 'setTokenStatus', status: 'pending'}) try { @@ -211,7 +222,7 @@ export function Disable() { {}} + onSubmitEditing={handleManageEmail2FA} /> @@ -224,7 +235,9 @@ export function Disable() { variant="solid" color="primary" onPress={handleManageEmail2FA} - disabled={!token || state.tokenStatus === 'pending'}> + disabled={ + !token || token.length !== 11 || state.tokenStatus === 'pending' + }> Disable 2FA diff --git a/src/components/dialogs/EmailDialog/screens/Update.tsx b/src/components/dialogs/EmailDialog/screens/Update.tsx index 9e177671e3..be0af88076 100644 --- a/src/components/dialogs/EmailDialog/screens/Update.tsx +++ b/src/components/dialogs/EmailDialog/screens/Update.tsx @@ -12,7 +12,10 @@ import {atoms as a, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {ResendEmailText} from '#/components/dialogs/EmailDialog/components/ResendEmailText' -import {TokenField} from '#/components/dialogs/EmailDialog/components/TokenField' +import { + isValidCode, + TokenField, +} from '#/components/dialogs/EmailDialog/components/TokenField' import {useRequestEmailUpdate} from '#/components/dialogs/EmailDialog/data/useRequestEmailUpdate' import {useRequestEmailVerification} from '#/components/dialogs/EmailDialog/data/useRequestEmailVerification' import {useUpdateEmail} from '#/components/dialogs/EmailDialog/data/useUpdateEmail' @@ -126,6 +129,14 @@ export function Update(_props: ScreenProps) { } const handleUpdateEmail = async () => { + if (state.step === 'token' && !isValidCode(state.token)) { + dispatch({ + type: 'setError', + error: _(msg`Please enter a valid code.`), + }) + return + } + dispatch({ type: 'setMutationStatus', status: 'pending', @@ -202,7 +213,7 @@ export function Update(_props: ScreenProps) { - + Please enter your new email address. @@ -231,7 +242,8 @@ export function Update(_props: ScreenProps) { Security step required - + Please enter the security code we sent to your previous email address. @@ -292,7 +304,8 @@ export function Update(_props: ScreenProps) { onPress={handleUpdateEmail} disabled={ !state.email || - (state.step === 'token' && !state.token) || + (state.step === 'token' && + (!state.token || state.token.length !== 11)) || state.mutationStatus === 'pending' }> diff --git a/src/components/dialogs/EmailDialog/screens/Verify.tsx b/src/components/dialogs/EmailDialog/screens/Verify.tsx index 16c6dd1752..dabd0d2f24 100644 --- a/src/components/dialogs/EmailDialog/screens/Verify.tsx +++ b/src/components/dialogs/EmailDialog/screens/Verify.tsx @@ -11,7 +11,10 @@ import {atoms as a, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {ResendEmailText} from '#/components/dialogs/EmailDialog/components/ResendEmailText' -import {TokenField} from '#/components/dialogs/EmailDialog/components/TokenField' +import { + isValidCode, + TokenField, +} from '#/components/dialogs/EmailDialog/components/TokenField' import {useConfirmEmail} from '#/components/dialogs/EmailDialog/data/useConfirmEmail' import {useRequestEmailVerification} from '#/components/dialogs/EmailDialog/data/useRequestEmailVerification' import {useOnEmailVerified} from '#/components/dialogs/EmailDialog/events' @@ -136,6 +139,14 @@ export function Verify({config, showScreen}: ScreenProps) { } const handleConfirmEmail = async () => { + if (!isValidCode(state.token)) { + dispatch({ + type: 'setError', + error: _(msg`Please enter a valid code.`), + }) + return + } + dispatch({ type: 'setMutationStatus', status: 'pending', @@ -328,7 +339,7 @@ export function Verify({config, showScreen}: ScreenProps) { value: token, }) }} - onSubmitEditing={() => {}} + onSubmitEditing={handleConfirmEmail} /> {state.error && {state.error}} @@ -339,7 +350,11 @@ export function Verify({config, showScreen}: ScreenProps) { variant="solid" color="primary" onPress={handleConfirmEmail} - disabled={!state.token || state.mutationStatus === 'pending'}> + disabled={ + !state.token || + state.token.length !== 11 || + state.mutationStatus === 'pending' + }> Verify code