From c758389ad2ebe98196d4618ec08dbf2b24d95bfa Mon Sep 17 00:00:00 2001
From: Ashm Walia <40498934+ashmgarv@users.noreply.github.com>
Date: Tue, 12 Jan 2021 13:35:33 -0800
Subject: [TMA 472] Added option to be added to Taggs wait list (#168)
* Added screens to add to waitlist and a page to display on success of the same
* Incorporated small comment
---
src/assets/icons/celebration-logo.svg | 1 +
src/components/onboarding/TaggBigInput.tsx | 3 +-
src/components/onboarding/TaggInput.tsx | 3 +-
.../onboarding/TermsAndConditionsText.tsx | 13 +-
src/constants/api.ts | 1 +
src/constants/constants.ts | 2 +
src/routes/onboarding/OnboardingStackNavigator.tsx | 2 +
src/routes/onboarding/OnboardingStackScreen.tsx | 10 +
src/screens/onboarding/AddWaitlistUserScreen.tsx | 238 +++++++++++++++++++++
.../onboarding/InvitationCodeVerification.tsx | 29 ++-
src/screens/onboarding/Login.tsx | 8 +-
src/screens/onboarding/WaitlistSuccessScreen.tsx | 156 ++++++++++++++
src/screens/onboarding/index.ts | 2 +
src/services/WaitlistUserService.tsx | 45 ++++
src/services/index.ts | 1 +
15 files changed, 506 insertions(+), 8 deletions(-)
create mode 100644 src/assets/icons/celebration-logo.svg
create mode 100644 src/screens/onboarding/AddWaitlistUserScreen.tsx
create mode 100644 src/screens/onboarding/WaitlistSuccessScreen.tsx
create mode 100644 src/services/WaitlistUserService.tsx
(limited to 'src')
diff --git a/src/assets/icons/celebration-logo.svg b/src/assets/icons/celebration-logo.svg
new file mode 100644
index 00000000..5e4e89a0
--- /dev/null
+++ b/src/assets/icons/celebration-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/components/onboarding/TaggBigInput.tsx b/src/components/onboarding/TaggBigInput.tsx
index ba965465..4e8e1ef7 100644
--- a/src/components/onboarding/TaggBigInput.tsx
+++ b/src/components/onboarding/TaggBigInput.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import {View, TextInput, StyleSheet, TextInputProps} from 'react-native';
import * as Animatable from 'react-native-animatable';
+import {TAGG_LIGHT_PURPLE} from '../../constants';
interface TaggBigInputProps extends TextInputProps {
valid?: boolean;
@@ -55,7 +56,7 @@ const styles = StyleSheet.create({
warning: {
fontSize: 14,
marginTop: 5,
- color: '#f4ddff',
+ color: TAGG_LIGHT_PURPLE,
maxWidth: 350,
textAlign: 'center',
},
diff --git a/src/components/onboarding/TaggInput.tsx b/src/components/onboarding/TaggInput.tsx
index 12d99325..405564ab 100644
--- a/src/components/onboarding/TaggInput.tsx
+++ b/src/components/onboarding/TaggInput.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import {View, TextInput, StyleSheet, TextInputProps} from 'react-native';
import * as Animatable from 'react-native-animatable';
+import {TAGG_LIGHT_PURPLE} from '../../constants';
interface TaggInputProps extends TextInputProps {
valid?: boolean;
@@ -52,7 +53,7 @@ const styles = StyleSheet.create({
warning: {
fontSize: 14,
marginTop: 5,
- color: '#f4ddff',
+ color: TAGG_LIGHT_PURPLE,
maxWidth: 350,
textAlign: 'center',
},
diff --git a/src/components/onboarding/TermsAndConditionsText.tsx b/src/components/onboarding/TermsAndConditionsText.tsx
index 39450667..2102d613 100644
--- a/src/components/onboarding/TermsAndConditionsText.tsx
+++ b/src/components/onboarding/TermsAndConditionsText.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
-import {StyleSheet, Text} from 'react-native';
+import {Linking, StyleSheet, Text} from 'react-native';
+import {TAGG_WEBSITE} from '../../constants';
const TermsAndConditionsText: React.FC = () => {
const textWithBulletPoint = (data: string, style: object) => {
@@ -550,8 +551,14 @@ const TermsAndConditionsText: React.FC = () => {
By email: support@tagg.id
- By visiting this page on our website:{' '}
- https://www.tagg.id/
+ By visiting this page on our{' '}
+ {
+ Linking.openURL(TAGG_WEBSITE + 'terms-and-conditions/');
+ }}>
+ website
+
);
diff --git a/src/constants/api.ts b/src/constants/api.ts
index 3b2289fd..639bc8f8 100644
--- a/src/constants/api.ts
+++ b/src/constants/api.ts
@@ -27,6 +27,7 @@ export const BLOCK_USER_ENDPOINT: string = API_URL + 'block/';
export const PASSWORD_RESET_ENDPOINT: string = API_URL + 'password-reset/';
export const MOMENT_CATEGORY_ENDPOINT: string = API_URL + 'moment-category/';
export const NOTIFICATIONS_ENDPOINT: string = API_URL + 'notifications/';
+export const WAITLIST_USER_ENDPOINT: string = API_URL + 'waitlist-user/';
// Register as FCM device
export const FCM_ENDPOINT: string = API_URL + 'fcm/';
diff --git a/src/constants/constants.ts b/src/constants/constants.ts
index 8d8b7dfe..90d70724 100644
--- a/src/constants/constants.ts
+++ b/src/constants/constants.ts
@@ -60,6 +60,7 @@ export const YOUTUBE_FONT_COLOR: string = '#FCA4A4';
export const TAGG_DARK_BLUE = '#4E699C';
export const TAGG_TEXT_LIGHT_BLUE: string = '#698DD3';
+export const TAGG_LIGHT_PURPLE = '#F4DDFF';
export const TAGGS_GRADIENT = {
start: '#9F00FF',
@@ -141,6 +142,7 @@ export const CLASS_YEAR_LIST: Array = [
'2026',
];
+export const TAGG_WEBSITE = 'https://www.tagg.id/';
export const MOMENT_CATEGORY_BG_COLORS: string[] = [
'#5E4AE4',
'#5044A6',
diff --git a/src/routes/onboarding/OnboardingStackNavigator.tsx b/src/routes/onboarding/OnboardingStackNavigator.tsx
index ea7ce8e8..9f614f7c 100644
--- a/src/routes/onboarding/OnboardingStackNavigator.tsx
+++ b/src/routes/onboarding/OnboardingStackNavigator.tsx
@@ -39,6 +39,8 @@ export type OnboardingStackParams = {
TaggPopup: {
popupProps: TaggPopupType;
};
+ AddWaitlistUser: undefined;
+ WaitlistSuccess: undefined;
};
export const OnboardingStack = createStackNavigator();
diff --git a/src/routes/onboarding/OnboardingStackScreen.tsx b/src/routes/onboarding/OnboardingStackScreen.tsx
index 54614b32..afc5be99 100644
--- a/src/routes/onboarding/OnboardingStackScreen.tsx
+++ b/src/routes/onboarding/OnboardingStackScreen.tsx
@@ -14,6 +14,8 @@ import {
PasswordReset,
WelcomeScreen,
CategorySelection,
+ AddWaitlistUserScreen,
+ WaitlistSuccessScreen,
} from '../../screens';
import {StackCardInterpolationProps} from '@react-navigation/stack';
import TaggPopup from '../../components/common/TaggPopup';
@@ -96,6 +98,14 @@ const Onboarding: React.FC = () => {
name="InvitationCodeVerification"
component={InvitationCodeVerification}
/>
+
+
;
+
+interface AddWaitlistUserScreenProps {
+ navigation: AddWaitlistUserScreenProp;
+}
+
+const AddWaitlistUserScreen: React.FC = ({
+ 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 = () => (
+
+ navigation.navigate('InvitationCodeVerification')}
+ />
+
+ );
+
+ const {phone_number, first_name, last_name} = form;
+
+ return (
+
+
+
+
+ JOIN WAITLIST
+
+ 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}
+ />
+ 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}
+ />
+ 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}
+ />
+
+ Submit
+
+
+
+
+
+ );
+};
+
+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 = ({
}
};
+ const navigateToAddWaitList = () => {
+ navigation.navigate('AddWaitlistUser');
+ };
+
const Footer = () => (
= ({
accessibilityHint="Select this after entering your invitation code"
onPress={handleInvitationCodeVerification}
/>
+
+ Don't have an invite?
+
+ {' '}
+ Join the Waitlist
+
+
@@ -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 = ({
+ navigation,
+}) => {
+ const handleSignIn = () => {
+ navigation.navigate('InvitationCodeVerification');
+ };
+
+ const Footer = () => (
+
+ navigation.navigate('AddWaitlistUser')}
+ />
+
+ );
+ return (
+
+
+
+
+
+ You've successfully joined{'\n'}
+ the waitlist, we'll let you know{'\n'}
+ as soon as your invite is{'\n'}ready!
+
+
+ To learn more about Tagg you can visit our{'\n'}{' '}
+ {
+ Linking.openURL(TAGG_WEBSITE);
+ }}>
+ website
+
+ . Thank you!
+
+
+ Got your invite text?
+
+
+ Sign In
+
+
+
+
+ );
+};
+
+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';
diff --git a/src/services/WaitlistUserService.tsx b/src/services/WaitlistUserService.tsx
new file mode 100644
index 00000000..516affe3
--- /dev/null
+++ b/src/services/WaitlistUserService.tsx
@@ -0,0 +1,45 @@
+import {Alert} from 'react-native';
+import {WAITLIST_USER_ENDPOINT} from '../constants';
+
+export const adduserToWaitlist: (
+ phone_number: string,
+ first_name: string,
+ last_name: string,
+) => Promise = async (phone_number, first_name, last_name) => {
+ try {
+ console.log(phone_number, first_name, last_name);
+ const response = await fetch(WAITLIST_USER_ENDPOINT, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ phone_number,
+ first_name,
+ last_name,
+ }),
+ });
+ const status = response.status;
+ const message = await response.json();
+ if (status === 200) {
+ return true;
+ } else {
+ if (status === 409) {
+ Alert.alert('You are already on our waitlist / on our app');
+ } else if (status === 400) {
+ Alert.alert('Some information needed was missing / ill-formatted');
+ } else if (status === 500) {
+ Alert.alert(
+ 'Something went wrong. Sorry unable to add you to the waitlist 😔',
+ );
+ }
+ console.log(message);
+ }
+ } catch (err) {
+ Alert.alert(
+ 'Something went wrong. Sorry unable to add you to the waitlist 😔',
+ );
+ console.log(err);
+ }
+ return false;
+};
diff --git a/src/services/index.ts b/src/services/index.ts
index 7ea5bf5d..56cefddd 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -8,3 +8,4 @@ export * from './BlockUserService';
export * from './MomentCategoryService';
export * from './NotificationService';
export * from './FCMService';
+export * from './WaitlistUserService';
--
cgit v1.2.3-70-g09d2