diff options
Diffstat (limited to 'src')
15 files changed, 699 insertions, 95 deletions
diff --git a/src/assets/images/onboarding-backarrow.png b/src/assets/images/onboarding-backarrow.png Binary files differnew file mode 100644 index 00000000..9aaa66cb --- /dev/null +++ b/src/assets/images/onboarding-backarrow.png diff --git a/src/components/onboarding/ArrowButton.tsx b/src/components/onboarding/ArrowButton.tsx index bf07c6ac..67fd0f62 100644 --- a/src/components/onboarding/ArrowButton.tsx +++ b/src/components/onboarding/ArrowButton.tsx @@ -1,23 +1,51 @@ import React from 'react'; -import {Image, TouchableOpacity, TouchableOpacityProps} from 'react-native'; +import { + Image, + StyleSheet, + TouchableOpacity, + TouchableOpacityProps, +} from 'react-native'; +import {normalize} from '../../utils'; interface ArrowButtonProps extends TouchableOpacityProps { direction: 'forward' | 'backward'; disabled?: boolean; + onboarding?: boolean; } -const ArrowButton: React.FC<ArrowButtonProps> = (props: ArrowButtonProps) => { - const arrow = - props.direction === 'forward' - ? props.disabled - ? require('../../assets/images/arrow-forward-disabled.png') - : require('../../assets/images/arrow-forward-enabled.png') - : require('../../assets/images/arrow-backward.png'); +const ArrowButton: React.FC<ArrowButtonProps> = (props) => { + const {direction, disabled, onboarding} = props; + let uri; + + if (direction === 'forward') { + if (disabled) { + uri = require('../../assets/images/arrow-forward-disabled.png'); + } else { + uri = require('../../assets/images/arrow-forward-enabled.png'); + } + } else { + if (onboarding) { + uri = require('../../assets/images/onboarding-backarrow.png'); + } else { + uri = require('../../assets/images/arrow-backward.png'); + } + } return ( - <TouchableOpacity {...props}> - <Image source={arrow} /> + <TouchableOpacity style={[styles.defautSize, props.style]} {...props}> + <Image style={styles.image} source={uri} /> </TouchableOpacity> ); }; +const styles = StyleSheet.create({ + image: { + width: '100%', + height: '100%', + }, + defautSize: { + width: normalize(29), + height: normalize(25), + }, +}); + export default ArrowButton; diff --git a/src/components/onboarding/TaggInput.tsx b/src/components/onboarding/TaggInput.tsx index 405564ab..297392e5 100644 --- a/src/components/onboarding/TaggInput.tsx +++ b/src/components/onboarding/TaggInput.tsx @@ -1,5 +1,12 @@ import React from 'react'; -import {View, TextInput, StyleSheet, TextInputProps} from 'react-native'; +import { + View, + TextInput, + StyleSheet, + TextInputProps, + ViewStyle, + StyleProp, +} from 'react-native'; import * as Animatable from 'react-native-animatable'; import {TAGG_LIGHT_PURPLE} from '../../constants'; @@ -7,6 +14,7 @@ interface TaggInputProps extends TextInputProps { valid?: boolean; invalidWarning?: string; attemptedSubmit?: boolean; + externalStyles?: Record<string, StyleProp<ViewStyle>>; } /** * An input component that receives all props a normal TextInput component does. TaggInput components grow to 60% of their parent's width by default, but this can be set using the `width` prop. @@ -15,7 +23,7 @@ const TaggInput = React.forwardRef((props: TaggInputProps, ref: any) => { return ( <View style={styles.container}> <TextInput - style={styles.input} + style={[styles.input, props.externalStyles?.inputWarning]} placeholderTextColor="#ddd" clearButtonMode="while-editing" ref={ref} @@ -25,7 +33,7 @@ const TaggInput = React.forwardRef((props: TaggInputProps, ref: any) => { <Animatable.Text animation="shake" duration={500} - style={styles.warning}> + style={[styles.warning, props.externalStyles?.warning]}> {props.invalidWarning} </Animatable.Text> )} diff --git a/src/components/onboarding/TermsConditions.tsx b/src/components/onboarding/TermsConditions.tsx index 08cd8228..9bd0ee3b 100644 --- a/src/components/onboarding/TermsConditions.tsx +++ b/src/components/onboarding/TermsConditions.tsx @@ -49,11 +49,11 @@ const TermsConditions: React.FC<TermsConditionsProps> = (props) => { <View style={styles.body}> <RadioCheckbox checked={accepted} onPress={toggleAccepted} /> <View style={styles.bodyPrompt}> - <Text style={styles.bodyPromptText}>I accept the </Text> + <Text style={styles.bodyPromptText}>Accept </Text> <TouchableOpacity onPress={() => setModalVisible(true)}> <Text style={[styles.bodyPromptText, styles.bodyPromptTextUnderline]}> - EULA & Terms of Service + Terms and Conditions </Text> </TouchableOpacity> </View> diff --git a/src/constants/strings.ts b/src/constants/strings.ts index e8f2725d..56d54d39 100644 --- a/src/constants/strings.ts +++ b/src/constants/strings.ts @@ -45,6 +45,7 @@ export const ERROR_SERVER_DOWN = 'mhm, looks like our servers are down, please r export const ERROR_SOMETHING_WENT_WRONG = 'Oh dear, don’t worry someone will be held responsible for this error, In the meantime refresh the app'; export const ERROR_SOMETHING_WENT_WRONG_REFRESH = "Ha, looks like this one's on us, please refresh and try again"; export const ERROR_SOMETHING_WENT_WRONG_RELOAD = "You broke it, Just kidding! we don't know what happened... Please reload the app and try again"; +export const ERROR_T_AND_C_NOT_ACCEPTED = 'You must first agree to the terms and conditions.'; export const ERROR_TWILIO_SERVER_ERROR = 'mhm, looks like that is an invalid phone number or our servers are down, please try again in a few mins'; export const ERROR_UNABLE_CONNECT_CHAT = 'Unable to connect chat'; export const ERROR_UNABLE_TO_FIND_PROFILE = 'We were unable to find this profile. Please check username and try again'; @@ -57,17 +58,17 @@ export const ERROR_UPLOAD_SMALL_PROFILE_PIC = "Can't have a profile without a pi export const ERROR_UPLOAD_SP_PHOTO = 'Unable to update suggested people photo. Please retry!'; export const ERROR_VERIFICATION_FAILED_SHORT = 'Verification failed 😓'; export const FIRST_MESSAGE = 'How about sending your first message to your friend'; -export const START_CHATTING = 'Let’s Start Chatting!'; export const MARKED_AS_MSG = (str: string) => `Marked as ${str}`; export const MOMENT_DELETED_MSG = 'Moment deleted....Some moments have to go, to create space for greater ones'; export const NO_NEW_NOTIFICATIONS = 'You have no new notifications'; export const NO_RESULTS_FOUND = 'No Results Found!'; export const PRIVATE_ACCOUNT = 'This account is private'; +export const START_CHATTING = 'Let’s Start Chatting!'; export const SUCCESS_BADGES_UPDATE = 'Badges updated successfully!' export const SUCCESS_CATEGORY_DELETE = 'Category successfully deleted, but its memory will live on'; -export const SUCCESS_LAST_CONTACT_INVITE = 'Done! That was your last invite, hope you used it wisely!'; export const SUCCESS_INVITATION_CODE = 'Welcome to Tagg!'; export const SUCCESS_INVITE_CONTACT = (str: string) => `Success! You now have ${str} invites left!`; +export const SUCCESS_LAST_CONTACT_INVITE = 'Done! That was your last invite, hope you used it wisely!'; export const SUCCESS_LINK = (str: string) => `Successfully linked ${str} 🎉`; export const SUCCESS_PIC_UPLOAD = 'Beautiful, the picture was uploaded successfully!'; export const SUCCESS_PWD_RESET = 'Your password was reset successfully!'; diff --git a/src/routes/onboarding/OnboardingStackNavigator.tsx b/src/routes/onboarding/OnboardingStackNavigator.tsx index 4726a47d..7a74988b 100644 --- a/src/routes/onboarding/OnboardingStackNavigator.tsx +++ b/src/routes/onboarding/OnboardingStackNavigator.tsx @@ -3,9 +3,8 @@ import {createStackNavigator} from '@react-navigation/stack'; export type OnboardingStackParams = { InvitationCodeVerification: {userId: string; username: string}; Login: undefined; - OnboardingStepOne: undefined; - OnboardingStepThree: {userId: string; username: string}; - OnboardingStepTwo: {firstName: string; lastName: string; phone: string}; + BasicInfoOnboarding: {isPhoneVerified: boolean}; + ProfileInfoOnboarding: {userId: string; username: string}; PasswordReset: {value: string}; PasswordResetRequest: undefined; PasswordVerification: {id: string}; diff --git a/src/routes/onboarding/OnboardingStackScreen.tsx b/src/routes/onboarding/OnboardingStackScreen.tsx index 339c3d0d..50fd52d6 100644 --- a/src/routes/onboarding/OnboardingStackScreen.tsx +++ b/src/routes/onboarding/OnboardingStackScreen.tsx @@ -1,17 +1,16 @@ import {StackCardInterpolationProps} from '@react-navigation/stack'; import React from 'react'; import { + BasicInfoOnboarding, InvitationCodeVerification, Login, - OnboardingStepThree, - OnboardingStepTwo, PasswordReset, PasswordResetRequest, PasswordVerification, PhoneVerification, + ProfileInfoOnboarding, WelcomeScreen, } from '../../screens'; -import OnboardingStepOne from '../../screens/onboarding/OnboardingStepOne'; import {modalStyle} from '../main'; import {OnboardingStack} from './OnboardingStackNavigator'; @@ -44,6 +43,10 @@ const Onboarding: React.FC = () => { /> <OnboardingStack.Screen name="WelcomeScreen" component={WelcomeScreen} /> <OnboardingStack.Screen + name="BasicInfoOnboarding" + component={BasicInfoOnboarding} + /> + <OnboardingStack.Screen name="PasswordReset" component={PasswordReset} options={{ @@ -59,22 +62,13 @@ const Onboarding: React.FC = () => { }} /> <OnboardingStack.Screen - name="OnboardingStepOne" - component={OnboardingStepOne} - /> - <OnboardingStack.Screen name="PhoneVerification" component={PhoneVerification} options={{...modalStyle}} /> <OnboardingStack.Screen - name="OnboardingStepTwo" - component={OnboardingStepTwo} - options={{...modalStyle}} - /> - <OnboardingStack.Screen - name="OnboardingStepThree" - component={OnboardingStepThree} + name="ProfileInfoOnboarding" + component={ProfileInfoOnboarding} options={{...modalStyle}} /> <OnboardingStack.Screen diff --git a/src/screens/onboarding/BasicInfoOnboarding.tsx b/src/screens/onboarding/BasicInfoOnboarding.tsx new file mode 100644 index 00000000..3fa33f63 --- /dev/null +++ b/src/screens/onboarding/BasicInfoOnboarding.tsx @@ -0,0 +1,588 @@ +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, +} from 'react-native'; +import {normalize} from 'react-native-elements'; +import Animated, {Easing, useValue} 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 {HeaderHeight, 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<BasicInfoOnboardingProps> = ({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' | 'sentences' | 'words' | 'characters' | undefined + >('none'); + const [fadeValue, setFadeValue] = useState<Animated.Value<number>>( + new Animated.Value(0), + ); + const fadeButtonValue = useValue<number>(0); + const [form, setForm] = useState({ + fname: '', + lname: '', + username: '', + phone: '', + email: '', + password: '', + }); + + const fadeFormIn = () => { + setFadeValue(new Animated.Value(0)); + }; + + const fadeButtonTo = (target: number) => { + Animated.timing(fadeButtonValue, { + toValue: target, + duration: 100, + easing: Easing.linear, + }).start(); + }; + + useEffect(() => { + const fade = async () => { + Animated.timing(fadeValue, { + toValue: 1, + duration: 1000, + easing: Easing.linear, + }).start(); + }; + fade(); + }, [fadeValue]); + + useEffect(() => { + if (valid) { + fadeButtonTo(1); + } else { + fadeButtonTo(0); + } + }, [valid]); + + const goToPhoneVerification = 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); + fadeFormIn(); + } + }; + 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 ( + <Background + style={styles.container} + gradientType={BackgroundGradientType.Light}> + <StatusBar barStyle="light-content" /> + <KeyboardAvoidingView + behavior={Platform.OS === 'ios' ? 'padding' : 'height'} + keyboardVerticalOffset={-(SCREEN_HEIGHT * 0.2)} + style={styles.container}> + {currentStep !== 0 && currentStep !== 3 && ( + <ArrowButton + style={styles.backArrow} + direction="backward" + onboarding={true} + onPress={() => { + // if I go back do I want to reset the previous form? + setCurrentStep(currentStep - 1); + resetForm(step.placeholder); + setAttemptedSubmit(false); + setFadeValue(new Animated.Value(0)); + }} + /> + )} + {step.placeholder === 'Phone' && !isPhoneVerified ? ( + <> + <Animated.Text style={[styles.formHeader, {opacity: fadeValue}]}> + PHONE NUMBER + </Animated.Text> + <Animated.View style={[styles.formContainer, {opacity: fadeValue}]}> + <TaggInput + style={ + attemptedSubmit && !valid + ? [styles.input, styles.invalidColor] + : styles.input + } + maxLength={10} // currently only support US phone numbers + accessibilityHint="Enter your phone number." + accessibilityLabel="Phone number input field." + placeholder="Phone Number" + autoCompleteType="tel" + selectionColor="white" + textContentType="telephoneNumber" + externalStyles={{ + warning: styles.passWarning, + }} + keyboardType="number-pad" + onChangeText={handlePhoneUpdate} + autoFocus={true} + blurOnSubmit={false} + valid={valid} + invalidWarning={'Please enter a valid 10 digit number.'} + attemptedSubmit={attemptedSubmit} + onSubmitEditing={goToPhoneVerification} + /> + <Animated.View style={{opacity: fadeButtonValue}}> + <TaggSquareButton + onPress={goToPhoneVerification} + title={'Verify'} + buttonStyle={'normal'} + buttonColor={'white'} + labelColor={'blue'} + /> + </Animated.View> + </Animated.View> + </> + ) : ( + <> + {step.placeholder !== 'Password' ? ( + <> + <Text style={styles.formHeader}>SIGN UP</Text> + <Animated.View + style={[styles.formContainer, {opacity: fadeValue}]}> + <TaggInput + key={step.placeholder} + style={ + attemptedSubmit && !valid + ? [styles.input, styles.invalidColor] + : styles.input + } + accessibilityHint={`Enter your ${step.placeholder.toLowerCase()}`} + accessibilityLabel={`${step.placeholder} input field.`} + placeholder={step.placeholder} + autoCompleteType="name" + autoCapitalize={autoCapitalize} + textContentType="name" + returnKeyType="done" + selectionColor="white" + onChangeText={step.onChangeText} + onSubmitEditing={advance} + autoFocus={true} + blurOnSubmit={false} + externalStyles={{ + warning: styles.passWarning, + }} + valid={valid} + invalidWarning={`Please enter a valid ${step.placeholder.toLowerCase()}`} + attemptedSubmit={attemptedSubmit} + /> + <Animated.View style={{opacity: fadeButtonValue}}> + <TaggSquareButton + onPress={advance} + title={'Next'} + buttonStyle={'normal'} + buttonColor={'white'} + labelColor={'blue'} + /> + </Animated.View> + </Animated.View> + </> + ) : ( + <Animated.View + style={[styles.formContainer, {opacity: fadeValue}]}> + <TaggInput + accessibilityHint="Enter a password." + accessibilityLabel="Password input field." + placeholder="Password" + autoCompleteType="password" + textContentType="oneTimeCode" + returnKeyType="done" + selectionColor="white" + onChangeText={handlePasswordUpdate} + onSubmitEditing={advanceRegistration} + blurOnSubmit={false} + autoFocus={true} + secureTextEntry={!passVisibility} + valid={valid} + externalStyles={{ + warning: styles.passWarning, + }} + invalidWarning={ + 'Password must be at least 8 characters & contain at least one of a-z, A-Z, 0-9, and a special character.' + } + attemptedSubmit={attemptedSubmit} + style={ + attemptedSubmit && !valid + ? [styles.input, styles.invalidColor] + : styles.input + } + /> + <TouchableOpacity + accessibilityLabel="Show password button" + accessibilityHint="Select this if you want to display your tagg password" + style={styles.showPassContainer} + onPress={() => setPassVisibility(!passVisibility)}> + <Text style={styles.showPass}>Show Password</Text> + </TouchableOpacity> + <LoadingIndicator /> + <TermsConditions + style={styles.tc} + accepted={tcAccepted} + onChange={setTCAccepted} + /> + <Animated.View style={{opacity: fadeButtonValue}}> + <TaggSquareButton + onPress={advanceRegistration} + title={'Next'} + buttonStyle={'normal'} + buttonColor={'white'} + labelColor={'blue'} + /> + </Animated.View> + </Animated.View> + )} + </> + )} + </KeyboardAvoidingView> + </Background> + ); +}; + +const styles = StyleSheet.create({ + container: { + height: SCREEN_HEIGHT, + width: SCREEN_WIDTH, + alignItems: 'center', + justifyContent: 'center', + }, + formContainer: { + marginTop: '20%', + height: SCREEN_HEIGHT * 0.2, + width: '80%', + justifyContent: 'space-between', + alignItems: 'center', + }, + arrow: { + color: '#6EE7E7', + }, + showPassContainer: { + marginVertical: '1%', + borderBottomWidth: 1, + paddingBottom: '1%', + alignSelf: 'flex-start', + borderBottomColor: 'white', + marginBottom: '8%', + }, + showPass: { + color: 'white', + }, + passWarning: { + fontSize: 14, + marginTop: 5, + color: '#FF8989', + maxWidth: 350, + alignSelf: 'flex-start', + }, + input: { + minWidth: '100%', + height: 40, + fontSize: 16, + fontWeight: '600', + color: '#fff', + borderBottomWidth: 1, + borderBottomColor: '#fff', + }, + invalidColor: { + color: '#FF8989', + }, + 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: SCREEN_HEIGHT * 0.15, + }, + load: { + top: '5%', + }, + tc: { + marginVertical: '5%', + }, + backArrow: { + width: normalize(29), + height: normalize(25), + position: 'absolute', + top: HeaderHeight * 1.5, + left: 20, + }, +}); +export default BasicInfoOnboarding; diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx index 3b970864..6922bbc7 100644 --- a/src/screens/onboarding/Login.tsx +++ b/src/screens/onboarding/Login.tsx @@ -182,7 +182,7 @@ const Login: React.FC<LoginProps> = ({navigation}: LoginProps) => { * finish step 3, thus does not have a universtiy. * Redirecting user back to onboarding to finish the process */ - navigation.navigate('OnboardingStepThree', { + navigation.navigate('ProfileInfoOnboarding', { userId: data.UserID, username: username, }); diff --git a/src/screens/onboarding/PhoneVerification.tsx b/src/screens/onboarding/PhoneVerification.tsx index 6ec511b3..7d9a04d8 100644 --- a/src/screens/onboarding/PhoneVerification.tsx +++ b/src/screens/onboarding/PhoneVerification.tsx @@ -4,7 +4,6 @@ import React, {useMemo} from 'react'; import { Alert, KeyboardAvoidingView, - Platform, StyleSheet, TouchableOpacity, View, @@ -16,12 +15,12 @@ import { useBlurOnFulfill, useClearByFocusCell, } from 'react-native-confirmation-code-field'; +import {normalize} from 'react-native-elements'; import {trackPromise} from 'react-promise-tracker'; import { ArrowButton, Background, LoadingIndicator, - RegistrationWizard, SubmitButton, } from '../../components'; import {codeRegex} from '../../constants'; @@ -32,7 +31,7 @@ import { import {OnboardingStackParams} from '../../routes'; import {sendOtp, verifyOtp} from '../../services'; import {BackgroundGradientType} from '../../types'; -import {SCREEN_HEIGHT} from '../../utils'; +import {HeaderHeight} from '../../utils'; type PhoneVerificationRouteProp = RouteProp< OnboardingStackParams, @@ -67,9 +66,7 @@ const PhoneVerification: React.FC<PhoneVerificationProps> = ({ try { const success = await trackPromise(verifyOtp(phone, value)); if (success) { - navigation.navigate('OnboardingStepTwo', { - ...route.params, - }); + navigation.navigate('BasicInfoOnboarding', {isPhoneVerified: true}); } } catch (error) { console.log(error); @@ -79,12 +76,14 @@ const PhoneVerification: React.FC<PhoneVerificationProps> = ({ const footer = useMemo( () => ( - <View style={styles.footer}> - <ArrowButton - direction="backward" - onPress={() => navigation.navigate('OnboardingStepOne')} - /> - </View> + <ArrowButton + style={styles.backArrow} + direction="backward" + onboarding={true} + onPress={() => + navigation.navigate('BasicInfoOnboarding', {isPhoneVerified: false}) + } + /> ), [], ); @@ -94,7 +93,6 @@ const PhoneVerification: React.FC<PhoneVerificationProps> = ({ centered style={styles.container} gradientType={BackgroundGradientType.Light}> - <RegistrationWizard style={styles.wizard} step="one" /> <KeyboardAvoidingView behavior="padding" style={styles.form}> <Text style={styles.formHeader}>Enter 6 digit code</Text> <Text style={styles.description}> @@ -144,10 +142,6 @@ const styles = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, - wizard: { - position: 'absolute', - top: SCREEN_HEIGHT * 0.1, - }, form: { top: '20%', alignItems: 'center', @@ -208,18 +202,12 @@ const styles = StyleSheet.create({ loadingIndicator: { marginVertical: '5%', }, - footer: { - width: '100%', - flexDirection: 'row', - justifyContent: 'space-around', - ...Platform.select({ - ios: { - bottom: '20%', - }, - android: { - bottom: '10%', - }, - }), + backArrow: { + width: normalize(29), + height: normalize(25), + position: 'absolute', + top: HeaderHeight * 1.5, + left: 20, }, }); export default PhoneVerification; diff --git a/src/screens/onboarding/OnboardingStepThree.tsx b/src/screens/onboarding/ProfileInfoOnboarding.tsx index 34173b39..a481b0c0 100644 --- a/src/screens/onboarding/OnboardingStepThree.tsx +++ b/src/screens/onboarding/ProfileInfoOnboarding.tsx @@ -33,17 +33,17 @@ import {patchEditProfile} from '../../services'; import {BackgroundGradientType, UniversityType} from '../../types'; import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; -type OnboardingStepThreeRouteProp = RouteProp< +type ProfileInfoOnboardingRouteProp = RouteProp< OnboardingStackParams, - 'OnboardingStepThree' + 'ProfileInfoOnboarding' >; -type OnboardingStepThreeNavigationProp = StackNavigationProp< +type ProfileInfoOnboardingNavigationProp = StackNavigationProp< OnboardingStackParams, - 'OnboardingStepThree' + 'ProfileInfoOnboarding' >; -interface OnboardingStepThreeProps { - route: OnboardingStepThreeRouteProp; - navigation: OnboardingStepThreeNavigationProp; +interface ProfileInfoOnboardingProps { + route: ProfileInfoOnboardingRouteProp; + navigation: ProfileInfoOnboardingNavigationProp; } type FormType = { @@ -56,7 +56,7 @@ type FormType = { attemptedSubmit: boolean; }; -const OnboardingStepThree: React.FC<OnboardingStepThreeProps> = ({ +const ProfileInfoOnboarding: React.FC<ProfileInfoOnboardingProps> = ({ route, navigation, }) => { @@ -224,7 +224,6 @@ const OnboardingStepThree: React.FC<OnboardingStepThreeProps> = ({ gradientType={BackgroundGradientType.Light} style={styles.container}> <StatusBar barStyle="light-content" /> - <RegistrationWizard style={styles.wizard} step="three" /> <View style={styles.profile}> <SmallProfilePic /> <Image @@ -378,4 +377,4 @@ const styles = StyleSheet.create({ }, }); -export default OnboardingStepThree; +export default ProfileInfoOnboarding; diff --git a/src/screens/onboarding/WelcomeScreen.tsx b/src/screens/onboarding/WelcomeScreen.tsx index c36a6e05..f0089206 100644 --- a/src/screens/onboarding/WelcomeScreen.tsx +++ b/src/screens/onboarding/WelcomeScreen.tsx @@ -35,7 +35,7 @@ const WelcomeScreen: React.FC<WelcomeScreenProps> = ({navigation}) => { </View> <TaggSquareButton onPress={() => { - navigation.navigate('OnboardingStepOne'); + navigation.navigate('BasicInfoOnboarding', {isPhoneVerified: false}); }} title={'Next'} buttonStyle={'large'} diff --git a/src/screens/onboarding/index.ts b/src/screens/onboarding/index.ts index 7eb0587f..5423c46e 100644 --- a/src/screens/onboarding/index.ts +++ b/src/screens/onboarding/index.ts @@ -1,8 +1,7 @@ export {default as InvitationCodeVerification} from './InvitationCodeVerification'; export {default as Login} from './Login'; -export {default as OnboardingStepOne} from './OnboardingStepOne'; -export {default as OnboardingStepThree} from './OnboardingStepThree'; -export {default as OnboardingStepTwo} from './OnboardingStepTwo'; +export {default as ProfileInfoOnboarding} from './ProfileInfoOnboarding'; +export {default as BasicInfoOnboarding} from './BasicInfoOnboarding'; export {default as PasswordReset} from './PasswordReset'; export {default as PasswordResetRequest} from './PasswordResetRequest'; export {default as PhoneVerification} from './PhoneVerification'; diff --git a/src/screens/onboarding/OnboardingStepOne.tsx b/src/screens/onboarding/legacy/OnboardingStepOne.tsx index 618bc39b..b25d41fd 100644 --- a/src/screens/onboarding/OnboardingStepOne.tsx +++ b/src/screens/onboarding/legacy/OnboardingStepOne.tsx @@ -15,17 +15,17 @@ import { Background, RegistrationWizard, TaggInput, -} from '../../components'; -import {nameRegex, phoneRegex} from '../../constants'; +} from '../../../components'; +import {nameRegex, phoneRegex} from '../../../constants'; import { ERROR_NEXT_PAGE, ERROR_PHONE_IN_USE, ERROR_TWILIO_SERVER_ERROR, -} from '../../constants/strings'; -import {OnboardingStackParams} from '../../routes'; -import {sendOtpStatusCode} from '../../services'; -import {BackgroundGradientType} from '../../types'; -import {SCREEN_HEIGHT} from '../../utils'; +} from '../../../constants/strings'; +import {OnboardingStackParams} from '../../../routes'; +import {sendOtpStatusCode} from '../../../services'; +import {BackgroundGradientType} from '../../../types'; +import {SCREEN_HEIGHT} from '../../../utils'; type OnboardingStepOneNavigationProp = StackNavigationProp< OnboardingStackParams, @@ -270,4 +270,4 @@ const styles = StyleSheet.create({ }, }); -export default OnboardingStepOne; +export default OnboardingStepOne;
\ No newline at end of file diff --git a/src/screens/onboarding/OnboardingStepTwo.tsx b/src/screens/onboarding/legacy/OnboardingStepTwo.tsx index fc89b887..40130263 100644 --- a/src/screens/onboarding/OnboardingStepTwo.tsx +++ b/src/screens/onboarding/legacy/OnboardingStepTwo.tsx @@ -19,17 +19,17 @@ import { RegistrationWizard, TaggInput, TermsConditions, -} from '../../components'; -import {emailRegex, passwordRegex, usernameRegex} from '../../constants'; +} from '../../../components'; +import {emailRegex, passwordRegex, usernameRegex} from '../../../constants'; import { ERROR_DOUBLE_CHECK_CONNECTION, ERROR_REGISTRATION, ERROR_SOMETHING_WENT_WRONG_REFRESH, -} from '../../constants/strings'; -import {OnboardingStackParams} from '../../routes'; -import {sendRegister} from '../../services'; -import {BackgroundGradientType} from '../../types'; -import {SCREEN_HEIGHT} from '../../utils'; +} from '../../../constants/strings'; +import {OnboardingStackParams} from '../../../routes'; +import {sendRegister} from '../../../services'; +import {BackgroundGradientType} from '../../../types'; +import {SCREEN_HEIGHT} from '../../../utils'; type OnboardingStepTwoRouteProp = RouteProp< OnboardingStackParams, @@ -272,7 +272,7 @@ const OnboardingStepTwo: React.FC<OnboardingStepTwoProps> = ({ ref={usernameRef} valid={form.isValidUsername} invalidWarning={ - 'Username must be at least 6 characters and contain only alphanumerics.' + 'Username must be at least 6 characters and contain only alphanumerics.' } attemptedSubmit={form.attemptedSubmit} width={280} @@ -378,4 +378,4 @@ const styles = StyleSheet.create({ }, }); -export default OnboardingStepTwo; +export default OnboardingStepTwo;
\ No newline at end of file |