/** * Author : Ashm Walia * Purpose : Add a new screen to allow the user to enter first and last name */ import AsyncStorage from '@react-native-community/async-storage'; import {RouteProp} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; import React, {useRef, useState} from 'react'; import { Alert, KeyboardAvoidingView, Platform, StatusBar, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { ArrowButton, Background, LoadingIndicator, RegistrationWizard, TaggInput, TermsConditions, } from '../../components'; import {passwordRegex, REGISTER_ENDPOINT, usernameRegex} from '../../constants'; import { ERROR_DOUBLE_CHECK_CONNECTION, ERROR_REGISTRATION, ERROR_SOMETHING_WENT_WRONG_REFRESH, } from '../../constants/strings'; import {OnboardingStackParams} from '../../routes'; import {BackgroundGradientType} from '../../types'; type RegistrationScreenThreeRouteProp = RouteProp< OnboardingStackParams, 'RegistrationThree' >; type RegistrationScreenThreeNavigationProp = StackNavigationProp< OnboardingStackParams, 'RegistrationThree' >; interface RegistrationThreeProps { route: RegistrationScreenThreeRouteProp; navigation: RegistrationScreenThreeNavigationProp; } /** * Registration screen 3 for username, password, and terms and conditions * @param navigation react-navigation navigation object */ const RegistrationThree: React.FC = ({ route, navigation, }) => { // refs for changing focus const usernameRef = useRef(); const passwordRef = useRef(); const confirmRef = useRef(); const registrationName = route.params; const fname: string = registrationName!.firstName; const lname: string = registrationName!.lastName; const phone: string = registrationName!.phone; const email: string = registrationName!.email; /** * Handles focus change to the next input field. * @param field key for field to move focus onto */ const handleFocusChange = (field: string): void => { switch (field) { case 'username': const usernameField: any = usernameRef.current; usernameField.focus(); break; case 'password': const passwordField: any = passwordRef.current; passwordField.focus(); break; case 'confirm': const confirmField: any = confirmRef.current; confirmField.focus(); break; default: return; } }; // registration form state const [form, setForm] = useState({ phone: '', username: '', password: '', confirm: '', isValidPhone: false, isValidUsername: false, isValidPassword: false, passwordsMatch: false, tcAccepted: false, attemptedSubmit: false, }); /* * Handles changes to the username field value and verifies the input by updating state and running a validation function. */ const handleUsernameUpdate = (username: string) => { let isValidUsername: boolean = usernameRegex.test(username); setForm({ ...form, username, isValidUsername, }); }; /* * Handles changes to the password field value and verifies the input by updating state and running a validation function. */ const handlePasswordUpdate = (password: string) => { let isValidPassword: boolean = passwordRegex.test(password); let passwordsMatch: boolean = form.password === form.confirm; setForm({ ...form, password, isValidPassword, passwordsMatch, }); }; /* * Handles changes to the confirm password field value and verifies the input by updating state and running a validation function. */ const handleConfirmUpdate = (confirm: string) => { let passwordsMatch: boolean = form.password === confirm; setForm({ ...form, confirm, passwordsMatch, }); }; /** * Handles changes to the terms and conditions accepted boolean. * @param tcAccepted the boolean to set the terms and conditions value to */ const handleTcUpdate = (tcAccepted: boolean) => { setForm({ ...form, tcAccepted, }); }; /** * Handles a click on the "next" arrow button by sending an API request to the backend and displaying the appropriate response. */ const handleRegister = async () => { if (!form.attemptedSubmit) { setForm({ ...form, attemptedSubmit: true, }); } try { if (form.isValidUsername && form.isValidPassword && form.passwordsMatch) { if (form.tcAccepted) { let registerResponse = await fetch(REGISTER_ENDPOINT, { method: 'POST', body: JSON.stringify({ first_name: fname, last_name: lname, email: email, phone_number: phone, username: form.username, password: form.password, }), }); let statusCode = registerResponse.status; let data = await registerResponse.json(); const userId: string = data.UserID; if (statusCode === 201) { try { await AsyncStorage.setItem('token', data.token); /* * Skipping navigation to Checkpoint for alpha * navigation.navigate('Checkpoint', { userId: userId, username: form.username }); */ navigation.navigate('ProfileOnboarding', { userId: userId, username: form.username, }); } catch (err) { console.log(err); } } else if (statusCode === 409) { Alert.alert(ERROR_REGISTRATION(data)); } else { Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH); } } else { Alert.alert( 'Terms and conditions', 'You must first agree to the terms and conditions.', ); } } else { setForm({...form, attemptedSubmit: false}); setTimeout(() => setForm({...form, attemptedSubmit: true})); } } catch (error) { Alert.alert(ERROR_REGISTRATION(ERROR_DOUBLE_CHECK_CONNECTION)); return { name: 'Registration error', description: error, }; } }; const Footer = () => ( navigation.navigate('RegistrationTwo', {phone: phone})} /> ); return ( SIGN UP handleFocusChange('password')} blurOnSubmit={false} ref={usernameRef} valid={form.isValidUsername} invalidWarning={ 'Username must beĀ at least 6 characters and contain only alphanumerics.' } attemptedSubmit={form.attemptedSubmit} width={280} /> handleFocusChange('confirm')} 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} />