Handle token field validation
This commit is contained in:
@@ -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<TextInputProps, 'value' | 'onChangeText' | 'onSubmitEditing'>) {
|
||||
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({
|
||||
<TextField.Root>
|
||||
<TextField.Icon icon={Shield} />
|
||||
<TextField.Input
|
||||
isInvalid={isInvalid}
|
||||
label={_(msg`Confirmation code`)}
|
||||
placeholder="XXXXX-XXXXX"
|
||||
value={value}
|
||||
|
||||
@@ -12,7 +12,10 @@ import {Admonition} from '#/components/Admonition'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {useDialogContext} from '#/components/Dialog'
|
||||
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 {useManageEmail2FA} from '#/components/dialogs/EmailDialog/data/useManageEmail2FA'
|
||||
import {useRequestEmailUpdate} from '#/components/dialogs/EmailDialog/data/useRequestEmailUpdate'
|
||||
import {Divider} from '#/components/Divider'
|
||||
@@ -122,6 +125,14 @@ export function Disable() {
|
||||
}
|
||||
|
||||
const handleManageEmail2FA = async () => {
|
||||
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() {
|
||||
<TokenField
|
||||
value={token}
|
||||
onChangeText={setToken}
|
||||
onSubmitEditing={() => {}}
|
||||
onSubmitEditing={handleManageEmail2FA}
|
||||
/>
|
||||
<ResendEmailText onPress={handleSendEmail} />
|
||||
</View>
|
||||
@@ -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'
|
||||
}>
|
||||
<ButtonText>
|
||||
<Trans>Disable 2FA</Trans>
|
||||
</ButtonText>
|
||||
|
||||
@@ -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<ScreenID.Update>) {
|
||||
}
|
||||
|
||||
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<ScreenID.Update>) {
|
||||
|
||||
<View style={[a.gap_md]}>
|
||||
<View>
|
||||
<Text style={[a.pb_sm, t.atoms.text_contrast_medium]}>
|
||||
<Text style={[a.pb_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||
<Trans>Please enter your new email address.</Trans>
|
||||
</Text>
|
||||
<TextField.Root>
|
||||
@@ -231,7 +242,8 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
|
||||
<Text style={[a.text_md, a.pb_sm, a.font_bold]}>
|
||||
<Trans>Security step required</Trans>
|
||||
</Text>
|
||||
<Text style={[a.pb_sm, t.atoms.text_contrast_medium]}>
|
||||
<Text
|
||||
style={[a.pb_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||
<Trans>
|
||||
Please enter the security code we sent to your previous email
|
||||
address.
|
||||
@@ -292,7 +304,8 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
|
||||
onPress={handleUpdateEmail}
|
||||
disabled={
|
||||
!state.email ||
|
||||
(state.step === 'token' && !state.token) ||
|
||||
(state.step === 'token' &&
|
||||
(!state.token || state.token.length !== 11)) ||
|
||||
state.mutationStatus === 'pending'
|
||||
}>
|
||||
<ButtonText>
|
||||
|
||||
@@ -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<ScreenID.Verify>) {
|
||||
}
|
||||
|
||||
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<ScreenID.Verify>) {
|
||||
value: token,
|
||||
})
|
||||
}}
|
||||
onSubmitEditing={() => {}}
|
||||
onSubmitEditing={handleConfirmEmail}
|
||||
/>
|
||||
|
||||
{state.error && <Admonition type="error">{state.error}</Admonition>}
|
||||
@@ -339,7 +350,11 @@ export function Verify({config, showScreen}: ScreenProps<ScreenID.Verify>) {
|
||||
variant="solid"
|
||||
color="primary"
|
||||
onPress={handleConfirmEmail}
|
||||
disabled={!state.token || state.mutationStatus === 'pending'}>
|
||||
disabled={
|
||||
!state.token ||
|
||||
state.token.length !== 11 ||
|
||||
state.mutationStatus === 'pending'
|
||||
}>
|
||||
<ButtonText>
|
||||
<Trans>Verify code</Trans>
|
||||
</ButtonText>
|
||||
|
||||
Reference in New Issue
Block a user