aboutsummaryrefslogtreecommitdiff
path: root/src/screens/onboarding/ProfileInfoOnboarding.tsx
diff options
context:
space:
mode:
authorIvan Chen <ivan@tagg.id>2021-05-07 20:15:18 -0400
committerGitHub <noreply@github.com>2021-05-07 20:15:18 -0400
commit1c3f2c5712ca0c865f5933b3e6b1aff7604e9f35 (patch)
treed912c10dc5efe7ce2fa99423b7c707a44adb39de /src/screens/onboarding/ProfileInfoOnboarding.tsx
parenteb1a01196ae6a999ac73e146cf5286fddc0454e3 (diff)
parent525678fde244e8e9d3ea373ee8fb93c26ea92be8 (diff)
Merge pull request #405 from grusuTagg/tma823-onboarding-revamp
[TMA-823] Onboarding Revamp
Diffstat (limited to 'src/screens/onboarding/ProfileInfoOnboarding.tsx')
-rw-r--r--src/screens/onboarding/ProfileInfoOnboarding.tsx380
1 files changed, 380 insertions, 0 deletions
diff --git a/src/screens/onboarding/ProfileInfoOnboarding.tsx b/src/screens/onboarding/ProfileInfoOnboarding.tsx
new file mode 100644
index 00000000..a481b0c0
--- /dev/null
+++ b/src/screens/onboarding/ProfileInfoOnboarding.tsx
@@ -0,0 +1,380 @@
+import {RouteProp} from '@react-navigation/native';
+import {StackNavigationProp} from '@react-navigation/stack';
+import moment from 'moment';
+import React 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,
+ UniversitySelection,
+} from '../../components';
+import {CLASS_YEAR_LIST, genderRegex, TAGG_PURPLE} from '../../constants';
+import {
+ ERROR_SELECT_BIRTHDAY,
+ ERROR_SELECT_CLASS_YEAR,
+ ERROR_SELECT_GENDER,
+ ERROR_SELECT_UNIVERSITY,
+} from '../../constants/strings';
+import {OnboardingStackParams} from '../../routes/onboarding';
+import {patchEditProfile} from '../../services';
+import {BackgroundGradientType, UniversityType} from '../../types';
+import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+
+type ProfileInfoOnboardingRouteProp = RouteProp<
+ OnboardingStackParams,
+ 'ProfileInfoOnboarding'
+>;
+type ProfileInfoOnboardingNavigationProp = StackNavigationProp<
+ OnboardingStackParams,
+ 'ProfileInfoOnboarding'
+>;
+interface ProfileInfoOnboardingProps {
+ route: ProfileInfoOnboardingRouteProp;
+ navigation: ProfileInfoOnboardingNavigationProp;
+}
+
+type FormType = {
+ smallPic: string;
+ university: UniversityType;
+ birthdate: string | undefined;
+ gender: string;
+ isValidGender: boolean;
+ classYear: number;
+ attemptedSubmit: boolean;
+};
+
+const ProfileInfoOnboarding: React.FC<ProfileInfoOnboardingProps> = ({
+ route,
+ navigation,
+}) => {
+ const {userId} = route.params;
+ const [form, setForm] = React.useState<FormType>({
+ smallPic: '',
+ university: UniversityType.Empty,
+ birthdate: undefined,
+ 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) => {
+ const classYear = parseInt(value, 10);
+ 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.classYear === -1) {
+ Alert.alert(ERROR_SELECT_CLASS_YEAR);
+ return;
+ }
+ if (form.university === UniversityType.Empty) {
+ Alert.alert(ERROR_SELECT_UNIVERSITY);
+ return;
+ }
+ if (!form.birthdate) {
+ Alert.alert(ERROR_SELECT_BIRTHDAY);
+ return;
+ }
+ if (form.gender === '') {
+ Alert.alert(ERROR_SELECT_GENDER);
+ return;
+ }
+ if (!form.attemptedSubmit) {
+ setForm({
+ ...form,
+ attemptedSubmit: true,
+ });
+ }
+ const request = new FormData();
+ if (form.smallPic) {
+ request.append('smallProfilePicture', {
+ uri: form.smallPic,
+ name: 'small_profile_pic.jpg',
+ type: 'image/jpg',
+ });
+ }
+
+ if (customGender) {
+ if (form.isValidGender) {
+ request.append('gender', form.gender);
+ } else {
+ setForm({...form, attemptedSubmit: false});
+ setTimeout(() => setForm({...form, attemptedSubmit: true}));
+ return;
+ }
+ } else {
+ if (form.isValidGender) {
+ request.append('gender', form.gender);
+ }
+ }
+
+ request.append('birthday', form.birthdate);
+ request.append('university_class', form.classYear);
+ request.append('university', form.university);
+
+ patchEditProfile(request, userId)
+ .then((_) =>
+ navigation.navigate('InvitationCodeVerification', route.params),
+ )
+ .catch((error) => {
+ Alert.alert(error);
+ });
+ };
+
+ return (
+ <Animated.ScrollView bounces={false}>
+ <Background
+ centered
+ gradientType={BackgroundGradientType.Light}
+ style={styles.container}>
+ <StatusBar barStyle="light-content" />
+ <View style={styles.profile}>
+ <SmallProfilePic />
+ <Image
+ source={require('../../assets/icons/purple-plus.png')}
+ style={styles.purplePlus}
+ />
+ </View>
+ <View style={styles.contentContainer}>
+ <UniversitySelection
+ selected={form.university}
+ setSelected={(selected) => {
+ setForm({
+ ...form,
+ university: selected,
+ });
+ }}
+ />
+ <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 ProfileInfoOnboarding;