diff options
18 files changed, 307 insertions, 119 deletions
diff --git a/src/assets/icons/front-arrow.svg b/src/assets/icons/front-arrow.svg new file mode 100644 index 00000000..7beeb83e --- /dev/null +++ b/src/assets/icons/front-arrow.svg @@ -0,0 +1 @@ +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 720"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-linecap:round;stroke-linejoin:round;stroke-width:77.17px;}</style></defs><polyline class="cls-1" points="205.65 669.79 514.35 356.69 205.65 50.2"/></svg>
\ No newline at end of file diff --git a/src/components/common/TaggSquareButton.tsx b/src/components/common/TaggSquareButton.tsx index 817a2690..1a1c33b3 100644 --- a/src/components/common/TaggSquareButton.tsx +++ b/src/components/common/TaggSquareButton.tsx @@ -9,14 +9,17 @@ import { ViewStyle, } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; -import {BACKGROUND_GRADIENT_MAP, TAGG_PURPLE} from '../../constants'; +import { + BACKGROUND_GRADIENT_MAP, + TAGG_LIGHT_BLUE, + TAGG_PURPLE, +} from '../../constants'; import {normalize, SCREEN_WIDTH} from '../../utils'; - interface TaggSquareButtonProps extends ViewProps { onPress: (event: GestureResponderEvent) => void; title: string; buttonStyle: 'normal' | 'large' | 'gradient'; - buttonColor: 'purple' | 'white'; + buttonColor: 'purple' | 'white' | 'blue'; labelColor: 'white' | 'blue'; style?: ViewStyle; labelStyle?: TextStyle; @@ -27,6 +30,8 @@ const TaggSquareButton: React.FC<TaggSquareButtonProps> = (props) => { switch (props.buttonColor) { case 'purple': return {backgroundColor: TAGG_PURPLE}; + case 'blue': + return {backgroundColor: TAGG_LIGHT_BLUE}; case 'white': default: return {backgroundColor: 'white'}; diff --git a/src/components/profile/ProfileMoreInfoDrawer.tsx b/src/components/profile/ProfileMoreInfoDrawer.tsx index 90f5da48..2fec5cca 100644 --- a/src/components/profile/ProfileMoreInfoDrawer.tsx +++ b/src/components/profile/ProfileMoreInfoDrawer.tsx @@ -42,7 +42,10 @@ const ProfileMoreInfoDrawer: React.FC<ProfileMoreInfoDrawerProps> = (props) => { if (suggested_people_linked === 0) { Alert.alert(ERROR_ATTEMPT_EDIT_SP); } else { - navigation.push('UpdateSPPicture'); + // Sending undefined for updatedSelectedBadges to mark that there was no update yet + navigation.push('UpdateSPPicture', { + editing: true, + }); setIsOpen(false); } }; diff --git a/src/components/search/SearchCategories.tsx b/src/components/search/SearchCategories.tsx index a71befe6..4bae27c2 100644 --- a/src/components/search/SearchCategories.tsx +++ b/src/components/search/SearchCategories.tsx @@ -1,10 +1,10 @@ import {useNavigation} from '@react-navigation/native'; import React, {useEffect, useState} from 'react'; import {StyleSheet, View} from 'react-native'; -import {GradientBorderButton} from '..'; import {getSuggestedSearchBubbleSuggestions} from '../../services/ExploreService'; import {SearchCategoryType} from '../../types'; import {SCREEN_WIDTH} from '../../utils'; +import GradientBorderButton from '../common/GradientBorderButton'; interface SearchCategoriesProps { darkStyle?: boolean; diff --git a/src/components/suggestedPeople/BadgesDropdown.tsx b/src/components/suggestedPeople/BadgesDropdown.tsx index 70c70e47..76e8e46f 100644 --- a/src/components/suggestedPeople/BadgesDropdown.tsx +++ b/src/components/suggestedPeople/BadgesDropdown.tsx @@ -71,7 +71,7 @@ const BadgesDropdown: React.FC<BadgesDropdownProps> = ({ <TouchableOpacity activeOpacity={1} onPress={() => { - const updatedBadges = !displayBadges + const updatedBadges = !displayBadges; setDisplayBadges(updatedBadges); if (updatedBadges) { animate(); diff --git a/src/constants/api.ts b/src/constants/api.ts index 127ef432..34ef9a1c 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -33,12 +33,13 @@ export const DISCOVER_ENDPOINT: string = API_URL + 'discover/'; export const SEARCH_BUTTONS_ENDPOPINT: string = DISCOVER_ENDPOINT + 'search_buttons/'; export const WAITLIST_USER_ENDPOINT: string = API_URL + 'waitlist-user/'; export const COMMENT_THREAD_ENDPOINT: string = API_URL + 'reply/'; -export const ADD_USER_BADGES: string = API_URL + 'suggested_people/add_badges/'; // Suggested People export const SP_USERS_ENDPOINT: string = API_URL + 'suggested_people/'; -export const SP_UPDATE_PICTURE_ENDPOINT: string = API_URL + 'suggested_people/update_picture/'; +export const SP_UPDATE_PICTURE_ENDPOINT: string = SP_USERS_ENDPOINT + 'update_picture/'; export const SP_MUTUAL_BADGE_HOLDERS_ENDPOINT: string = SP_USERS_ENDPOINT + 'get_mutual_badge_holders/'; +export const ADD_BADGES_ENDPOINT: string = SP_USERS_ENDPOINT + 'add_badges/'; +export const UPDATE_BADGES_ENDPOINT: string = SP_USERS_ENDPOINT + 'update_badges/'; // Register as FCM device export const FCM_ENDPOINT: string = API_URL + 'fcm/'; diff --git a/src/constants/strings.ts b/src/constants/strings.ts index 93da6e59..f289cfc1 100644 --- a/src/constants/strings.ts +++ b/src/constants/strings.ts @@ -43,10 +43,11 @@ export const ERROR_TWILIO_SERVER_ERROR = 'mhm, looks like that is an invalid pho export const ERROR_UNABLE_TO_FIND_PROFILE = 'We were unable to find this profile. Please check username and try again'; export const ERROR_UNABLE_TO_VIEW_PROFILE = 'Unable to view this profile'; export const ERROR_UPLOAD = 'An error occurred while uploading. Please try again!'; -export const ERROR_UPLOAD_BADGES = 'Unable to upload your badges. Please retry'; +export const ERROR_UPLOAD_BADGES = 'Unable to upload your badges. Please retry!'; export const ERROR_BADGES_EXCEED_LIMIT = 'You can\'t have more than 5 badges!'; export const ERROR_UPLOAD_LARGE_PROFILE_PIC = "Can't have the first image seen on the profile be blank, please upload a large picture"; export const ERROR_UPLOAD_MOMENT = 'Unable to upload moment. Please retry'; +export const ERROR_UPLOAD_SP_PHOTO = 'Unable to update suggested people photo. Please retry!'; export const ERROR_UPLOAD_SMALL_PROFILE_PIC = "Can't have a profile without a pic to represent you, please upload a small profile picture"; export const ERROR_VERIFICATION_FAILED_SHORT = 'Verification failed 😓'; export const MARKED_AS_MSG = (str: string) => `Marked as ${str}`; @@ -57,6 +58,7 @@ export const SUCCESS_CATEGORY_DELETE = 'Category successfully deleted, but its m export const SUCCESS_INVITATION_CODE = 'Perfect! You entered a valid invitation code, you are now able to login and explore Tagg!'; export const SUCCESS_LINK = (str: string) => `Successfully linked ${str} 🎉`; export const SUCCESS_PIC_UPLOAD = 'Beautiful, the picture was uploaded successfully!'; +export const SUCCESS_BADGES_UPDATE = 'Badges updated successfully!' export const SUCCESS_PWD_RESET = 'Your password was reset successfully!'; export const SUCCESS_VERIFICATION_CODE_SENT = 'New verification code sent! Check your phone messages for your code'; export const UP_TO_DATE = 'Up-to-Date!'; diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx index 8953cfe0..f7404f27 100644 --- a/src/routes/main/MainStackNavigator.tsx +++ b/src/routes/main/MainStackNavigator.tsx @@ -74,7 +74,10 @@ export type MainStackParams = { screenType: ScreenType; }; UpdateSPPicture: { - goTo: string; + editing: boolean; + }; + BadgeSelection: { + editing: boolean; }; MutualBadgeHolders: { badge_id: string; diff --git a/src/routes/main/MainStackScreen.tsx b/src/routes/main/MainStackScreen.tsx index cb232297..95d45d32 100644 --- a/src/routes/main/MainStackScreen.tsx +++ b/src/routes/main/MainStackScreen.tsx @@ -7,6 +7,7 @@ import {normalize} from 'react-native-elements'; import BackIcon from '../../assets/icons/back-arrow.svg'; import { AnimatedTutorial, + BadgeSelection, CaptionScreen, CategorySelection, CreateCustomCategory, @@ -229,7 +230,15 @@ const MainStackScreen: React.FC<MainStackProps> = ({route}) => { <MainStack.Screen name="UpdateSPPicture" component={SuggestedPeopleUploadPictureScreen} - initialParams={{goTo: 'Profile'}} + initialParams={{editing: true}} + options={{ + ...headerBarOptions('white', ''), + }} + /> + <MainStack.Screen + name="BadgeSelection" + component={BadgeSelection} + initialParams={{editing: true}} options={{ ...headerBarOptions('white', ''), }} diff --git a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx index 63547acb..30a83200 100644 --- a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx +++ b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx @@ -3,11 +3,11 @@ import {createStackNavigator} from '@react-navigation/stack'; export type SuggestedPeopleOnboardingStackParams = { WelcomeScreen: undefined; UploadPicture: { - goTo: string; + editing: boolean; + }; + BadgeSelection: { + editing: boolean; }; - BadgeSelection: undefined; }; -export const SuggestedPeopleOnboardingStack = createStackNavigator< - SuggestedPeopleOnboardingStackParams ->(); +export const SuggestedPeopleOnboardingStack = createStackNavigator<SuggestedPeopleOnboardingStackParams>(); diff --git a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx index d1a6e5e1..a02e8373 100644 --- a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx +++ b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx @@ -26,7 +26,7 @@ const SuggestedPeopleOnboardingStackScreen: React.FC = () => { <SuggestedPeopleOnboardingStack.Screen name="UploadPicture" component={SuggestedPeopleUploadPictureScreen} - initialParams={{goTo: 'SP Preview'}} + initialParams={{editing: false}} options={{ ...headerBarOptions('white', ''), }} @@ -34,6 +34,7 @@ const SuggestedPeopleOnboardingStackScreen: React.FC = () => { <SuggestedPeopleOnboardingStack.Screen name="BadgeSelection" component={BadgeSelection} + initialParams={{editing: false}} options={{ ...headerBarOptions('white', ''), }} diff --git a/src/screens/badge/BadgeItem.tsx b/src/screens/badge/BadgeItem.tsx index adf74026..3141e662 100644 --- a/src/screens/badge/BadgeItem.tsx +++ b/src/screens/badge/BadgeItem.tsx @@ -2,7 +2,11 @@ import React from 'react'; import {View, Text, StyleSheet, Image, ImageSourcePropType} from 'react-native'; import {SCREEN_WIDTH, normalize} from '../../utils'; import LinearGradient from 'react-native-linear-gradient'; -import {BADGE_GRADIENT_FIRST, BADGE_GRADIENT_REST} from '../../constants'; +import { + BACKGROUND_GRADIENT_MAP, + BADGE_GRADIENT_FIRST, + BADGE_GRADIENT_REST, +} from '../../constants'; import {TouchableOpacity} from 'react-native-gesture-handler'; interface BadgeItemProps { @@ -21,32 +25,45 @@ const BadgeItem: React.FC<BadgeItemProps> = ({ onSelection, }) => { return ( - <TouchableOpacity onPress={() => onSelection(title)}> - <LinearGradient - colors={index === 0 ? BADGE_GRADIENT_FIRST : BADGE_GRADIENT_REST} - useAngle={true} - angle={136.69} - style={styles.item}> - <View - style={ - selected ? styles.selectedDetailContainer : styles.detailContainer - }> - <Image source={resourcePath} style={styles.imageStyles} /> - <View style={styles.textContainer}> - <Text style={styles.title}>{title}</Text> + <LinearGradient + colors={ + selected ? BACKGROUND_GRADIENT_MAP[0] : ['transparent', 'transparent'] + } + useAngle={true} + angle={136.69} + style={styles.border}> + <TouchableOpacity + onPress={() => onSelection(title)} + style={{alignSelf: 'center', marginTop: 3}}> + <LinearGradient + colors={index === 0 ? BADGE_GRADIENT_FIRST : BADGE_GRADIENT_REST} + // BACKGROUND_GRADIENT_MAP + useAngle={true} + angle={136.69} + style={styles.item}> + <View style={styles.detailContainer}> + <Image source={resourcePath} style={styles.imageStyles} /> + <View style={styles.textContainer}> + <Text style={styles.title}>{title}</Text> + </View> </View> - </View> - </LinearGradient> - </TouchableOpacity> + </LinearGradient> + </TouchableOpacity> + </LinearGradient> ); }; const styles = StyleSheet.create({ + border: { + width: SCREEN_WIDTH / 3 - 20 + 6, + height: 146, + marginLeft: 10, + marginBottom: 12, + borderRadius: 8, + }, item: { width: SCREEN_WIDTH / 3 - 20, height: 140, - marginLeft: 15, - marginBottom: 12, borderRadius: 8, }, detailContainer: { diff --git a/src/screens/badge/BadgeSelection.tsx b/src/screens/badge/BadgeSelection.tsx index f1cd000c..cbd7dd88 100644 --- a/src/screens/badge/BadgeSelection.tsx +++ b/src/screens/badge/BadgeSelection.tsx @@ -1,59 +1,92 @@ -import AsyncStorage from '@react-native-community/async-storage'; -import {StackNavigationProp} from '@react-navigation/stack'; +import {RouteProp} from '@react-navigation/core'; import React, {useEffect, useState} from 'react'; import {Alert, SafeAreaView, StatusBar, StyleSheet, View} from 'react-native'; import {Text} from 'react-native-animatable'; import {TouchableOpacity} from 'react-native-gesture-handler'; import LinearGradient from 'react-native-linear-gradient'; -import {useDispatch} from 'react-redux'; -import {ADD_USER_BADGES, BACKGROUND_GRADIENT_MAP} from '../../constants'; -import {BADGE_DATA} from '../../constants/badges'; +import {useDispatch, useSelector} from 'react-redux'; +import {MainStackParams} from '../../routes'; import { - ERROR_BADGES_EXCEED_LIMIT, - ERROR_UPLOAD_BADGES, -} from '../../constants/strings'; + addBadgesService, + getSuggestedPeopleProfile, + updateBadgesService, +} from '../../services'; +import {BACKGROUND_GRADIENT_MAP} from '../../constants'; +import {BADGE_DATA} from '../../constants/badges'; +import {ERROR_BADGES_EXCEED_LIMIT} from '../../constants/strings'; import {suggestedPeopleBadgesFinished} from '../../store/actions'; import {BackgroundGradientType} from '../../types'; import {SCREEN_HEIGHT, StatusBarHeight} from '../../utils'; import BadgeList from './BadgeList'; import BadgeScreenHeader from './BadgeScreenHeader'; +import {useNavigation} from '@react-navigation/native'; +import {RootState} from '../../store/rootReducer'; /** * Home Screen for displaying Tagg Badge Selections **/ -type BadgeSelectionParamList = { - BadgeList: any[]; -}; - -type BadgeSelectionScreenNavigationProp = StackNavigationProp< - BadgeSelectionParamList, - 'BadgeList' ->; +type BadgeSelectionRouteProp = RouteProp<MainStackParams, 'BadgeSelection'>; type BadgeSelectionProps = { - navigation: BadgeSelectionScreenNavigationProp; + route: BadgeSelectionRouteProp; }; -const BadgeSelection: React.FC<BadgeSelectionProps> = ({navigation}) => { - const [canSubmit, setCanSubmit] = useState(false); +const BadgeSelection: React.FC<BadgeSelectionProps> = ({route}) => { + const {editing} = route.params; + const {userId: loggedInUserId} = useSelector( + (state: RootState) => state.user.user, + ); + const [selectedBadges, setSelectedBadges] = useState<string[]>([]); + const dispatch = useDispatch(); + const navigation = useNavigation(); + + // Loading badges data and extracting into a string [] + useEffect(() => { + const loadData = async () => { + const response = await getSuggestedPeopleProfile(loggedInUserId); + if (response) { + const data = response.badges; + let extractedBadgeNames: string[] = []; + data.forEach((badge) => { + extractedBadgeNames.push(badge.name); + }); + setSelectedBadges(extractedBadgeNames); + } + }; + if (editing) { + loadData(); + } + }, []); + navigation.setOptions({ headerRight: () => ( <TouchableOpacity style={styles.rightButtonContainer} - onPress={() => { - if (canSubmit) { - uploadUserSelection(); + onPress={async () => { + if (editing) { + updateBadgesService(selectedBadges); + navigation.navigate('UpdateSPPicture', { + editing: true, + }); } else { - dispatch(suggestedPeopleBadgesFinished()); + if (selectedBadges.length !== 0) { + const success = await addBadgesService(selectedBadges); + if (success) { + dispatch(suggestedPeopleBadgesFinished()); + } + } else { + dispatch(suggestedPeopleBadgesFinished()); + } } }}> - <Text style={styles.rightButton}>{canSubmit ? 'Done' : 'Skip'}</Text> + <Text style={styles.rightButton}> + {selectedBadges.length !== 0 || editing ? 'Done' : 'Skip'} + </Text> </TouchableOpacity> ), }); - const [selectedBadges, setSelectedBadges] = useState<string[]>([]); const selectKey = (key: string) => { if (selectedBadges.includes(key)) { const selectedBadgesArray = [...selectedBadges]; @@ -63,36 +96,12 @@ const BadgeSelection: React.FC<BadgeSelectionProps> = ({navigation}) => { } setSelectedBadges(selectedBadgesArray); } else { - const selectedBadgesArray = [...selectedBadges, key]; - setSelectedBadges(selectedBadgesArray); - } - }; - const dispatch = useDispatch(); - useEffect(() => { - setCanSubmit(selectedBadges.length !== 0); - }, [selectedBadges]); - - const uploadUserSelection = async () => { - try { - const token = await AsyncStorage.getItem('token'); - const form = new FormData(); - form.append('badges', JSON.stringify(selectedBadges)); - const response = await fetch(ADD_USER_BADGES, { - method: 'POST', - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: 'Token ' + token, - }, - body: form, - }); - if (response.status === 400) { + if (selectedBadges.length < 5) { + const selectedBadgesArray = [...selectedBadges, key]; + setSelectedBadges(selectedBadgesArray); + } else { Alert.alert(ERROR_BADGES_EXCEED_LIMIT); - return; } - dispatch(suggestedPeopleBadgesFinished()); - } catch (error) { - console.log(error); - Alert.alert(ERROR_UPLOAD_BADGES); } }; diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx index 2ca4172b..cfa39dbd 100644 --- a/src/screens/onboarding/Login.tsx +++ b/src/screens/onboarding/Login.tsx @@ -165,7 +165,6 @@ const Login: React.FC<LoginProps> = ({navigation}: LoginProps) => { userLogin(dispatch, {userId: data.UserID, username}); fcmService.sendFcmTokenToServer(); } catch (err) { - console.log(data); Alert.alert(ERROR_INVALID_LOGIN); } } else if (statusCode === 200 && !data.isOnboarded) { diff --git a/src/screens/onboarding/OnboardingStepTwo.tsx b/src/screens/onboarding/OnboardingStepTwo.tsx index de869c99..93342c3f 100644 --- a/src/screens/onboarding/OnboardingStepTwo.tsx +++ b/src/screens/onboarding/OnboardingStepTwo.tsx @@ -173,12 +173,10 @@ const OnboardingStepTwo: React.FC<OnboardingStepTwoProps> = ({ Alert.alert(ERROR_REGISTRATION(Object.values(data))); break; default: - console.log('fooo'); Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH); break; } } else { - console.log('barrr'); Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH); } } else { diff --git a/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx b/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx index 92f862c4..87e22d9e 100644 --- a/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx +++ b/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx @@ -1,4 +1,4 @@ -import {useNavigation} from '@react-navigation/native'; +import {RouteProp, useNavigation} from '@react-navigation/native'; import React, {useEffect, useState} from 'react'; import { Alert, @@ -6,16 +6,23 @@ import { ImageBackground, StatusBar, StyleSheet, + View, } from 'react-native'; import {Text} from 'react-native-animatable'; import {TouchableOpacity} from 'react-native-gesture-handler'; import ImagePicker from 'react-native-image-crop-picker'; import {SafeAreaView} from 'react-native-safe-area-context'; import {useDispatch, useSelector} from 'react-redux'; -import {TaggSquareButton} from '../../components'; +import {MainStackParams} from 'src/routes'; +import FrontArrow from '../../assets/icons/front-arrow.svg'; +import {TaggSquareButton, UniversityIcon} from '../../components'; import TaggLoadingIndicator from '../../components/common/TaggLoadingIndicator'; import {SP_HEIGHT, SP_WIDTH} from '../../constants'; -import {ERROR_UPLOAD, SUCCESS_PIC_UPLOAD} from '../../constants/strings'; +import { + ERROR_UPLOAD, + ERROR_UPLOAD_SP_PHOTO, + SUCCESS_PIC_UPLOAD, +} from '../../constants/strings'; import { getSuggestedPeopleProfile, sendSuggestedPeoplePhoto, @@ -24,9 +31,21 @@ import {uploadedSuggestedPeoplePhoto} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; -const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { - const {goTo} = route.params; +type SuggestedPeopleUploadPictureScreenRouteProp = RouteProp< + MainStackParams, + 'UpdateSPPicture' +>; + +type SuggestedPeopleUploadPictureScreenProps = { + route: SuggestedPeopleUploadPictureScreenRouteProp; +}; + +const SuggestedPeopleUploadPictureScreen: React.FC<SuggestedPeopleUploadPictureScreenProps> = ({ + route, +}) => { + const {editing} = route.params; const [image, setImage] = useState<string | undefined>(undefined); + const [oldImage, setOldImage] = useState<string | undefined>(undefined); const [loading, setLoading] = useState(false); const dispatch = useDispatch(); const navigation = useNavigation(); @@ -39,10 +58,11 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { const response = await getSuggestedPeopleProfile(loggedInUserId); if (response) { setImage(response.suggested_people_url); + setOldImage(response.suggested_people_url); } }; // if we're in edit SP, attempt to load current sp image - if (goTo === 'Profile') { + if (editing) { loadData(); } }, []); @@ -71,27 +91,27 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { }; const uploadImage = async () => { - setLoading(true); - if (image) { + // Uploading image only if initially loaded image is not the same as the image being uploaded + if (image && oldImage !== image) { + setLoading(true); const success = await sendSuggestedPeoplePhoto(image); if (success) { dispatch(uploadedSuggestedPeoplePhoto(image)); - if (goTo !== 'Profile') { - navigation.push('BadgeSelection'); + if (!editing) { + navigation.push('BadgeSelection', {editing: false}); } } else { Alert.alert(ERROR_UPLOAD); } + setLoading(false); + // Navigated back to Profile if user is editing their Suggested People Picture + if (editing) { + setTimeout(() => { + Alert.alert(success ? SUCCESS_PIC_UPLOAD : ERROR_UPLOAD_SP_PHOTO); + }, 500); + } } - setLoading(false); - - // Navigated back to Profile if user is editing their Suggested People Picture - if (goTo === 'Profile') { - navigation.goBack(); - setTimeout(() => { - Alert.alert(SUCCESS_PIC_UPLOAD); - }, 500); - } + navigation.goBack(); }; return ( @@ -99,9 +119,15 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { {loading && <TaggLoadingIndicator fullscreen />} <StatusBar barStyle={'light-content'} /> <SafeAreaView style={styles.container}> - <Text style={styles.title}>PHOTO</Text> + <Text style={editing ? styles.titleEditSuggested : styles.titlePHOTO}> + {editing ? 'Edit Suggested' : 'PHOTO'} + </Text> {image ? ( - <Text style={styles.body}>Tap again to choose another photo</Text> + <Text style={styles.body}> + {editing + ? 'Tap to upload new photo' + : 'Tap again to choose another photo'} + </Text> ) : ( <Text style={styles.body}> Upload a photo, this is what other users will see @@ -110,7 +136,7 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { {image ? ( <TouchableOpacity onPress={openImagePicker}> <ImageBackground - source={{uri: image}} + source={{uri: image, cache: 'reload'}} style={[styles.imageContainer, styles.overlay]} borderRadius={30}> <Image @@ -132,12 +158,29 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => { </ImageBackground> </TouchableOpacity> )} + {editing && ( + <TouchableOpacity + onPress={() => { + navigation.push('BadgeSelection', {editing: true}); + }}> + <View style={styles.editBadgesMainContainer}> + <View style={styles.editBadgesSubContainer}> + <UniversityIcon + university="brown" + imageStyle={{width: normalize(16), height: normalize(20)}} + /> + <Text style={styles.editBadgesText}>Edit Badges</Text> + </View> + <FrontArrow style={styles.rightArrow} /> + </View> + </TouchableOpacity> + )} {image && ( <TaggSquareButton onPress={uploadImage} title={'Done'} buttonStyle={'normal'} - buttonColor={'purple'} + buttonColor={editing ? 'blue' : 'purple'} labelColor={'white'} style={styles.buttonStyle} labelStyle={styles.buttonLabel} @@ -155,20 +198,28 @@ const styles = StyleSheet.create({ backgroundColor: '#878787', alignItems: 'center', }, - title: { + titlePHOTO: { marginTop: '5%', fontSize: normalize(25), lineHeight: normalize(30), fontWeight: '600', color: 'white', }, + titleEditSuggested: { + marginTop: '5%', + fontSize: normalize(19), + lineHeight: normalize(22.7), + letterSpacing: normalize(0.1), + fontWeight: '600', + color: 'white', + }, body: { fontSize: normalize(15), lineHeight: normalize(18), textAlign: 'center', fontWeight: '600', color: 'white', - marginTop: '5%', + marginTop: '2%', width: SCREEN_WIDTH * 0.7, }, buttonLabel: { @@ -194,5 +245,35 @@ const styles = StyleSheet.create({ marginTop: '30%', marginBottom: '10%', }, + rightButtonContainer: {marginRight: 24}, + rightButton: { + color: '#FFFFFF', + fontWeight: 'bold', + fontSize: 15, + lineHeight: 18, + }, + editBadgesMainContainer: { + height: 30, + flexDirection: 'row', + width: SCREEN_WIDTH * 0.6, + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: '4%', + marginTop: '0.8%', + }, + editBadgesSubContainer: {flexDirection: 'row', alignItems: 'center'}, + editBadgesText: { + color: 'white', + fontWeight: '600', + fontSize: normalize(14), + lineHeight: normalize(16.71), + textAlign: 'left', + marginLeft: 18, + }, + rightArrow: { + width: 20, + height: 20, + alignSelf: 'center', + }, }); export default SuggestedPeopleUploadPictureScreen; diff --git a/src/services/SuggestedPeopleService.ts b/src/services/SuggestedPeopleService.ts index d0032458..a65b91ef 100644 --- a/src/services/SuggestedPeopleService.ts +++ b/src/services/SuggestedPeopleService.ts @@ -1,11 +1,19 @@ import AsyncStorage from '@react-native-community/async-storage'; import { + ERROR_BADGES_EXCEED_LIMIT, + ERROR_UPLOAD_BADGES, + SUCCESS_BADGES_UPDATE, +} from '../constants/strings'; +import { + ADD_BADGES_ENDPOINT, EDIT_PROFILE_ENDPOINT, SP_MUTUAL_BADGE_HOLDERS_ENDPOINT, SP_UPDATE_PICTURE_ENDPOINT, SP_USERS_ENDPOINT, -} from '../constants'; + UPDATE_BADGES_ENDPOINT, +} from '../constants/api'; import {ProfilePreviewType, SuggestedPeopleDataType} from '../types'; +import { Alert } from 'react-native'; export const sendSuggestedPeopleLinked = async ( userId: string, @@ -119,3 +127,55 @@ export const getMutualBadgeHolders = async () => { return undefined; } }; + +export const addBadgesService = async (selectedBadges: string[]) => { + try { + const token = await AsyncStorage.getItem('token'); + const form = new FormData(); + form.append('badges', JSON.stringify(selectedBadges)); + const response = await fetch(ADD_BADGES_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: 'Token ' + token, + }, + body: form, + }); + if (response.status === 400) { + Alert.alert(ERROR_BADGES_EXCEED_LIMIT); + return false; + } + return true; + } catch (error) { + console.log(error); + Alert.alert(ERROR_UPLOAD_BADGES); + return false; + } +}; + +export const updateBadgesService = async (selectedBadges: string[]) => { + try { + const token = await AsyncStorage.getItem('token'); + const form = new FormData(); + form.append('badges', JSON.stringify(selectedBadges)); + const response = await fetch(UPDATE_BADGES_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: 'Token ' + token, + }, + body: form, + }); + if (response.status === 400) { + Alert.alert(ERROR_BADGES_EXCEED_LIMIT); + return; + } + if (response.status === 200) { + Alert.alert(SUCCESS_BADGES_UPDATE); + return; + } + } catch (error) { + console.log(error); + Alert.alert(ERROR_UPLOAD_BADGES); + } +}; diff --git a/src/services/WaitlistUserService.tsx b/src/services/WaitlistUserService.tsx index 516affe3..f50b7f39 100644 --- a/src/services/WaitlistUserService.tsx +++ b/src/services/WaitlistUserService.tsx @@ -7,7 +7,6 @@ export const adduserToWaitlist: ( last_name: string, ) => Promise<boolean> = 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: { |