diff options
Diffstat (limited to 'src/screens/onboarding/RegistrationOne.tsx')
-rw-r--r-- | src/screens/onboarding/RegistrationOne.tsx | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/screens/onboarding/RegistrationOne.tsx b/src/screens/onboarding/RegistrationOne.tsx new file mode 100644 index 00000000..3b9ddb3e --- /dev/null +++ b/src/screens/onboarding/RegistrationOne.tsx @@ -0,0 +1,268 @@ +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, +} from 'react-native'; + +import {RootStackParamList} from '../../routes'; +import { + ArrowButton, + RegistrationWizard, + TaggInput, + Background, +} from '../../components'; +import {nameRegex, emailRegex} from '../../constants'; + +type RegistrationScreenOneRouteProp = RouteProp< + RootStackParamList, + 'RegistrationOne' +>; +type RegistrationScreenOneNavigationProp = StackNavigationProp< + RootStackParamList, + 'RegistrationOne' +>; +interface RegistrationOneProps { + route: RegistrationScreenOneRouteProp; + navigation: RegistrationScreenOneNavigationProp; +} +/** + * Registration screen 1 for First Name, Last Name, and email + * @param navigation react-navigation navigation object + */ +const RegistrationOne: React.FC<RegistrationOneProps> = ({navigation}) => { + // refs for changing focus + const lnameRef = useRef(); + const emailRef = useRef(); + /** + * 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 'lname': + const lnameField: any = lnameRef.current; + lnameField.focus(); + break; + case 'email': + const emailField: any = emailRef.current; + emailField.focus(); + break; + default: + return; + } + }; + + // registration form state + const [form, setForm] = useState({ + fname: '', + lname: '', + email: '', + isValidFname: false, + isValidLname: false, + isValidEmail: false, + attemptedSubmit: false, + }); + + /* + * Handles changes to the first name field value and verifies the input by updating state and running a validation function. + */ + const handleFnameUpdate = (fname: string) => { + let isValidFname: boolean = nameRegex.test(fname); + setForm({ + ...form, + fname, + isValidFname, + }); + }; + /* + * Handles changes to the last name field value and verifies the input by updating state and running a validation function. + */ + const handleLnameUpdate = (lname: string) => { + let isValidLname: boolean = nameRegex.test(lname); + setForm({ + ...form, + lname, + isValidLname, + }); + }; + + /* + * Handles changes to the email field value and verifies the input by updating state and running a validation function. + */ + const handleEmailUpdate = (email: string) => { + let isValidEmail: boolean = emailRegex.test(email); + setForm({ + ...form, + email, + isValidEmail, + }); + }; + + /** + * Handles a click on the "next" arrow button by navigating to RegistrationTwo if First Name and Last Name are filled + */ + const goToRegisterTwo = async () => { + if (!form.attemptedSubmit) { + setForm({ + ...form, + attemptedSubmit: true, + }); + } + try { + if (form.isValidFname && form.isValidLname && form.isValidEmail) { + navigation.navigate('RegistrationTwo', { + firstName: form.fname, + lastName: form.lname, + email: form.email, + }); + } 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: 'Registration error', + description: error, + }; + } + }; + + const Footer = () => ( + <View style={styles.footer}> + <ArrowButton + direction="backward" + onPress={() => navigation.navigate('Login')} + /> + <TouchableOpacity onPress={goToRegisterTwo}> + <ArrowButton + direction="forward" + disabled={ + !(form.isValidFname && form.isValidLname && form.isValidEmail) + } + onPress={() => + navigation.navigate('RegistrationTwo', { + firstName: form.fname, + lastName: form.lname, + email: form.email, + }) + } + /> + </TouchableOpacity> + </View> + ); + + return ( + <Background style={styles.container}> + <StatusBar barStyle="light-content" /> + <RegistrationWizard style={styles.wizard} step="one" /> + <KeyboardAvoidingView + behavior={Platform.OS === 'ios' ? 'padding' : 'height'} + style={styles.container}> + <View> + <Text style={styles.formHeader}>SIGN UP</Text> + </View> + <TaggInput + accessibilityHint="Enter your first name." + accessibilityLabel="First name input field." + placeholder="First Name" + autoCompleteType="name" + textContentType="name" + returnKeyType="next" + onChangeText={handleFnameUpdate} + onSubmitEditing={() => handleFocusChange('lname')} + blurOnSubmit={false} + valid={form.isValidFname} + invalidWarning="Please enter a valid first name." + attemptedSubmit={form.attemptedSubmit} + width={280} + /> + <TaggInput + accessibilityHint="Enter your last name." + accessibilityLabel="Last name input field." + placeholder="Last Name" + autoCompleteType="name" + textContentType="name" + returnKeyType="next" + onChangeText={handleLnameUpdate} + onSubmitEditing={() => handleFocusChange('email')} + blurOnSubmit={false} + ref={lnameRef} + valid={form.isValidLname} + invalidWarning="Please enter a valid last name." + attemptedSubmit={form.attemptedSubmit} + width={280} + /> + <TaggInput + accessibilityHint="Enter your email." + accessibilityLabel="Email input field." + placeholder="Email" + autoCompleteType="email" + textContentType="emailAddress" + autoCapitalize="none" + returnKeyType="next" + keyboardType="email-address" + onChangeText={handleEmailUpdate} + blurOnSubmit={false} + ref={emailRef} + valid={form.isValidEmail} + invalidWarning={'Please enter a valid email address.'} + attemptedSubmit={form.attemptedSubmit} + width={280} + onSubmitEditing={goToRegisterTwo} + /> + </KeyboardAvoidingView> + <Footer /> + </Background> + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + wizard: { + ...Platform.select({ + ios: { + top: 50, + }, + android: { + bottom: 40, + }, + }), + }, + formHeader: { + color: '#fff', + fontSize: 30, + fontWeight: '600', + marginBottom: '16%', + }, + footer: { + width: '100%', + flexDirection: 'row', + justifyContent: 'space-around', + ...Platform.select({ + ios: { + bottom: '20%', + }, + android: { + bottom: '10%', + }, + }), + }, +}); + +export default RegistrationOne; |