diff options
-rw-r--r-- | src/screens/Signup/StepInfo/index.tsx | 65 | ||||
-rw-r--r-- | src/screens/Signup/state.ts | 20 | ||||
-rw-r--r-- | src/view/com/modals/ChangePassword.tsx | 17 |
3 files changed, 79 insertions, 23 deletions
diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx index 18ba38528..a19a3ad4a 100644 --- a/src/screens/Signup/StepInfo/index.tsx +++ b/src/screens/Signup/StepInfo/index.tsx @@ -75,22 +75,6 @@ export function StepInfo({ const emailChanged = prevEmailValueRef.current !== email const password = passwordValueRef.current - if (emailChanged && tldtsRef.current) { - if (isEmailMaybeInvalid(email, tldtsRef.current)) { - prevEmailValueRef.current = email - setHasWarnedEmail(true) - return dispatch({ - type: 'setError', - value: _( - msg`It looks like you may have entered your email address incorrectly. Are you sure it's right?`, - ), - }) - } - } else if (hasWarnedEmail) { - setHasWarnedEmail(false) - } - prevEmailValueRef.current = email - if (!is13(state.dateOfBirth)) { return } @@ -99,24 +83,50 @@ export function StepInfo({ return dispatch({ type: 'setError', value: _(msg`Please enter your invite code.`), + field: 'invite-code', }) } if (!email) { return dispatch({ type: 'setError', value: _(msg`Please enter your email.`), + field: 'email', }) } if (!EmailValidator.validate(email)) { return dispatch({ type: 'setError', value: _(msg`Your email appears to be invalid.`), + field: 'email', }) } + if (emailChanged && tldtsRef.current) { + if (isEmailMaybeInvalid(email, tldtsRef.current)) { + prevEmailValueRef.current = email + setHasWarnedEmail(true) + return dispatch({ + type: 'setError', + value: _( + msg`Please double-check that you have entered your email address correctly.`, + ), + }) + } + } else if (hasWarnedEmail) { + setHasWarnedEmail(false) + } + prevEmailValueRef.current = email if (!password) { return dispatch({ type: 'setError', value: _(msg`Please choose your password.`), + field: 'password', + }) + } + if (password.length < 8) { + return dispatch({ + type: 'setError', + value: _(msg`Your password must be at least 8 characters long.`), + field: 'password', }) } @@ -149,11 +159,17 @@ export function StepInfo({ <TextField.LabelText> <Trans>Invite code</Trans> </TextField.LabelText> - <TextField.Root> + <TextField.Root isInvalid={state.errorField === 'invite-code'}> <TextField.Icon icon={Ticket} /> <TextField.Input onChangeText={value => { inviteCodeValueRef.current = value.trim() + if ( + state.errorField === 'invite-code' && + value.trim().length > 0 + ) { + dispatch({type: 'clearError'}) + } }} label={_(msg`Required for this provider`)} defaultValue={state.inviteCode} @@ -173,7 +189,7 @@ export function StepInfo({ <TextField.LabelText> <Trans>Email</Trans> </TextField.LabelText> - <TextField.Root> + <TextField.Root isInvalid={state.errorField === 'email'}> <TextField.Icon icon={Envelope} /> <TextField.Input testID="emailInput" @@ -183,6 +199,13 @@ export function StepInfo({ if (hasWarnedEmail) { setHasWarnedEmail(false) } + if ( + state.errorField === 'email' && + value.trim().length > 0 && + EmailValidator.validate(value.trim()) + ) { + dispatch({type: 'clearError'}) + } }} label={_(msg`Enter your email address`)} defaultValue={state.email} @@ -201,13 +224,16 @@ export function StepInfo({ <TextField.LabelText> <Trans>Password</Trans> </TextField.LabelText> - <TextField.Root> + <TextField.Root isInvalid={state.errorField === 'password'}> <TextField.Icon icon={Lock} /> <TextField.Input testID="passwordInput" inputRef={passwordInputRef} onChangeText={value => { passwordValueRef.current = value + if (state.errorField === 'password' && value.length >= 8) { + dispatch({type: 'clearError'}) + } }} label={_(msg`Choose your password`)} defaultValue={state.password} @@ -219,6 +245,7 @@ export function StepInfo({ onSubmitEditing={native(() => birthdateInputRef.current?.focus(), )} + passwordRules="minlength: 8;" /> </TextField.Root> </View> diff --git a/src/screens/Signup/state.ts b/src/screens/Signup/state.ts index 4addf3580..3daf36a9b 100644 --- a/src/screens/Signup/state.ts +++ b/src/screens/Signup/state.ts @@ -31,6 +31,13 @@ type SubmitTask = { mutableProcessed: boolean // OK to mutate assuming it's never read in render. } +type ErrorField = + | 'invite-code' + | 'email' + | 'handle' + | 'password' + | 'date-of-birth' + export type SignupState = { hasPrev: boolean activeStep: SignupStep @@ -45,6 +52,7 @@ export type SignupState = { handle: string error: string + errorField?: ErrorField isLoading: boolean pendingSubmit: null | SubmitTask @@ -62,7 +70,8 @@ export type SignupAction = | {type: 'setDateOfBirth'; value: Date} | {type: 'setInviteCode'; value: string} | {type: 'setHandle'; value: string} - | {type: 'setError'; value: string} + | {type: 'setError'; value: string; field?: ErrorField} + | {type: 'clearError'} | {type: 'setIsLoading'; value: boolean} | {type: 'submit'; task: SubmitTask} @@ -80,6 +89,7 @@ export const initialState: SignupState = { inviteCode: '', error: '', + errorField: undefined, isLoading: false, pendingSubmit: null, @@ -102,6 +112,7 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) next.activeStep-- next.error = '' + next.errorField = undefined } break } @@ -110,6 +121,7 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) next.activeStep++ next.error = '' + next.errorField = undefined } break } @@ -156,6 +168,12 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { } case 'setError': { next.error = a.value + next.errorField = a.field + break + } + case 'clearError': { + next.error = '' + next.errorField = undefined break } case 'submit': { diff --git a/src/view/com/modals/ChangePassword.tsx b/src/view/com/modals/ChangePassword.tsx index d68b4e453..9b96e7db0 100644 --- a/src/view/com/modals/ChangePassword.tsx +++ b/src/view/com/modals/ChangePassword.tsx @@ -81,8 +81,7 @@ export function Component() { const onChangePassword = async () => { const formattedCode = checkAndFormatResetCode(resetCode) - // TODO Better password strength check - if (!formattedCode || !newPassword) { + if (!formattedCode) { setError( _( msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`, @@ -90,6 +89,16 @@ export function Component() { ) return } + if (!newPassword) { + setError( + _(msg`Please enter a password. It must be at least 8 characters long.`), + ) + return + } + if (newPassword.length < 8) { + setError(_(msg`Password must be at least 8 characters long.`)) + return + } setError('') setIsProcessing(true) @@ -104,7 +113,9 @@ export function Component() { logger.warn('Failed to set new password', {error: e}) if (isNetworkError(e)) { setError( - 'Unable to contact your service. Please check your Internet connection.', + _( + msg`Unable to contact your service. Please check your Internet connection.`, + ), ) } else { setError(cleanError(errMsg)) |