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, TouchableOpacity, KeyboardAvoidingView, ActivityIndicator, } from 'react-native'; import {usePromiseTracker, trackPromise} from 'react-promise-tracker'; import {OnboardingStackParams} from '../../routes'; import { ArrowButton, RegistrationWizard, TaggInput, TermsConditions, Background, } from '../../components'; import { passwordRegex, usernameRegex, REGISTER_ENDPOINT, SEND_OTP_ENDPOINT, } from '../../constants'; type RegistrationScreenTwoRouteProp = RouteProp< OnboardingStackParams, 'RegistrationTwo' >; type RegistrationScreenTwoNavigationProp = StackNavigationProp< OnboardingStackParams, 'RegistrationTwo' >; interface RegistrationTwoProps { route: RegistrationScreenTwoRouteProp; navigation: RegistrationScreenTwoNavigationProp; } /** * Registration screen 2 for email, username, password, and terms and conditions * @param navigation react-navigation navigation object */ const RegistrationTwo: 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 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({ email: '', username: '', password: '', confirm: '', isValidEmail: 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, username: form.username, password: form.password, }), }); let statusCode = registerResponse.status; let data = await registerResponse.json(); if (statusCode === 201) { let sendOtpResponse = await trackPromise( fetch(SEND_OTP_ENDPOINT, { method: 'POST', body: JSON.stringify({ username: form.username, email: email, }), }), ); let otpStatusCode = sendOtpResponse.status; if (otpStatusCode === 200) { const userId: string = data.UserID; navigation.navigate('Verification', { username: form.username, email: email, userId: userId, }); } } else if (statusCode === 409) { Alert.alert('Registration failed ๐Ÿ˜”', `${data}`); } else { Alert.alert( 'Something went wrong! ๐Ÿ˜ญ', "Would you believe me if I told you that I don't know what happened?", ); } } 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( 'Registration failed ๐Ÿ˜“', 'Please double-check your network connection and retry.', ); return { name: 'Registration error', description: error, }; } }; const Footer = () => ( navigation.navigate('RegistrationOne')} /> ); /** * An activity indicator to indicate that the app is working during the send_otp request. */ const LoadingIndicator = () => { const {promiseInProgress} = usePromiseTracker(); return promiseInProgress ? ( ) : ( <> ); }; 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} />