aboutsummaryrefslogtreecommitdiff
path: root/src/screens/onboarding/OnboardingStepThree.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens/onboarding/OnboardingStepThree.tsx')
-rw-r--r--src/screens/onboarding/OnboardingStepThree.tsx411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/screens/onboarding/OnboardingStepThree.tsx b/src/screens/onboarding/OnboardingStepThree.tsx
new file mode 100644
index 00000000..f832539d
--- /dev/null
+++ b/src/screens/onboarding/OnboardingStepThree.tsx
@@ -0,0 +1,411 @@
+import AsyncStorage from '@react-native-community/async-storage';
+import {RouteProp} from '@react-navigation/native';
+import {StackNavigationProp} from '@react-navigation/stack';
+import moment from 'moment';
+import React, {useMemo} from 'react';
+import {
+ Alert,
+ Image,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+import ImagePicker from 'react-native-image-crop-picker';
+import Animated from 'react-native-reanimated';
+import {
+ Background,
+ BirthDatePicker,
+ RegistrationWizard,
+ TaggDropDown,
+ TaggInput,
+} from '../../components';
+import {
+ CLASS_YEAR_LIST,
+ EDIT_PROFILE_ENDPOINT,
+ genderRegex,
+ TAGG_PURPLE,
+} from '../../constants';
+import {
+ ERROR_DOUBLE_CHECK_CONNECTION,
+ ERROR_PROFILE_CREATION_SHORT,
+ ERROR_SELECT_BIRTHDAY,
+ ERROR_SELECT_CLASS_YEAR,
+ ERROR_SELECT_GENDER,
+ ERROR_SOMETHING_WENT_WRONG_REFRESH,
+ ERROR_UPLOAD_SMALL_PROFILE_PIC,
+} from '../../constants/strings';
+import {OnboardingStackParams} from '../../routes/onboarding';
+import {BackgroundGradientType} from '../../types';
+import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+
+type OnboardingStepThreeRouteProp = RouteProp<
+ OnboardingStackParams,
+ 'OnboardingStepThree'
+>;
+type OnboardingStepThreeNavigationProp = StackNavigationProp<
+ OnboardingStackParams,
+ 'OnboardingStepThree'
+>;
+interface OnboardingStepThreeProps {
+ route: OnboardingStepThreeRouteProp;
+ navigation: OnboardingStepThreeNavigationProp;
+}
+
+const OnboardingStepThree: React.FC<OnboardingStepThreeProps> = ({
+ route,
+ navigation,
+}) => {
+ const {userId, username} = route.params;
+ let emptyDate: string | undefined;
+ const [form, setForm] = React.useState({
+ smallPic: '',
+ birthdate: emptyDate,
+ gender: '',
+ isValidGender: true,
+ classYear: -1,
+ attemptedSubmit: false,
+ });
+ const [customGender, setCustomGender] = React.useState(false);
+
+ const classYearList = CLASS_YEAR_LIST.map((value) => ({
+ label: value,
+ value,
+ }));
+
+ /**
+ * Profile screen "Add profile picture" button
+ */
+ const SmallProfilePic = () => (
+ <TouchableOpacity
+ accessible={true}
+ accessibilityLabel="ADD PROFILE PICTURE"
+ onPress={goToGallerySmallPic}
+ style={styles.smallProfileUploader}>
+ {form.smallPic ? (
+ <Image source={{uri: form.smallPic}} style={styles.smallProfilePic} />
+ ) : (
+ <Text style={styles.smallProfileText}>ADD PROFILE PICTURE</Text>
+ )}
+ </TouchableOpacity>
+ );
+
+ const goToGallerySmallPic = () => {
+ ImagePicker.openPicker({
+ smartAlbums: [
+ 'Favorites',
+ 'RecentlyAdded',
+ 'SelfPortraits',
+ 'Screenshots',
+ 'UserLibrary',
+ ],
+ width: 580,
+ height: 580,
+ cropping: true,
+ cropperToolbarTitle: 'Select Profile Picture',
+ mediaType: 'photo',
+ cropperCircleOverlay: true,
+ }).then((picture) => {
+ if ('path' in picture) {
+ setForm({
+ ...form,
+ smallPic: picture.path,
+ });
+ }
+ });
+ };
+
+ const handleGenderUpdate = (gender: string) => {
+ if (gender === 'custom') {
+ setCustomGender(true);
+ } else {
+ setCustomGender(false);
+ let isValidGender: boolean = true;
+ setForm({
+ ...form,
+ gender,
+ isValidGender,
+ });
+ }
+ };
+
+ const handleClassYearUpdate = (value: string) => {
+ console.log('foooooo');
+ const classYear = Number.parseInt(value);
+ setForm({
+ ...form,
+ classYear,
+ });
+ };
+
+ const handleCustomGenderUpdate = (gender: string) => {
+ let isValidGender: boolean = genderRegex.test(gender);
+ gender = gender.replace(' ', '-');
+ setForm({
+ ...form,
+ gender,
+ isValidGender,
+ });
+ };
+
+ const handleBirthdateUpdate = (birthdate: Date) => {
+ setForm({
+ ...form,
+ birthdate: birthdate && moment(birthdate).format('YYYY-MM-DD'),
+ });
+ };
+
+ const handleSubmit = async () => {
+ if (!form.smallPic) {
+ Alert.alert(ERROR_UPLOAD_SMALL_PROFILE_PIC);
+ return;
+ }
+ if (form.classYear === -1) {
+ Alert.alert(ERROR_SELECT_CLASS_YEAR);
+ return;
+ }
+ if (form.birthdate === emptyDate) {
+ Alert.alert(ERROR_SELECT_BIRTHDAY);
+ return;
+ }
+ if (form.gender === '') {
+ Alert.alert(ERROR_SELECT_GENDER);
+ return;
+ }
+ if (!form.attemptedSubmit) {
+ setForm({
+ ...form,
+ attemptedSubmit: true,
+ });
+ }
+ let invalidFields: boolean = false;
+ const request = new FormData();
+ if (form.smallPic) {
+ request.append('smallProfilePicture', {
+ uri: form.smallPic,
+ name: 'small_profile_pic.jpg',
+ type: 'image/jpg',
+ });
+ }
+
+ if (form.birthdate) {
+ request.append('birthday', form.birthdate);
+ }
+
+ if (customGender) {
+ if (form.isValidGender) {
+ request.append('gender', form.gender);
+ } else {
+ setForm({...form, attemptedSubmit: false});
+ setTimeout(() => setForm({...form, attemptedSubmit: true}));
+ invalidFields = true;
+ }
+ } else {
+ if (form.isValidGender) {
+ request.append('gender', form.gender);
+ }
+ }
+
+ if (form.classYear !== -1) {
+ request.append('university_class', form.classYear);
+ }
+
+ if (invalidFields) {
+ return;
+ }
+
+ const endpoint = EDIT_PROFILE_ENDPOINT + `${userId}/`;
+ try {
+ const token = await AsyncStorage.getItem('token');
+ let response = await fetch(endpoint, {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ Authorization: 'Token ' + token,
+ },
+ body: request,
+ });
+ console.log(route.params.userId);
+ let statusCode = response.status;
+ let data = await response.json();
+ if (statusCode === 200) {
+ navigation.navigate('InvitationCodeVerification', {
+ userId: route.params.userId,
+ });
+ } else if (statusCode === 400) {
+ Alert.alert(
+ 'Profile update failed. 😔',
+ data.error || 'Something went wrong! 😭',
+ );
+ } else {
+ Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
+ }
+ } catch (error) {
+ Alert.alert(ERROR_PROFILE_CREATION_SHORT, ERROR_DOUBLE_CHECK_CONNECTION);
+ return {
+ name: 'Profile creation error',
+ description: error,
+ };
+ }
+ };
+
+ const profilePics = useMemo(() => {
+ return (
+ <View style={styles.profile}>
+ <SmallProfilePic />
+ <Image
+ source={require('../../assets/icons/purple-plus.png')}
+ style={styles.purplePlus}
+ />
+ </View>
+ );
+ }, [form.largePic, form.smallPic]);
+
+ return (
+ <Animated.ScrollView bounces={false}>
+ <Background
+ centered
+ gradientType={BackgroundGradientType.Light}
+ style={styles.container}>
+ <StatusBar barStyle="light-content" />
+ <RegistrationWizard style={styles.wizard} step="three" />
+ {profilePics}
+ <View style={styles.contentContainer}>
+ <TaggDropDown
+ onValueChange={(value: string) => handleClassYearUpdate(value)}
+ items={classYearList}
+ placeholder={{
+ label: 'Class Year',
+ value: null,
+ color: '#ddd',
+ }}
+ />
+ <BirthDatePicker
+ handleBDUpdate={handleBirthdateUpdate}
+ width={280}
+ date={form.birthdate}
+ showPresetdate={false}
+ />
+ {customGender && (
+ <TaggInput
+ accessibilityHint="Custom"
+ accessibilityLabel="Gender input field."
+ placeholder="Enter your gender"
+ autoCompleteType="off"
+ textContentType="none"
+ autoCapitalize="none"
+ returnKeyType="next"
+ blurOnSubmit={false}
+ onChangeText={handleCustomGenderUpdate}
+ onSubmitEditing={() => handleSubmit()}
+ valid={form.isValidGender}
+ attemptedSubmit={form.attemptedSubmit}
+ invalidWarning={
+ 'Custom field can only contain letters and hyphens'
+ }
+ width={280}
+ />
+ )}
+ <TaggDropDown
+ onValueChange={(value: string) => handleGenderUpdate(value)}
+ items={[
+ {label: 'Male', value: 'male'},
+ {label: 'Female', value: 'female'},
+ {label: 'Custom', value: 'custom'},
+ ]}
+ placeholder={{
+ label: 'Gender',
+ value: null,
+ color: '#ddd',
+ }}
+ />
+ </View>
+ <View style={styles.footer}>
+ <TouchableOpacity onPress={handleSubmit} style={styles.submitBtn}>
+ <Text style={styles.submitBtnLabel}>Let's start!</Text>
+ </TouchableOpacity>
+ </View>
+ </Background>
+ </Animated.ScrollView>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ height: SCREEN_HEIGHT,
+ },
+ profile: {
+ marginTop: '10%',
+ marginBottom: '5%',
+ },
+ contentContainer: {
+ position: 'relative',
+ width: 280,
+ },
+ smallProfileUploader: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 20,
+ backgroundColor: '#E1F0FF',
+ height: normalize(150),
+ width: normalize(150),
+ borderRadius: normalize(150),
+ },
+ smallProfileText: {
+ textAlign: 'center',
+ fontSize: 14,
+ fontWeight: 'bold',
+ color: '#806DF4',
+ },
+ smallProfilePic: {
+ height: normalize(150),
+ width: normalize(150),
+ borderRadius: normalize(150),
+ borderWidth: 2,
+ borderColor: 'white',
+ },
+ submitBtn: {
+ backgroundColor: TAGG_PURPLE,
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH / 2.5,
+ height: SCREEN_WIDTH / 10,
+ borderRadius: 5,
+ marginTop: '5%',
+ alignSelf: 'center',
+ },
+ submitBtnLabel: {
+ fontSize: 16,
+ fontWeight: '500',
+ color: '#fff',
+ },
+ goBack: {
+ textDecorationLine: 'underline',
+ color: '#fff',
+ fontSize: 15,
+ fontWeight: '600',
+ },
+ footer: {
+ marginTop: '3%',
+ alignItems: 'center',
+ justifyContent: 'space-around',
+ height: SCREEN_HEIGHT * 0.15,
+ },
+ wizard: {
+ position: 'absolute',
+ top: SCREEN_HEIGHT * 0.1,
+ },
+ purplePlus: {
+ position: 'absolute',
+ height: normalize(40),
+ width: normalize(40),
+ bottom: 0,
+ right: 0,
+ },
+});
+
+export default OnboardingStepThree;