diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/common/BadgeDetailView.tsx | 89 | ||||
-rw-r--r-- | src/constants/api.ts | 1 | ||||
-rw-r--r-- | src/screens/badge/BadgeSelection.tsx | 47 | ||||
-rw-r--r-- | src/services/SuggestedPeopleService.ts | 44 | ||||
-rw-r--r-- | src/store/actions/user.ts | 22 | ||||
-rw-r--r-- | src/store/initialStates.ts | 1 | ||||
-rw-r--r-- | src/store/reducers/userReducer.ts | 5 | ||||
-rw-r--r-- | src/types/types.ts | 1 | ||||
-rw-r--r-- | src/utils/users.ts | 21 |
9 files changed, 141 insertions, 90 deletions
diff --git a/src/components/common/BadgeDetailView.tsx b/src/components/common/BadgeDetailView.tsx index bc4384e8..6504300c 100644 --- a/src/components/common/BadgeDetailView.tsx +++ b/src/components/common/BadgeDetailView.tsx @@ -1,24 +1,15 @@ import {useNavigation} from '@react-navigation/core'; import React, {useEffect, useState} from 'react'; -import { - ActivityIndicator, - FlatList, - Image, - Modal, - StyleSheet, - Text, - View, -} from 'react-native'; +import {FlatList, Image, Modal, StyleSheet, Text, View} from 'react-native'; import {TouchableOpacity} from 'react-native-gesture-handler'; import LinearGradient from 'react-native-linear-gradient'; -import {useSelector} from 'react-redux'; +import {useDispatch, useSelector} from 'react-redux'; import CloseIcon from '../../assets/ionicons/close-outline.svg'; import {BADGE_GRADIENT_FIRST} from '../../constants'; import {BADGE_DATA} from '../../constants/badges'; -import {getSuggestedPeopleProfile, removeBadgesService} from '../../services'; import {RootState} from '../../store/rootreducer'; -import {ScreenType, UniversityBadge} from '../../types'; -import {getUniversityBadge, normalize} from '../../utils'; +import {ScreenType} from '../../types'; +import {getUniversityBadge, normalize, removeUserBadge} from '../../utils'; interface BadgeDetailModalProps { userXId: string | undefined; @@ -35,38 +26,21 @@ const BadgeDetailView: React.FC<BadgeDetailModalProps> = ({ isEditable = true, setBadgeViewVisible, }) => { - const {user, profile} = useSelector((state: RootState) => + const dispatch = useDispatch(); + const { + user, + profile: {university, badges}, + } = useSelector((state: RootState) => userXId ? state.userX[screenType][userXId] : state.user, ); const navigation = useNavigation(); - const [selectedBadges, setSelectedBadges] = useState<UniversityBadge[]>([]); - const [isLoading, setIsLoading] = useState(true); const [selectedBadgesWithImage, setSelectedBadgesWithImage] = useState<any[]>( [], ); - const fetchBadges = async () => { - if (user.userId) { - const response = await getSuggestedPeopleProfile(user.userId); - if (response) { - const data = response.badges; - let extractedBadgeNames: UniversityBadge[] = []; - data.forEach((badge) => { - extractedBadgeNames.push(badge); - }); - setSelectedBadges(extractedBadgeNames); - } - } - }; - - useEffect(() => { - setIsLoading(true); - fetchBadges(); - }, []); - useEffect(() => { let badgesWithImage = []; - selectedBadges.forEach((e) => { + badges.forEach((e) => { const uniData = BADGE_DATA[e.university]; const categoryData = uniData.filter((u) => { return u.title === e.category; @@ -81,14 +55,11 @@ const BadgeDetailView: React.FC<BadgeDetailModalProps> = ({ }); setTimeout(() => { setSelectedBadgesWithImage(badgesWithImage); - setIsLoading(false); }, 250); - }, [selectedBadges]); + }, [badges]); - const removeBadgeCell = async (badge: string) => { - setIsLoading(true); - await removeBadgesService([badge], user.userId); - fetchBadges(); + const removeBadgeCell = async (badgeName: string) => { + await removeUserBadge(badges, badgeName, user.userId, dispatch); }; const badgeEditCell = ({item: {id, name, badgeImage}}) => { @@ -175,38 +146,27 @@ const BadgeDetailView: React.FC<BadgeDetailModalProps> = ({ <View style={styles.modalImageContainerStyles}> <Image style={styles.modalImageStyles} - source={getUniversityBadge(profile.university, 'Crest')} + source={getUniversityBadge(university, 'Crest')} /> </View> </View> {modalHeader()} - {!isLoading && ( - <View> - <FlatList - contentContainerStyle={styles.modalListStyles} - scrollEnabled={false} - data={selectedBadgesWithImage} - numColumns={3} - renderItem={badgeEditCell} - keyExtractor={(item) => item.id.toString()} - /> - </View> - )} - {isLoading && _loaderView()} + <View> + <FlatList + contentContainerStyle={styles.modalListStyles} + scrollEnabled={false} + data={selectedBadgesWithImage} + numColumns={3} + renderItem={badgeEditCell} + keyExtractor={(item) => item.id.toString()} + /> + </View> {isEditable && addButton()} </View> </View> ); }; - const _loaderView = () => { - return ( - <View style={styles.loaderStyles}> - <ActivityIndicator animating={isLoading} size="large" color="black" /> - </View> - ); - }; - return ( <Modal animationType="fade" @@ -269,7 +229,6 @@ const styles = StyleSheet.create({ lineHeight: normalize(20.29), textAlign: 'center', }, - loaderStyles: {justifyContent: 'center', marginVertical: 20}, modalSubheadingStyles: { fontWeight: '600', fontSize: normalize(11), diff --git a/src/constants/api.ts b/src/constants/api.ts index 45b6e8ae..d45616a1 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -60,6 +60,7 @@ export const UPDATE_BADGES_ENDPOINT: string = SP_USERS_ENDPOINT + 'update_badges/'; export const REMOVE_BADGES_ENDPOINT: string = SP_USERS_ENDPOINT + 'remove_badges/'; +export const GET_USER_BADGES_ENDPOINT: string = SP_USERS_ENDPOINT + 'get_badges/'; // Register as FCM device export const FCM_ENDPOINT: string = API_URL + 'fcm/'; diff --git a/src/screens/badge/BadgeSelection.tsx b/src/screens/badge/BadgeSelection.tsx index 38a2b01c..d0dcfa4c 100644 --- a/src/screens/badge/BadgeSelection.tsx +++ b/src/screens/badge/BadgeSelection.tsx @@ -8,14 +8,20 @@ import LinearGradient from 'react-native-linear-gradient'; import {useDispatch, useSelector} from 'react-redux'; import {BACKGROUND_GRADIENT_MAP} from '../../constants'; import {BADGE_DATA} from '../../constants/badges'; -import {ERROR_BADGES_EXCEED_LIMIT} from '../../constants/strings'; +import { + ERROR_BADGES_EXCEED_LIMIT, + SUCCESS_BADGES_UPDATE, +} from '../../constants/strings'; import {MainStackParams} from '../../routes'; import { addBadgesService, - getSuggestedPeopleProfile, + getBadgesService, updateBadgesService, } from '../../services'; -import {suggestedPeopleBadgesFinished} from '../../store/actions'; +import { + suggestedPeopleBadgesFinished, + updateUserBadges, +} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import {BackgroundGradientType} from '../../types'; import {SCREEN_HEIGHT, StatusBarHeight} from '../../utils'; @@ -36,37 +42,47 @@ const BadgeSelection: React.FC<BadgeSelectionProps> = ({route}) => { const {editing} = route.params; const { user: {userId: loggedInUserId}, - profile: {university}, + profile: {university, badges}, } = useSelector((state: RootState) => state.user); const [selectedBadges, setSelectedBadges] = useState<string[]>([]); const dispatch = useDispatch(); const navigation = useNavigation(); - // Loading badges data and extracting into a string [] + // Extracting badges data 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); - } + let extractedBadgeNames: string[] = []; + badges.forEach((badge) => { + extractedBadgeNames.push(badge.name); + }); + setSelectedBadges(extractedBadgeNames); }; if (editing) { loadData(); } }, []); + // Retrieve updated badges using get badges service and udpate the store + const loadUserBadges = async () => { + const newBadges = await getBadgesService(loggedInUserId); + dispatch(updateUserBadges(newBadges)); + }; + navigation.setOptions({ headerRight: () => ( <TouchableOpacity style={styles.rightButtonContainer} onPress={async () => { if (editing) { - await updateBadgesService(selectedBadges, university); + const success = await updateBadgesService( + selectedBadges, + university, + ); + if (success === true) { + // Load updated badges to store + loadUserBadges(); + Alert.alert(SUCCESS_BADGES_UPDATE); + } if (navigation.canGoBack()) { navigation.goBack(); } else { @@ -82,6 +98,7 @@ const BadgeSelection: React.FC<BadgeSelectionProps> = ({route}) => { ); if (success) { dispatch(suggestedPeopleBadgesFinished()); + loadUserBadges(); navigation.navigate('SuggestedPeople'); } } else { diff --git a/src/services/SuggestedPeopleService.ts b/src/services/SuggestedPeopleService.ts index 7f5b4b8c..2ae8cf55 100644 --- a/src/services/SuggestedPeopleService.ts +++ b/src/services/SuggestedPeopleService.ts @@ -2,18 +2,22 @@ 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, + GET_USER_BADGES_ENDPOINT, REMOVE_BADGES_ENDPOINT, SP_MUTUAL_BADGE_HOLDERS_ENDPOINT, SP_UPDATE_PICTURE_ENDPOINT, SP_USERS_ENDPOINT, UPDATE_BADGES_ENDPOINT, } from '../constants/api'; -import {ProfilePreviewType, SuggestedPeopleDataType} from '../types'; +import { + ProfilePreviewType, + SuggestedPeopleDataType, + UniversityBadge, +} from '../types'; import {Alert} from 'react-native'; export const sendSuggestedPeopleLinked = async ( @@ -166,6 +170,31 @@ export const addBadgesService = async ( } }; +export const getBadgesService = async (userId: string) => { + try { + const token = await AsyncStorage.getItem('token'); + const response = await fetch( + GET_USER_BADGES_ENDPOINT + '?user_id=' + userId, + { + method: 'GET', + headers: { + Authorization: 'Token ' + token, + }, + }, + ); + if (response.status === 200) { + const data: UniversityBadge[] = await response.json(); + return data ? data : []; + } else { + console.log('Error loading badges data'); + return []; + } + } catch (error) { + console.log('Exception occued while loading badges data, ', error); + return []; + } +}; + export const updateBadgesService = async ( selectedBadges: string[], university: string, @@ -185,11 +214,10 @@ export const updateBadgesService = async ( }); if (response.status === 400) { Alert.alert(ERROR_BADGES_EXCEED_LIMIT); - return; + return false; } if (response.status === 200) { - Alert.alert(SUCCESS_BADGES_UPDATE); - return; + return true; } } catch (error) { console.log(error); @@ -216,14 +244,14 @@ export const removeBadgesService = async ( }); if (response.status === 400) { Alert.alert(ERROR_BADGES_EXCEED_LIMIT); - return; + return false; } if (response.status === 200) { - Alert.alert(SUCCESS_BADGES_UPDATE); - return; + return true; } } catch (error) { console.log(error); Alert.alert(ERROR_UPLOAD_BADGES); + return false; } }; diff --git a/src/store/actions/user.ts b/src/store/actions/user.ts index 3ebd4190..96e636f6 100644 --- a/src/store/actions/user.ts +++ b/src/store/actions/user.ts @@ -6,10 +6,11 @@ import { loadProfileInfo, sendSuggestedPeopleLinked, } from '../../services'; -import {UserType} from '../../types/types'; +import {UniversityBadge, UserType} from '../../types/types'; import {getTokenOrLogout} from '../../utils'; import { clearHeaderAndProfileImages, + profileBadgesUpdated, profileCompletionStageUpdated, setIsOnboardedUser, setNewNotificationReceived, @@ -90,6 +91,25 @@ export const updateSocial = ( } }; +/** + * To update new user badges + * @param badges current selection of badges + */ +export const updateUserBadges = ( + badges: UniversityBadge[], +): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( + dispatch, +) => { + try { + dispatch({ + type: profileBadgesUpdated.type, + payload: {badges}, + }); + } catch (error) { + console.log(error); + } +}; + export const updateProfileCompletionStage = ( stage: number, ): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async ( diff --git a/src/store/initialStates.ts b/src/store/initialStates.ts index 7fd3ac5a..e0f9d776 100644 --- a/src/store/initialStates.ts +++ b/src/store/initialStates.ts @@ -18,6 +18,7 @@ export const NO_PROFILE: ProfileInfoType = { birthday: undefined, university_class: 2021, university: undefined, + badges: [], //Default to an invalid value and ignore it gracefully while showing tutorials / popups. profile_completion_stage: -1, suggested_people_linked: -1, diff --git a/src/store/reducers/userReducer.ts b/src/store/reducers/userReducer.ts index a8789c1d..97bf845c 100644 --- a/src/store/reducers/userReducer.ts +++ b/src/store/reducers/userReducer.ts @@ -42,6 +42,10 @@ const userDataSlice = createSlice({ } }, + profileBadgesUpdated: (state, action) => { + state.profile.badges = action.payload.badges; + }, + profileCompletionStageUpdated: (state, action) => { state.profile.profile_completion_stage = action.payload.stage; }, @@ -90,6 +94,7 @@ export const { setReplyPosted, setSuggestedPeopleImage, clearHeaderAndProfileImages, + profileBadgesUpdated, // setChatClientReady, } = userDataSlice.actions; export const userDataReducer = userDataSlice.reducer; diff --git a/src/types/types.ts b/src/types/types.ts index 690d6fb9..00501d49 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -49,6 +49,7 @@ export interface ProfileInfoType { gender: string; university_class: number; university: UniversityType; + badges: UniversityBadge[]; profile_completion_stage: number; suggested_people_linked: number; birthday: Date | undefined; diff --git a/src/utils/users.ts b/src/utils/users.ts index 754382b3..334cb3c0 100644 --- a/src/utils/users.ts +++ b/src/utils/users.ts @@ -1,6 +1,6 @@ import AsyncStorage from '@react-native-community/async-storage'; import {INTEGRATED_SOCIAL_LIST} from '../constants'; -import {isUserBlocked, loadSocialPosts} from '../services'; +import {isUserBlocked, loadSocialPosts, removeBadgesService} from '../services'; import { loadAllSocials, loadBlockedList, @@ -10,6 +10,7 @@ import { loadUserMoments, loadUserNotifications, logout, + updateUserBadges, } from '../store/actions'; import {NO_SOCIAL_ACCOUNTS} from '../store/initialStates'; import {loadUserMomentCategories} from './../store/actions/momentCategories'; @@ -21,6 +22,7 @@ import { ProfilePreviewType, ScreenType, UserType, + UniversityBadge, } from './../types/types'; const loadData = async (dispatch: AppDispatch, user: UserType) => { @@ -200,6 +202,23 @@ export const canViewProfile = ( return false; }; +/* Function to call remove badge service, + * remove selected badge from list passed in and + * dispatch thunk action to update store + */ +export const removeUserBadge = async ( + badges: UniversityBadge[], + badgeName: string, + userId: string, + dispatch: AppDispatch, +) => { + const success = await removeBadgesService([badgeName], userId); + if (success === true) { + badges = badges.filter((badge) => badge.name !== badgeName); + dispatch(updateUserBadges(badges)); + } +}; + export const navigateToProfile = async ( state: RootState, dispatch: any, |