diff options
Diffstat (limited to 'src/screens')
| -rw-r--r-- | src/screens/onboarding/AddWaitlistUserScreen.tsx | 238 | ||||
| -rw-r--r-- | src/screens/onboarding/InvitationCodeVerification.tsx | 29 | ||||
| -rw-r--r-- | src/screens/onboarding/Login.tsx | 8 | ||||
| -rw-r--r-- | src/screens/onboarding/WaitlistSuccessScreen.tsx | 156 | ||||
| -rw-r--r-- | src/screens/onboarding/index.ts | 2 |
5 files changed, 430 insertions, 3 deletions
diff --git a/src/screens/onboarding/AddWaitlistUserScreen.tsx b/src/screens/onboarding/AddWaitlistUserScreen.tsx new file mode 100644 index 00000000..1c13ffb5 --- /dev/null +++ b/src/screens/onboarding/AddWaitlistUserScreen.tsx @@ -0,0 +1,238 @@ +import {StackNavigationProp} from '@react-navigation/stack'; +import * as React from 'react'; +import { + KeyboardAvoidingView, + Platform, + StatusBar, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import { + ArrowButton, + Background, + LoadingIndicator, + SubmitButton, + TaggInput, +} from '../../components'; +import {nameRegex, phoneRegex} from '../../constants'; +import {OnboardingStackParams} from '../../routes'; +import {adduserToWaitlist} from '../../services'; +import {BackgroundGradientType} from '../../types'; +import {SCREEN_HEIGHT} from '../../utils'; + +type AddWaitlistUserScreenProp = StackNavigationProp< + OnboardingStackParams, + 'AddWaitlistUser' +>; + +interface AddWaitlistUserScreenProps { + navigation: AddWaitlistUserScreenProp; +} + +const AddWaitlistUserScreen: React.FC<AddWaitlistUserScreenProps> = ({ + navigation, +}) => { + const phoneRef = React.useRef(); + const lnameRef = React.useRef(); + + const [form, setForm] = React.useState({ + phone_number: {value: '', isValid: false}, + first_name: {value: '', isValid: false}, + last_name: {value: '', isValid: false}, + attemptedSubmit: false, + }); + + //Handlers + const handleFocusChange = (field: string): void => { + switch (field) { + case 'last_name': + const lnameField: any = lnameRef.current; + lnameField.focus(); + break; + case 'phone_number': + const phoneField: any = phoneRef.current; + phoneField.focus(); + break; + default: + return; + } + }; + + const validate = (value: string, type: string) => { + let isValid: boolean = false; + switch (type) { + case 'phone_number': + isValid = phoneRegex.test(value); + break; + default: + isValid = nameRegex.test(value); + break; + } + return isValid; + }; + + const handleUpdate = (value: string, type: string) => { + value = value.trim(); + const isValid = validate(value, type); + setForm({ + ...form, + [type]: {value, isValid}, + }); + }; + + const handleAddUser = async () => { + if (!form.attemptedSubmit) { + setForm({ + ...form, + attemptedSubmit: true, + }); + } + try { + const {phone_number, first_name, last_name} = form; + if (phone_number.isValid && first_name.isValid && last_name.isValid) { + const success = await adduserToWaitlist( + phone_number.value, + first_name.value, + last_name.value, + ); + if (success) { + navigation.navigate('WaitlistSuccess'); + } + } else { + setForm({...form, attemptedSubmit: false}); + setTimeout(() => setForm({...form, attemptedSubmit: true})); + } + } catch (err) { + console.log(err); + } + }; + + //Components + const Footer = () => ( + <View style={styles.footer}> + <ArrowButton + direction="backward" + onPress={() => navigation.navigate('InvitationCodeVerification')} + /> + </View> + ); + + const {phone_number, first_name, last_name} = form; + + return ( + <Background + style={styles.container} + gradientType={BackgroundGradientType.Light}> + <StatusBar barStyle="light-content" /> + <KeyboardAvoidingView + behavior={Platform.OS === 'ios' ? 'padding' : 'height'} + style={styles.container}> + <View> + <Text style={styles.formHeader}>JOIN WAITLIST</Text> + </View> + <TaggInput + accessibilityHint="Enter your first name." + accessibilityLabel="First name input field." + placeholder="First Name" + autoCompleteType="name" + textContentType="name" + returnKeyType="next" + onChangeText={(text) => handleUpdate(text, 'first_name')} + onSubmitEditing={() => handleFocusChange('first_name')} + blurOnSubmit={false} + valid={first_name.isValid} + 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={(text) => handleUpdate(text, 'last_name')} + blurOnSubmit={false} + ref={lnameRef} + valid={last_name.isValid} + invalidWarning="Please enter a valid last name." + onSubmitEditing={() => handleFocusChange('phone_number')} + attemptedSubmit={form.attemptedSubmit} + width={280} + /> + <TaggInput + maxLength={12} + accessibilityHint="Enter your phone number." + accessibilityLabel="Phone number input field." + placeholder="Phone Number" + autoCompleteType="tel" + textContentType="telephoneNumber" + autoCapitalize="none" + returnKeyType="next" + keyboardType="phone-pad" + onChangeText={(text) => handleUpdate(text, 'phone_number')} + blurOnSubmit={false} + ref={phoneRef} + valid={phone_number.isValid} + invalidWarning="Please enter a valid 10 digit number." + onSubmitEditing={handleAddUser} + attemptedSubmit={form.attemptedSubmit} + width={280} + /> + <TouchableOpacity onPress={handleAddUser} style={styles.finalAction}> + <Text style={styles.finalActionLabel}>Submit</Text> + </TouchableOpacity> + <LoadingIndicator /> + </KeyboardAvoidingView> + <Footer /> + </Background> + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + finalAction: { + backgroundColor: 'white', + justifyContent: 'center', + alignItems: 'center', + width: 150, + height: 40, + borderRadius: 5, + borderWidth: 1, + borderColor: '#fff', + marginVertical: SCREEN_HEIGHT / 20, + }, + finalActionLabel: { + fontSize: 16, + fontWeight: '500', + color: 'black', + }, + 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 AddWaitlistUserScreen; diff --git a/src/screens/onboarding/InvitationCodeVerification.tsx b/src/screens/onboarding/InvitationCodeVerification.tsx index a9d1c12e..cc7cd678 100644 --- a/src/screens/onboarding/InvitationCodeVerification.tsx +++ b/src/screens/onboarding/InvitationCodeVerification.tsx @@ -10,7 +10,10 @@ import { LoadingIndicator, } from '../../components'; -import {VERIFY_INVITATION_CODE_ENDPOUNT} from '../../constants'; +import { + TAGG_LIGHT_PURPLE, + VERIFY_INVITATION_CODE_ENDPOUNT, +} from '../../constants'; import {Text} from 'react-native-animatable'; import { @@ -83,6 +86,10 @@ const InvitationCodeVerification: React.FC<InvitationCodeVerificationProps> = ({ } }; + const navigateToAddWaitList = () => { + navigation.navigate('AddWaitlistUser'); + }; + const Footer = () => ( <View style={styles.footer}> <ArrowButton @@ -131,6 +138,13 @@ const InvitationCodeVerification: React.FC<InvitationCodeVerificationProps> = ({ accessibilityHint="Select this after entering your invitation code" onPress={handleInvitationCodeVerification} /> + <View style={styles.noInviteCode}> + <Text style={styles.inviteCodeText}>Don't have an invite? </Text> + <Text style={styles.inviteCodeLink} onPress={navigateToAddWaitList}> + {' '} + Join the Waitlist + </Text> + </View> <LoadingIndicator /> </KeyboardAvoidingView> <Footer /> @@ -206,6 +220,19 @@ const styles = StyleSheet.create({ }, }), }, + noInviteCode: { + flexDirection: 'row', + justifyContent: 'center', + }, + inviteCodeText: { + color: TAGG_LIGHT_PURPLE, + fontSize: 18, + }, + inviteCodeLink: { + color: 'white', + fontSize: 18, + textDecorationLine: 'underline', + }, }); export default InvitationCodeVerification; diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx index 006b38db..d1717fc1 100644 --- a/src/screens/onboarding/Login.tsx +++ b/src/screens/onboarding/Login.tsx @@ -15,7 +15,11 @@ import { import {fcmService} from '../../services'; import {OnboardingStackParams} from '../../routes/onboarding'; import {Background, TaggInput, SubmitButton} from '../../components'; -import {usernameRegex, LOGIN_ENDPOINT} from '../../constants'; +import { + usernameRegex, + LOGIN_ENDPOINT, + TAGG_LIGHT_PURPLE, +} from '../../constants'; import AsyncStorage from '@react-native-community/async-storage'; import {BackgroundGradientType, UserType} from '../../types'; import {useDispatch} from 'react-redux'; @@ -351,7 +355,7 @@ const styles = StyleSheet.create({ }, newUser: { fontSize: 14, - color: '#f4ddff', + color: TAGG_LIGHT_PURPLE, }, getStarted: { fontSize: 14, diff --git a/src/screens/onboarding/WaitlistSuccessScreen.tsx b/src/screens/onboarding/WaitlistSuccessScreen.tsx new file mode 100644 index 00000000..1f603e3a --- /dev/null +++ b/src/screens/onboarding/WaitlistSuccessScreen.tsx @@ -0,0 +1,156 @@ +import {StackNavigationProp} from '@react-navigation/stack'; +import * as React from 'react'; +import { + KeyboardAvoidingView, + Linking, + Platform, + StatusBar, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import {ArrowButton, Background, SubmitButton} from '../../components'; +import {OnboardingStackParams} from '../../routes'; +import {BackgroundGradientType} from '../../types'; +import CelebrationLogo from '../../assets/icons/celebration-logo.svg'; +import {SCREEN_HEIGHT} from '../../utils'; +import {TAGG_WEBSITE} from '../../constants'; + +type WaitlistSuccessScreenProp = StackNavigationProp< + OnboardingStackParams, + 'WaitlistSuccess' +>; + +interface WaitlistSuccessScreenProps { + navigation: WaitlistSuccessScreenProp; +} + +const WaitlistSuccessScreen: React.FC<WaitlistSuccessScreenProps> = ({ + navigation, +}) => { + const handleSignIn = () => { + navigation.navigate('InvitationCodeVerification'); + }; + + const Footer = () => ( + <View style={styles.footer}> + <ArrowButton + direction="backward" + onPress={() => navigation.navigate('AddWaitlistUser')} + /> + </View> + ); + return ( + <Background + style={styles.container} + gradientType={BackgroundGradientType.Light}> + <KeyboardAvoidingView + behavior={Platform.OS === 'ios' ? 'padding' : 'height'} + style={styles.container}> + <StatusBar barStyle="light-content" /> + <CelebrationLogo width={100} height={100} /> + <Text style={styles.heading}> + You've successfully joined{'\n'} + the waitlist, we'll let you know{'\n'} + as soon as your invite is{'\n'}ready! + </Text> + <Text style={[styles.subHeading, styles.subHeadOneMargin]}> + To learn more about Tagg you can visit our{'\n'}{' '} + <Text + style={styles.link} + onPress={() => { + Linking.openURL(TAGG_WEBSITE); + }}> + website + </Text> + . Thank you! + </Text> + <Text style={[styles.subHeading, styles.subHeadTwoMargin]}> + Got your invite text? + </Text> + <TouchableOpacity onPress={handleSignIn} style={styles.finalAction}> + <Text style={styles.finalActionLabel}>Sign In</Text> + </TouchableOpacity> + </KeyboardAvoidingView> + <Footer /> + </Background> + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }, + wizard: { + ...Platform.select({ + ios: { + top: 50, + }, + android: { + bottom: 40, + }, + }), + }, + link: { + textDecorationLine: 'underline', + }, + finalAction: { + backgroundColor: 'white', + justifyContent: 'center', + alignItems: 'center', + width: 150, + height: 40, + borderRadius: 5, + borderWidth: 1, + borderColor: '#fff', + marginBottom: SCREEN_HEIGHT / 20, + marginTop: SCREEN_HEIGHT / 45, + }, + finalActionLabel: { + fontSize: 16, + fontWeight: '500', + color: 'black', + }, + 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%', + }, + }), + }, + heading: { + fontSize: 25, + fontWeight: 'bold', + color: 'white', + marginTop: SCREEN_HEIGHT / 25, + textAlign: 'center', + }, + subHeading: { + color: 'white', + textAlign: 'center', + }, + subHeadOneMargin: { + marginTop: SCREEN_HEIGHT / 30, + }, + subHeadTwoMargin: { + marginTop: SCREEN_HEIGHT / 10, + }, +}); + +export default WaitlistSuccessScreen; diff --git a/src/screens/onboarding/index.ts b/src/screens/onboarding/index.ts index 20a8020d..14d0e405 100644 --- a/src/screens/onboarding/index.ts +++ b/src/screens/onboarding/index.ts @@ -11,4 +11,6 @@ export {default as PasswordResetRequest} from './PasswordResetRequest'; export {default as PasswordReset} from './PasswordReset'; export {default as WelcomeScreen} from './WelcomeScreen'; export {default as CategorySelection} from './CategorySelection'; +export {default as AddWaitlistUserScreen} from './AddWaitlistUserScreen'; +export {default as WaitlistSuccessScreen} from './WaitlistSuccessScreen'; export {default as CreateCustomCategory} from './CreateCustomCategory'; |
