aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Chen <ivan@thetaggid.com>2021-02-23 18:51:50 -0500
committerGitHub <noreply@github.com>2021-02-23 18:51:50 -0500
commita586f89ddd40b1954310673cf86f1b953545d720 (patch)
treebd8dd6dc89ee583c8decac25b46170bb3ef792ee
parent5864b997b68ae774a871ee9b43c0e548a2656cc6 (diff)
parent9bf53a2251f043396fb536800b49e2cf4f811a66 (diff)
Merge pull request #259 from shravyaramesh/sp-add-friend-button
[TMA-258] Suggested People: Add friend button
-rw-r--r--src/components/profile/Friends.tsx1
-rw-r--r--src/screens/suggestedPeople/SuggestedPeopleScreen.tsx147
-rw-r--r--src/services/UserFriendsService.ts28
-rw-r--r--src/store/actions/userFriends.ts65
-rw-r--r--src/types/types.ts6
-rw-r--r--src/utils/friends.ts13
6 files changed, 218 insertions, 42 deletions
diff --git a/src/components/profile/Friends.tsx b/src/components/profile/Friends.tsx
index da289e8a..02a7460a 100644
--- a/src/components/profile/Friends.tsx
+++ b/src/components/profile/Friends.tsx
@@ -2,7 +2,6 @@ import React from 'react';
import {View, StyleSheet, ScrollView, Text} from 'react-native';
import {ProfilePreviewType, ScreenType} from '../../types';
import {ProfilePreview} from '..';
-import {Button} from 'react-native-elements';
import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
import {TAGG_LIGHT_BLUE} from '../../constants';
import {RootState} from '../../store/rootReducer';
diff --git a/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx b/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx
index cec76d00..b1650e3d 100644
--- a/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx
+++ b/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx
@@ -1,5 +1,5 @@
import {useFocusEffect, useNavigation} from '@react-navigation/native';
-import React, {memo, useCallback, useEffect, useState} from 'react';
+import React, {memo, Fragment, useCallback, useEffect, useState} from 'react';
import {
FlatList,
ListRenderItemInfo,
@@ -18,9 +18,11 @@ import {MutualFriends} from '../../components/suggestedPeople';
import {SP_PAGE_SIZE} from '../../constants';
import SuggestedPeopleOnboardingStackScreen from '../../routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen';
import {getSuggestedPeople} from '../../services/SuggestedPeopleService';
-import {resetScreenType} from '../../store/actions';
+import {cancelFriendRequest, resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {
+ FriendshipStatusType,
+ FriendshipType,
ProfilePreviewType,
ScreenType,
SuggestedPeopleDataType,
@@ -28,6 +30,7 @@ import {
import {
fetchUserX,
getUserAsProfilePreviewType,
+ handleAddFriend,
normalize,
SCREEN_HEIGHT,
SCREEN_WIDTH,
@@ -53,10 +56,10 @@ const SuggestedPeopleScreen: React.FC = () => {
);
const {suggestedPeopleImage} = useSelector((state: RootState) => state.user);
const [people, setPeople] = useState<SuggestedPeopleDataType[]>([]);
+ const [displayedUser, setDisplayedUser] = useState<SuggestedPeopleDataType>();
const [page, setPage] = useState(0);
const [refreshing, setRefreshing] = useState(false);
const [shouldResetData, setShouldResetData] = useState(false);
- const [hideStatusBar, setHideStatusBar] = useState(false);
// loads data and append it to users based on current page
useEffect(() => {
@@ -142,12 +145,71 @@ const SuggestedPeopleScreen: React.FC = () => {
}, [navigation, suggested_people_linked]),
);
- // const onViewableItemsChanged = useCallback(
- // ({viewableItems}: {viewableItems: ViewToken[]}) => {
- // setHideStatusBar(viewableItems[0].index !== 0);
- // },
- // [],
- // );
+ const updateDisplayedUser = async (
+ suggested: SuggestedPeopleDataType,
+ status: FriendshipStatusType,
+ requester_id: string,
+ ) => {
+ const localDisplayedUser: SuggestedPeopleDataType = {
+ ...displayedUser,
+ friendship: {status, requester_id},
+ };
+ setDisplayedUser(localDisplayedUser);
+
+ people.map((item) => {
+ if (item.user.id === suggested.user.id) {
+ item.friendship.status = status;
+ item.friendship.requester_id = requester_id;
+ }
+ });
+ };
+
+ const onAddFriend = async (suggested: SuggestedPeopleDataType) => {
+ handleAddFriend(screenType, suggested.user, dispatch, state);
+ updateDisplayedUser(suggested, 'requested', loggedInUserId);
+ };
+
+ const onCancelRequest = (suggested: SuggestedPeopleDataType) => {
+ dispatch(cancelFriendRequest(suggested.user.id));
+ updateDisplayedUser(suggested, 'no_record', '');
+ };
+
+ const displayButton = (suggested: SuggestedPeopleDataType) => {
+ setDisplayedUser(suggested);
+ const friendship: FriendshipType = suggested.friendship;
+ switch (friendship.status) {
+ case 'friends':
+ return <Fragment />;
+ case 'requested':
+ if (friendship.requester_id === loggedInUserId) {
+ return (
+ <TouchableOpacity
+ style={styles.requestedButton}
+ onPress={() => onCancelRequest(suggested)}
+ disabled={false}>
+ <Text style={styles.requestedButtonTitle}>{'Requested'}</Text>
+ </TouchableOpacity>
+ );
+ } else {
+ return (
+ <TouchableOpacity style={styles.addButton} disabled={true}>
+ <Text style={styles.addButtonTitle}>{'Pending'}</Text>
+ </TouchableOpacity>
+ );
+ }
+ case 'no_record':
+ return (
+ <TouchableOpacity
+ style={styles.addButton}
+ onPress={() => onAddFriend(suggested)}
+ disabled={false}>
+ <Text style={styles.addButtonTitle}>{'Add Friend'}</Text>
+ </TouchableOpacity>
+ );
+ default:
+ return <Fragment />;
+ }
+ };
const SPBody = memo(
({item}: {item: ListRenderItemInfo<SuggestedPeopleDataType>}) => {
@@ -155,7 +217,7 @@ const SuggestedPeopleScreen: React.FC = () => {
const firstItem = item.index === 0;
return (
<>
- <StatusBar barStyle={'light-content'} hidden={hideStatusBar} />
+ <StatusBar barStyle={'light-content'} />
<Image
source={{
uri: data.suggested_people_url,
@@ -178,15 +240,7 @@ const SuggestedPeopleScreen: React.FC = () => {
<Text style={styles.firstName}>{data.user.first_name}</Text>
<Text style={styles.username}>@{data.user.username}</Text>
</TouchableOpacity>
- {/* TODO: Finish me ?! */}
- {/* <TouchableOpacity
- activeOpacity={0.5}
- // TODO: Call function to Add Friend
- onPress={() => console.log('Call add friend function')}>
- <View style={styles.addButton}>
- <Text style={styles.addButtonTitle}>{'Add Friend'}</Text>
- </View>
- </TouchableOpacity> */}
+ {displayButton(data)}
</View>
</View>
<TaggsBar
@@ -218,7 +272,6 @@ const SuggestedPeopleScreen: React.FC = () => {
keyExtractor={(item, index) => index.toString()}
showsVerticalScrollIndicator={false}
onEndReached={() => setPage(page + 1)}
- // onViewableItemsChanged={onViewableItemsChanged}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
@@ -312,6 +365,60 @@ const styles = StyleSheet.create({
alignItems: 'flex-start',
marginBottom: '5%',
},
+ requestedButton: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH * 0.3,
+ height: SCREEN_WIDTH * 0.085,
+ padding: 0,
+ borderWidth: 2,
+ borderColor: 'transparent',
+ borderRadius: 1,
+ marginLeft: '1%',
+ marginTop: '4%',
+ shadowColor: 'rgb(0, 0, 0)',
+ shadowRadius: 2,
+ shadowOffset: {width: 2, height: 2},
+ shadowOpacity: 0.5,
+ backgroundColor: '#fff',
+ },
+ requestedButtonTitle: {
+ backgroundColor: 'transparent',
+ fontSize: normalize(15),
+ lineHeight: normalize(18),
+ fontWeight: 'bold',
+ textAlign: 'center',
+ letterSpacing: normalize(1),
+ },
body: {},
+
+ button: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH * 0.4,
+ aspectRatio: 154 / 33,
+ borderWidth: 2,
+ borderColor: '#fff',
+ borderRadius: 3,
+ marginRight: '2%',
+ marginLeft: '1%',
+ },
+ transparentBG: {
+ backgroundColor: 'transparent',
+ },
+ lightBlueBG: {
+ backgroundColor: '#fff',
+ },
+ label: {
+ fontSize: normalize(15),
+ fontWeight: '700',
+ letterSpacing: 1,
+ },
+ blueLabel: {
+ color: '#fff',
+ },
+ whiteLabel: {
+ color: 'white',
+ },
});
export default SuggestedPeopleScreen;
diff --git a/src/services/UserFriendsService.ts b/src/services/UserFriendsService.ts
index eff18f16..a0bf7ac7 100644
--- a/src/services/UserFriendsService.ts
+++ b/src/services/UserFriendsService.ts
@@ -86,18 +86,16 @@ export const friendOrUnfriendUser = async (
}
};
-export const declineFriendRequestService = async (
- user_id: string,
- token: string | null,
-) => {
+export const addFriendService = async (friend: string, token: string) => {
try {
- const response = await fetch(FRIENDS_ENDPOINT + `${user_id}/`, {
- method: 'DELETE',
+ const response = await fetch(FRIENDS_ENDPOINT, {
+ method: 'POST',
headers: {
+ 'Content-Type': 'application/json',
Authorization: 'Token ' + token,
},
body: JSON.stringify({
- reason: 'declined',
+ requested: friend,
}),
});
const status = response.status;
@@ -105,12 +103,18 @@ export const declineFriendRequestService = async (
return true;
} else {
console.log(await response.json());
- Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
+ Alert.alert(
+ 'Something went wrong! 😭',
+ "Would you believe me if I told you that I don't know what happened?",
+ );
return false;
}
} catch (error) {
console.log(error);
- Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
+ Alert.alert(
+ 'Something went wrong! 😭',
+ "Would you believe me if I told you that I don't know what happened?",
+ );
return false;
}
};
@@ -148,18 +152,20 @@ export const acceptFriendRequestService = async (
}
};
-export const unfriendService = async (
+export const deleteFriendshipService = async (
user_id: string,
+ reason: 'declined' | 'cancelled' | 'unfriended',
token: string | null,
) => {
try {
+ console.log('deleteFriendshipService!');
const response = await fetch(FRIENDS_ENDPOINT + `${user_id}/`, {
method: 'DELETE',
headers: {
Authorization: 'Token ' + token,
},
body: JSON.stringify({
- reason: 'unfriended',
+ reason,
}),
});
const status = response.status;
diff --git a/src/store/actions/userFriends.ts b/src/store/actions/userFriends.ts
index 763f2575..054b7fbf 100644
--- a/src/store/actions/userFriends.ts
+++ b/src/store/actions/userFriends.ts
@@ -8,10 +8,10 @@ import {
} from '../../types/types';
import {
acceptFriendRequestService,
- declineFriendRequestService,
+ addFriendService,
friendOrUnfriendUser,
loadFriends,
- unfriendService,
+ deleteFriendshipService,
} from '../../services';
import {Action, ThunkAction} from '@reduxjs/toolkit';
import {
@@ -88,6 +88,34 @@ export const friendUnfriendUser = (
}
};
+export const addFriend = (
+ friend: ProfilePreviewType, // userX's profile preview
+ screenType: ScreenType, //screentype from content
+): ThunkAction<
+ Promise<boolean | undefined>,
+ RootState,
+ unknown,
+ Action<string>
+> => async (dispatch) => {
+ try {
+ const token = await getTokenOrLogout(dispatch);
+ const success = await addFriendService(friend.id, token);
+ if (success) {
+ dispatch({
+ type: userXFriendshipEdited.type,
+ payload: {
+ userId: friend.id,
+ screenType,
+ data: 'requested',
+ },
+ });
+ return true;
+ }
+ } catch (error) {
+ console.log(error);
+ }
+};
+
export const unfriendUser = (
friend: ProfilePreviewType, // userX's profile preview
screenType: ScreenType, //screentype from content
@@ -97,7 +125,8 @@ export const unfriendUser = (
try {
const token = await getTokenOrLogout(dispatch);
// Calls method to send post or delete request
- const success = await unfriendService(friend.id, token);
+ const reason = 'unfriended';
+ const success = await deleteFriendshipService(friend.id, reason, token);
if (success) {
let data = 'no_record';
await dispatch({
@@ -150,16 +179,32 @@ export const declineFriendRequest = (
) => {
try {
const token = await getTokenOrLogout(dispatch);
- const success = await declineFriendRequestService(user_id, token);
+ const reason = 'declined';
+ const success = await deleteFriendshipService(user_id, reason, token);
if (success) {
// Get profile of requester
console.log('declined request: ', success);
- // dispatch({
- // type: updateFriends.type,
- // payload: {
- // data: requester, // has to be a requester not id
- // },
- // });
+ } else {
+ console.log('Unsuccessful call');
+ }
+ } catch (error) {
+ console.log(error);
+ }
+};
+
+export const cancelFriendRequest = (
+ user_id: string,
+): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async (
+ dispatch,
+) => {
+ try {
+ console.log('cancelFriendRequest!');
+ const token = await getTokenOrLogout(dispatch);
+ const reason = 'cancelled';
+ const success = await deleteFriendshipService(user_id, reason, token);
+ if (success) {
+ // Get profile of requester
+ console.log('cancelled request: ', success);
} else {
console.log('Unsuccessful call');
}
diff --git a/src/types/types.ts b/src/types/types.ts
index 97471171..3ad787f2 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -237,4 +237,10 @@ export type SuggestedPeopleDataType = {
badges: UniversityBadge[];
social_links: string[];
suggested_people_url: string;
+ friendship: FriendshipType;
+};
+
+export type FriendshipType = {
+ status: FriendshipStatusType;
+ requester_id: string;
};
diff --git a/src/utils/friends.ts b/src/utils/friends.ts
index ba15e087..3398c123 100644
--- a/src/utils/friends.ts
+++ b/src/utils/friends.ts
@@ -4,6 +4,7 @@ import {RootState} from '../store/rootReducer';
import {ProfilePreviewType, ProfileType, ScreenType, UserType} from '../types';
import {AppDispatch} from '../store/configureStore';
import {
+ addFriend,
friendUnfriendUser,
unfriendUser,
updateUserXFriends,
@@ -52,3 +53,15 @@ export const handleUnfriend = async (
await dispatch(updateUserXFriends(friend.id, state));
dispatch(updateUserXProfileAllScreens(friend.id, state));
};
+
+export const handleAddFriend = async (
+ screenType: ScreenType,
+ friend: ProfilePreviewType,
+ dispatch: AppDispatch,
+ state: RootState,
+) => {
+ const success = await dispatch(addFriend(friend, screenType));
+ await dispatch(updateUserXFriends(friend.id, state));
+ await dispatch(updateUserXProfileAllScreens(friend.id, state));
+ return success;
+};