import AsyncStorage from '@react-native-community/async-storage'; import {useNavigation} from '@react-navigation/core'; import {RouteProp} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; import React, {useEffect, useState} from 'react'; import { Alert, KeyboardAvoidingView, Platform, StatusBar, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import {normalize} from 'react-native-elements'; import Animated, {Easing} from 'react-native-reanimated'; import { ArrowButton, Background, LoadingIndicator, TaggInput, TaggSquareButton, TermsConditions, } from '../../components'; import { emailRegex, nameRegex, passwordRegex, phoneRegex, usernameRegex, } from '../../constants'; import { ERROR_NEXT_PAGE, ERROR_PHONE_IN_USE, ERROR_REGISTRATION, ERROR_SOMETHING_WENT_WRONG_REFRESH, ERROR_TWILIO_SERVER_ERROR, ERROR_T_AND_C_NOT_ACCEPTED, } from '../../constants/strings'; import {OnboardingStackParams} from '../../routes'; import {sendOtpStatusCode, sendRegister} from '../../services'; import {BackgroundGradientType} from '../../types'; import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; type BasicInfoOnboardingRouteProp = RouteProp< OnboardingStackParams, 'BasicInfoOnboarding' >; type BasicInfoOnboardingNavigationProp = StackNavigationProp< OnboardingStackParams, 'BasicInfoOnboarding' >; interface BasicInfoOnboardingProps { route: BasicInfoOnboardingRouteProp; navigation: BasicInfoOnboardingNavigationProp; } const BasicInfoOnboarding: React.FC = ({route}) => { const {isPhoneVerified} = route.params; const navigation = useNavigation(); const [attemptedSubmit, setAttemptedSubmit] = useState(false); const [valid, setValid] = useState(false); const [currentStep, setCurrentStep] = useState(0); const [tcAccepted, setTCAccepted] = useState(false); const [passVisibility, setPassVisibility] = useState(false); const [autoCapitalize, setAutoCap] = useState('None'); const [fadeValue, setFadeValue] = useState>( new Animated.Value(0), ); const [form, setForm] = useState({ fname: '', lname: '', username: '', phone: '', email: '', password: '', }); const fadeComponentIn = async () => { Animated.timing(fadeValue, { toValue: 1, duration: 1000, easing: Easing.linear, }).start(); }; useEffect(() => { fadeComponentIn(); }, [fadeValue]); const goNext = async () => { if (!attemptedSubmit) { setAttemptedSubmit(true); } try { if (valid) { const {phone} = form; const code = await sendOtpStatusCode(phone); if (code) { switch (code) { case 200: const {fname, lname} = form; navigation.navigate('PhoneVerification', { firstName: fname, lastName: lname, phone, }); break; case 409: Alert.alert(ERROR_PHONE_IN_USE); break; default: Alert.alert(ERROR_TWILIO_SERVER_ERROR); } } else { setAttemptedSubmit(false); setTimeout(() => { setAttemptedSubmit(true); }); } } } catch (error) { Alert.alert(ERROR_NEXT_PAGE); return { name: 'Navigation error', description: error, }; } }; // 0 = first name, 1 = last name, 2 = username, 3 = phone # const handleNameUpdate = (name: string, nameType: number) => { name = name.trim(); let isValidName: boolean = nameRegex.test(name); switch (nameType) { case 0: setForm({ ...form, fname: name, }); setAutoCap('words'); setValid(isValidName); break; case 1: setForm({ ...form, lname: name, }); setAutoCap('words'); setValid(isValidName); break; case 2: setForm({ ...form, username: name, }); setValid(usernameRegex.test(name)); setAutoCap('None'); break; } }; const handlePhoneUpdate = (phone: string) => { phone = phone.trim(); setForm({ ...form, phone, }); setAutoCap('None'); setValid(phoneRegex.test(phone)); }; const handleEmailUpdate = (email: string) => { email = email.trim(); setForm({ ...form, email, }); setAutoCap('None'); setValid(emailRegex.test(email)); }; const handlePasswordUpdate = (password: string) => { setForm({ ...form, password, }); setAutoCap('None'); setValid(passwordRegex.test(password)); }; const formSteps: { placeholder: string; onChangeText: (text: string) => void; }[] = [ { placeholder: 'First Name', onChangeText: (text) => handleNameUpdate(text, 0), }, { placeholder: 'Last Name', onChangeText: (text) => handleNameUpdate(text, 1), }, { placeholder: 'Phone', onChangeText: handlePhoneUpdate, }, { placeholder: 'School Email', onChangeText: handleEmailUpdate, }, { placeholder: 'Username', onChangeText: (text) => handleNameUpdate(text, 2), }, { placeholder: 'Password', onChangeText: handlePasswordUpdate, }, ]; const resetForm = (formStep: String) => { setValid(false); switch (formStep) { case 'First Name': setForm({ ...form, fname: '', }); break; case 'Last Name': setForm({ ...form, lname: '', }); break; case 'Email': setForm({ ...form, email: '', }); break; case 'Password': setForm({ ...form, password: '', }); break; case 'School Email': setForm({ ...form, email: '', }); break; case 'Username': setForm({ ...form, username: '', }); break; } }; const step = formSteps[currentStep]; const advance = () => { setAttemptedSubmit(true); if (valid) { setCurrentStep(currentStep + 1); setAttemptedSubmit(false); setValid(false); setFadeValue(new Animated.Value(0)); } }; const advanceRegistration = async () => { setAttemptedSubmit(true); if (!valid) { return; } if (!tcAccepted) { Alert.alert('Terms and conditions', ERROR_T_AND_C_NOT_ACCEPTED); return; } const {fname, lname, phone, email, username, password} = form; const response = await sendRegister( fname, lname, phone, email, username, password, ); if (response) { const data = await response.json(); const {token, UserID} = data; switch (response.status) { case 201: await AsyncStorage.setItem('token', token); navigation.navigate('ProfileInfoOnboarding', { userId: UserID, username: username, }); break; case 400: Alert.alert(ERROR_REGISTRATION(data.toLowerCase())); break; default: Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH); break; } } else { Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH); } }; useEffect(() => { if (isPhoneVerified) { advance(); } }, [isPhoneVerified]); return ( {/* getting rid of registration progress in onboarding*/} {/* */} {currentStep !== 0 && currentStep !== 3 && ( { // if I go back do I want to reset the previous form? setCurrentStep(currentStep - 1); resetForm(step.placeholder); setAttemptedSubmit(false); }} /> )} {step.placeholder === 'Phone' && !isPhoneVerified ? ( ) : ( <> {step.placeholder !== 'Password' ? ( <> SIGN UP ) : ( setPassVisibility(!passVisibility)}> Show Password )} )} ); }; const styles = StyleSheet.create({ container: { height: SCREEN_HEIGHT, width: SCREEN_WIDTH, alignItems: 'center', justifyContent: 'center', }, arrow: { color: '#6EE7E7', }, showPass: { color: 'white', marginVertical: '1%', borderBottomWidth: 1, paddingBottom: '1%', left: '-18%', borderBottomColor: 'white', marginBottom: '8%', }, passWarning: { fontSize: 14, marginTop: 5, color: '#FF8989', maxWidth: 350, alignSelf: 'flex-start', }, input: { minWidth: '60%', height: 40, fontSize: 16, fontWeight: '600', color: '#fff', borderBottomWidth: 1, borderBottomColor: '#fff', }, errorInput: { minWidth: '60%', height: 40, fontSize: 16, fontWeight: '600', color: '#FF8989', borderBottomWidth: 1, borderBottomColor: '#fff', }, button: { alignItems: 'center', width: 40, aspectRatio: 10, }, formHeader: { color: '#fff', fontSize: 30, fontWeight: '600', position: 'absolute', top: '20%', }, load: { top: '5%', }, tc: { marginVertical: '5%', }, footer: { height: normalize(50), width: normalize(50), flexDirection: 'row', justifyContent: 'space-around', ...Platform.select({ ios: { bottom: '20%', }, android: { bottom: '10%', }, }), }, }); export default BasicInfoOnboarding;