From db575615046544e83759a3615f37540305aa9742 Mon Sep 17 00:00:00 2001 From: Ashm Walia <40498934+ashmgarv@users.noreply.github.com> Date: Tue, 8 Dec 2020 20:19:32 -0800 Subject: [TMA-308] Forgot password logic [Frontend] (#131) * Done with changes * Submit on enter * Fixed StrongPassword issue * Clean and modular Verification.tsx * small fix --- src/screens/onboarding/Login.tsx | 13 +- src/screens/onboarding/PasswordReset.tsx | 246 ++++++++++++++++++++++++ src/screens/onboarding/PasswordResetRequest.tsx | 198 +++++++++++++++++++ src/screens/onboarding/RegistrationOne.tsx | 4 +- src/screens/onboarding/RegistrationThree.tsx | 4 +- src/screens/onboarding/Verification.tsx | 133 ++++++++----- src/screens/onboarding/index.ts | 2 + 7 files changed, 537 insertions(+), 63 deletions(-) create mode 100644 src/screens/onboarding/PasswordReset.tsx create mode 100644 src/screens/onboarding/PasswordResetRequest.tsx (limited to 'src/screens') diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx index 2738d6ca..cb550ef8 100644 --- a/src/screens/onboarding/Login.tsx +++ b/src/screens/onboarding/Login.tsx @@ -127,10 +127,10 @@ const Login: React.FC = ({navigation}: LoginProps) => { }; /** - * Handler for the Let's Start button or the Go button on the keyboard. - Makes a POST request to the Django login API and presents Alerts based on the status codes that the backend returns. - * Stores token received in the response, into client's AsynStorage - */ + * Handler for the Let's Start button or the Go button on the keyboard. + Makes a POST request to the Django login API and presents Alerts based on the status codes that the backend returns. + * Stores token received in the response, into client's AsynStorage + */ const handleLogin = async () => { if (!form.attemptedSubmit) { setForm({ @@ -207,7 +207,7 @@ const Login: React.FC = ({navigation}: LoginProps) => { accessibilityLabel="Forgot password button" accessibilityHint="Select this if you forgot your tagg password" style={styles.forgotPassword} - onPress={() => Alert.alert("tagg! You're it!")}> + onPress={() => navigation.navigate('PasswordResetRequest')}> Forgot password ); @@ -293,8 +293,7 @@ const Login: React.FC = ({navigation}: LoginProps) => { attemptedSubmit={form.attemptedSubmit} ref={inputRef} /> - {/* Commenting this line because the Forgot Password has not been implemented for Alpha */} - {/* */} + diff --git a/src/screens/onboarding/PasswordReset.tsx b/src/screens/onboarding/PasswordReset.tsx new file mode 100644 index 00000000..25991d6e --- /dev/null +++ b/src/screens/onboarding/PasswordReset.tsx @@ -0,0 +1,246 @@ +import React, {useState, useRef} from 'react'; +import {RouteProp} from '@react-navigation/native'; +import {StackNavigationProp} from '@react-navigation/stack'; +import { + View, + Text, + StyleSheet, + StatusBar, + Alert, + Platform, + KeyboardAvoidingView, +} from 'react-native'; + +import {OnboardingStackParams} from '../../routes'; + +import { + ArrowButton, + TaggInput, + Background, + LoadingIndicator, + SubmitButton, +} from '../../components'; + +import {trackPromise} from 'react-promise-tracker'; +import {passwordRegex} from '../../constants'; +import {handlePasswordReset} from '../../services'; + +type PasswordResetRequestRouteProp = RouteProp< + OnboardingStackParams, + 'PasswordReset' +>; +type PasswordResetRequestNavigationProp = StackNavigationProp< + OnboardingStackParams, + 'PasswordReset' +>; +interface PasswordResetRequestProps { + route: PasswordResetRequestRouteProp; + navigation: PasswordResetRequestNavigationProp; +} +/** + * Password reset page + * @param navigation react-navigation navigation object + */ +const PasswordResetRequest: React.FC = ({ + route, + navigation, +}) => { + const passwordRef = useRef(); + const confirmRef = useRef(); + const {value} = route.params; + + /** + * Handles focus change to the next input field. + * @param field key for field to move focus onto + */ + const handleFocusChange = (): void => { + const confirmField: any = confirmRef.current; + confirmField.focus(); + }; + + const [form, setForm] = useState({ + password: '', + confirm: '', + isValidPassword: false, + passwordsMatch: false, + attemptedSubmit: false, + }); + + const handlePasswordUpdate = (password: string) => { + let isValidPassword: boolean = passwordRegex.test(password); + let passwordsMatch: boolean = form.password === form.confirm; + setForm({ + ...form, + password, + isValidPassword, + passwordsMatch, + }); + }; + + const handleConfirmUpdate = (confirm: string) => { + let passwordsMatch: boolean = form.password === confirm; + setForm({ + ...form, + confirm, + passwordsMatch, + }); + }; + + const handleSubmit = async () => { + if (!form.attemptedSubmit) { + setForm({ + ...form, + attemptedSubmit: true, + }); + } + try { + if (form.isValidPassword && form.passwordsMatch) { + const success = await trackPromise( + handlePasswordReset(value, form.password), + ); + if (success) { + navigation.navigate('Login'); + } + } else { + setForm({...form, attemptedSubmit: false}); + setTimeout(() => setForm({...form, attemptedSubmit: true})); + } + } catch (error) { + Alert.alert( + 'Looks like our servers are down. 😓', + "Try again in a couple minutes. We're sorry for the inconvenience.", + ); + return { + name: 'Verify Password error', + description: error, + }; + } + }; + + /** + * Reset Password Button. + */ + const ResetPasswordButton = () => ( + + ); + + const Footer = () => ( + + navigation.navigate('Login')} + /> + + ); + + return ( + + + + + Enter your new password + + handleFocusChange} + blurOnSubmit={false} + secureTextEntry + ref={passwordRef} + valid={form.isValidPassword} + invalidWarning={ + 'Password must be at least 8 characters & contain at least one of a-z, A-Z, 0-9, and a special character.' + } + attemptedSubmit={form.attemptedSubmit} + width={280} + /> + + + + +