aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/common/FriendsButton.tsx111
-rw-r--r--src/components/common/index.ts1
-rw-r--r--src/components/profile/Content.tsx26
-rw-r--r--src/components/profile/Friends.tsx83
-rw-r--r--src/components/profile/ProfileBody.tsx47
-rw-r--r--src/screens/profile/FriendsListScreen.tsx67
-rw-r--r--src/services/UserFriendsService.ts29
-rw-r--r--src/store/actions/userFriends.ts34
-rw-r--r--src/utils/friends.ts65
-rw-r--r--src/utils/index.ts1
10 files changed, 377 insertions, 87 deletions
diff --git a/src/components/common/FriendsButton.tsx b/src/components/common/FriendsButton.tsx
new file mode 100644
index 00000000..d47dc3b6
--- /dev/null
+++ b/src/components/common/FriendsButton.tsx
@@ -0,0 +1,111 @@
+import React from 'react';
+import {StyleSheet} from 'react-native';
+import {Button} from 'react-native-elements';
+import {ScreenType} from '../../types';
+import {TAGG_LIGHT_BLUE} from '../../constants';
+import {handleFriendUnfriend, SCREEN_WIDTH} from '../../utils';
+import {NO_PROFILE, NO_USER} from '../../store/initialStates';
+import {useDispatch, useSelector, useStore} from 'react-redux';
+import {RootState} from 'src/store/rootReducer';
+
+interface ProfileBodyProps {
+ userXId: string | undefined;
+ screenType: ScreenType;
+}
+const FriendsButton: React.FC<ProfileBodyProps> = ({userXId, screenType}) => {
+ const dispatch = useDispatch();
+
+ const {user = NO_USER, profile = NO_PROFILE} = userXId
+ ? useSelector((state: RootState) => state.userX[screenType][userXId])
+ : useSelector((state: RootState) => state.user);
+
+ const {user: loggedInUser = NO_USER} = useSelector(
+ (state: RootState) => state.user,
+ );
+
+ const state = useStore().getState();
+
+ const {friendship_status} = profile;
+
+ return (
+ <>
+ {friendship_status === 'no_record' && (
+ <Button
+ title={'Add Friend'}
+ buttonStyle={styles.button}
+ titleStyle={styles.buttonTitle}
+ onPress={() =>
+ handleFriendUnfriend(
+ screenType,
+ user,
+ profile,
+ dispatch,
+ state,
+ loggedInUser,
+ )
+ } // requested, requested status
+ />
+ )}
+ {friendship_status === 'friends' && (
+ <Button
+ title={'Unfriend'}
+ buttonStyle={styles.requestedButton}
+ titleStyle={styles.requestedButtonTitle}
+ onPress={() =>
+ handleFriendUnfriend(
+ screenType,
+ user,
+ profile,
+ dispatch,
+ state,
+ loggedInUser,
+ )
+ } // unfriend, no record status
+ />
+ )}
+ </>
+ );
+};
+
+const styles = StyleSheet.create({
+ requestedButton: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH * 0.4,
+ height: SCREEN_WIDTH * 0.075,
+ borderColor: TAGG_LIGHT_BLUE,
+ borderWidth: 2,
+ borderRadius: 0,
+ marginRight: '2%',
+ marginLeft: '1%',
+ padding: 0,
+ backgroundColor: 'transparent',
+ },
+ requestedButtonTitle: {
+ color: TAGG_LIGHT_BLUE,
+ padding: 0,
+ fontSize: 14,
+ fontWeight: '700',
+ },
+ buttonTitle: {
+ color: 'white',
+ padding: 0,
+ fontSize: 14,
+ fontWeight: '700',
+ },
+ button: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH * 0.4,
+ height: SCREEN_WIDTH * 0.075,
+ padding: 0,
+ borderWidth: 2,
+ borderColor: TAGG_LIGHT_BLUE,
+ borderRadius: 0,
+ marginRight: '2%',
+ marginLeft: '1%',
+ backgroundColor: TAGG_LIGHT_BLUE,
+ },
+});
+
+export default FriendsButton;
diff --git a/src/components/common/index.ts b/src/components/common/index.ts
index 61c7fa26..30ec6d02 100644
--- a/src/components/common/index.ts
+++ b/src/components/common/index.ts
@@ -20,3 +20,4 @@ export {default as GenericMoreInfoDrawer} from './GenericMoreInfoDrawer';
export {default as TaggPopUp} from './TaggPopup';
export {default as TaggPrompt} from './TaggPrompt';
export {default as AcceptDeclineButtons} from './AcceptDeclineButtons';
+export {default as FriendsButton} from './FriendsButton';
diff --git a/src/components/profile/Content.tsx b/src/components/profile/Content.tsx
index a35a5820..56ae1e51 100644
--- a/src/components/profile/Content.tsx
+++ b/src/components/profile/Content.tsx
@@ -216,31 +216,6 @@ const Content: React.FC<ContentProps> = ({y, userXId, screenType}) => {
}
}, [blockedUsers, user]);
- // Handles click on friend/requested/unfriend button
- /*
- * When user logged in clicks on the friend button:
- A request is sent.
- Which means you have to update the status of their friendshpi to requested
- When the status is changed to requested the button should change to requested.
- When the button is changed to requested and thr user clicks on it,
- a request much go to the backend to delete that request
- When that succeeds, their friendship must be updated to no-record again;
- When the button is changed to no_record, the add friends button should be displayed again
- */
- const handleFriendUnfriend = async () => {
- const {friendship_status} = profile;
- await dispatch(
- friendUnfriendUser(
- loggedInUser,
- getUserAsProfilePreviewType(user, profile),
- friendship_status,
- screenType,
- ),
- );
- await dispatch(updateUserXFriends(user.userId, state));
- dispatch(updateUserXProfileAllScreens(user.userId, state));
- };
-
/**
* Handles a click on the block / unblock button.
* loadFriends updates friends list for the logged in user
@@ -332,7 +307,6 @@ const Content: React.FC<ContentProps> = ({y, userXId, screenType}) => {
userXId,
screenType,
isFriend,
- handleFriendUnfriend,
handleBlockUnblock,
isBlocked,
}}
diff --git a/src/components/profile/Friends.tsx b/src/components/profile/Friends.tsx
index 23ce28fe..5c724617 100644
--- a/src/components/profile/Friends.tsx
+++ b/src/components/profile/Friends.tsx
@@ -1,40 +1,53 @@
import React from 'react';
-import {View, StyleSheet, Text} from 'react-native';
+import {View, StyleSheet, Text, ScrollView} from 'react-native';
import {ProfilePreviewType, ScreenType} from '../../types';
import {ProfilePreview} from '..';
import {useNavigation} from '@react-navigation/native';
import {Button} from 'react-native-elements';
+import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import {TAGG_LIGHT_BLUE} from '../../constants';
+import {RootState} from '../../store/rootReducer';
+import {useDispatch, useStore} from 'react-redux';
+import {handleUnfriend} from '../../utils/friends';
interface FriendsProps {
result: Array<ProfilePreviewType>;
screenType: ScreenType;
+ userXId: string;
}
-const Friends: React.FC<FriendsProps> = ({result, screenType}) => {
+const Friends: React.FC<FriendsProps> = ({result, screenType, userXId}) => {
const navigation = useNavigation();
+
+ const state: RootState = useStore().getState();
+ const dispatch = useDispatch();
+
return (
- <>
- <View style={styles.header}>
- <Button
- title="X"
- buttonStyle={styles.button}
- titleStyle={styles.buttonText}
- onPress={() => {
- navigation.pop();
- }}
- />
- <Text style={styles.title}>Friends</Text>
- </View>
+ <ScrollView
+ keyboardShouldPersistTaps={'always'}
+ stickyHeaderIndices={[4]}
+ style={styles.scrollView}
+ contentContainerStyle={styles.scrollViewContent}
+ showsVerticalScrollIndicator={false}>
{result.map((profilePreview) => (
- <ProfilePreview
- style={styles.friend}
- key={profilePreview.id}
- {...{profilePreview}}
- previewType={'Friend'}
- screenType={screenType}
- />
+ <View key={profilePreview.id}>
+ <ProfilePreview
+ style={styles.friend}
+ {...{profilePreview}}
+ previewType={'Friend'}
+ screenType={screenType}
+ />
+ <Button
+ title={'Unfriend'}
+ buttonStyle={styles.requestedButton}
+ titleStyle={styles.requestedButtonTitle}
+ onPress={() =>
+ handleUnfriend(screenType, profilePreview, dispatch, state)
+ } // unfriend, no record status
+ />
+ </View>
))}
- </>
+ </ScrollView>
);
};
@@ -60,6 +73,32 @@ const styles = StyleSheet.create({
fontSize: 18,
fontWeight: '400',
},
+ scrollView: {},
+ scrollViewContent: {
+ paddingBottom: SCREEN_HEIGHT / 15,
+ paddingHorizontal: 15,
+ marginTop: '5%',
+ backgroundColor: 'lightgrey',
+ },
+ requestedButton: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: SCREEN_WIDTH * 0.4,
+ height: SCREEN_WIDTH * 0.075,
+ borderColor: TAGG_LIGHT_BLUE,
+ borderWidth: 2,
+ borderRadius: 0,
+ marginRight: '2%',
+ marginLeft: '1%',
+ padding: 0,
+ backgroundColor: 'transparent',
+ },
+ requestedButtonTitle: {
+ color: TAGG_LIGHT_BLUE,
+ padding: 0,
+ fontSize: 14,
+ fontWeight: '700',
+ },
});
export default Friends;
diff --git a/src/components/profile/ProfileBody.tsx b/src/components/profile/ProfileBody.tsx
index 1ee3ae2b..555811c9 100644
--- a/src/components/profile/ProfileBody.tsx
+++ b/src/components/profile/ProfileBody.tsx
@@ -9,14 +9,17 @@ import {
import ToggleButton from './ToggleButton';
import {RootState} from '../../store/rootReducer';
import {useDispatch, useSelector, useStore} from 'react-redux';
-import {FriendshipStatusType, ScreenType} from '../../types';
-import {NO_PROFILE} from '../../store/initialStates';
-import {getUserAsProfilePreviewType, SCREEN_WIDTH} from '../../utils';
-import {AcceptDeclineButtons} from '../common';
+import {ScreenType} from '../../types';
+import {NO_PROFILE, NO_USER} from '../../store/initialStates';
+import {
+ getUserAsProfilePreviewType,
+ handleFriendUnfriend,
+ SCREEN_WIDTH,
+} from '../../utils';
+import {AcceptDeclineButtons, FriendsButton} from '../common';
import {
acceptFriendRequest,
declineFriendRequest,
- loadUserNotifications,
updateUserXFriends,
updateUserXProfileAllScreens,
} from '../../store/actions';
@@ -24,7 +27,6 @@ import {
interface ProfileBodyProps {
onLayout: (event: LayoutChangeEvent) => void;
isBlocked: boolean;
- handleFriendUnfriend: () => void;
handleBlockUnblock: () => void;
userXId: string | undefined;
screenType: ScreenType;
@@ -32,7 +34,6 @@ interface ProfileBodyProps {
const ProfileBody: React.FC<ProfileBodyProps> = ({
onLayout,
isBlocked,
- handleFriendUnfriend,
handleBlockUnblock,
userXId,
screenType,
@@ -41,6 +42,10 @@ const ProfileBody: React.FC<ProfileBodyProps> = ({
? useSelector((state: RootState) => state.userX[screenType][userXId])
: useSelector((state: RootState) => state.user);
+ const {user: loggedInUser = NO_USER} = useSelector(
+ (state: RootState) => state.user,
+ );
+
const {
biography,
website,
@@ -94,29 +99,23 @@ const ProfileBody: React.FC<ProfileBodyProps> = ({
)}
{userXId && !isBlocked && (
<View style={styles.buttonsContainer}>
- {friendship_status === 'no_record' && (
- <Button
- title={'Add Friend'}
- buttonStyle={styles.button}
- titleStyle={styles.buttonTitle}
- onPress={handleFriendUnfriend} // requested, requested status
- />
- )}
- {friendship_status === 'friends' && (
- <Button
- title={'Unfriend'}
- buttonStyle={styles.requestedButton}
- titleStyle={styles.requestedButtonTitle}
- onPress={handleFriendUnfriend} // unfriend, no record status
- />
- )}
+ <FriendsButton userXId={userXId} screenType={screenType} />
{(friendship_status === 'requested' &&
friendship_requester_id !== userXId && (
<Button
title={'Requested'}
buttonStyle={styles.requestedButton}
titleStyle={styles.requestedButtonTitle}
- onPress={handleFriendUnfriend} // delete request, no record status
+ onPress={() =>
+ handleFriendUnfriend(
+ screenType,
+ user,
+ profile,
+ dispatch,
+ state,
+ loggedInUser,
+ )
+ } // delete request, no record status
/>
)) ||
(friendship_status === 'requested' &&
diff --git a/src/screens/profile/FriendsListScreen.tsx b/src/screens/profile/FriendsListScreen.tsx
index f7192d10..ac3504d5 100644
--- a/src/screens/profile/FriendsListScreen.tsx
+++ b/src/screens/profile/FriendsListScreen.tsx
@@ -1,14 +1,21 @@
import React, {useState} from 'react';
-import {RouteProp} from '@react-navigation/native';
+import {RouteProp, useNavigation} from '@react-navigation/native';
import {TabsGradient, Friends, CenteredView} from '../../components';
import {ScrollView} from 'react-native-gesture-handler';
-import {SCREEN_HEIGHT} from '../../utils';
-import {StyleSheet, View} from 'react-native';
+import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import {
+ SafeAreaView,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+} from 'react-native';
import {ProfileStackParams} from '../../routes';
import {ProfilePreviewType} from '../../types';
import {EMPTY_PROFILE_PREVIEW_LIST} from '../../store/initialStates';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootReducer';
+import BackIcon from '../../assets/icons/back-arrow.svg';
type FriendsListScreenRouteProp = RouteProp<
ProfileStackParams,
@@ -20,28 +27,39 @@ interface FriendsListScreenProps {
const FriendsListScreen: React.FC<FriendsListScreenProps> = ({route}) => {
const {userXId, screenType} = route.params;
+ const navigation = useNavigation();
const {friends} = userXId
? useSelector((state: RootState) => state.userX[screenType][userXId])
: useSelector((state: RootState) => state.friends);
return (
- <CenteredView>
- <View style={styles.modalView}>
- <ScrollView
- keyboardShouldPersistTaps={'always'}
- stickyHeaderIndices={[4]}
- contentContainerStyle={styles.contentContainer}
- showsVerticalScrollIndicator={false}>
- <Friends result={friends} screenType={screenType} />
- </ScrollView>
- <TabsGradient />
- </View>
- </CenteredView>
+ <View style={styles.background}>
+ <SafeAreaView>
+ <View style={styles.header}>
+ <TouchableOpacity
+ style={styles.headerButton}
+ onPress={() => {
+ navigation.pop();
+ }}>
+ <BackIcon height={'100%'} width={'100%'} color={'white'} />
+ </TouchableOpacity>
+ <Text style={styles.headerText}>Friends</Text>
+ </View>
+ <View style={styles.body}>
+ <Friends result={friends} screenType={screenType} userXId={userXId} />
+ </View>
+ </SafeAreaView>
+ <TabsGradient />
+ </View>
);
};
const styles = StyleSheet.create({
+ background: {
+ backgroundColor: 'white',
+ height: '100%',
+ },
contentContainer: {
paddingBottom: SCREEN_HEIGHT / 15,
paddingHorizontal: 15,
@@ -66,6 +84,25 @@ const styles = StyleSheet.create({
modalScrollView: {
marginBottom: 10,
},
+ header: {justifyContent: 'center', padding: '3%'},
+ headerText: {
+ position: 'absolute',
+ alignSelf: 'center',
+ fontSize: 20.5,
+ fontWeight: '600',
+ },
+ headerButton: {
+ width: '5%',
+ aspectRatio: 1,
+ padding: 0,
+ marginLeft: '5%',
+ alignSelf: 'flex-start',
+ },
+ body: {
+ width: SCREEN_WIDTH,
+ height: SCREEN_HEIGHT * 0.8,
+ paddingTop: '3%',
+ },
});
export default FriendsListScreen;
diff --git a/src/services/UserFriendsService.ts b/src/services/UserFriendsService.ts
index f2e15824..99d86d0b 100644
--- a/src/services/UserFriendsService.ts
+++ b/src/services/UserFriendsService.ts
@@ -147,3 +147,32 @@ export const acceptFriendRequestService = async (
return false;
}
};
+
+export const unfriendService = async (
+ user_id: string,
+ token: string | null,
+) => {
+ try {
+ const response = await fetch(FRIENDS_ENDPOINT + `${user_id}/`, {
+ method: 'DELETE',
+ headers: {
+ Authorization: 'Token ' + token,
+ },
+ body: JSON.stringify({
+ reason: 'unfriended',
+ }),
+ });
+ const status = response.status;
+ if (Math.floor(status / 100) === 2) {
+ return true;
+ } else {
+ console.log(await response.json());
+ Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
+ return false;
+ }
+ } catch (error) {
+ console.log(error);
+ Alert.alert(ERROR_SOMETHING_WENT_WRONG_REFRESH);
+ return false;
+ }
+};
diff --git a/src/store/actions/userFriends.ts b/src/store/actions/userFriends.ts
index 18ad247c..ae808e9a 100644
--- a/src/store/actions/userFriends.ts
+++ b/src/store/actions/userFriends.ts
@@ -11,6 +11,7 @@ import {
declineFriendRequestService,
friendOrUnfriendUser,
loadFriends,
+ unfriendService,
} from '../../services';
import {Action, ThunkAction} from '@reduxjs/toolkit';
import {
@@ -85,6 +86,39 @@ export const friendUnfriendUser = (
}
};
+export const unfriendUser = (
+ friend: ProfilePreviewType, // userX's profile preview
+ screenType: ScreenType, //screentype from content
+): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async (
+ dispatch,
+) => {
+ try {
+ const token = await getTokenOrLogout(dispatch);
+ // Calls method to send post or delete request
+ const success = await unfriendService(friend.id, token);
+ if (success) {
+ let data = 'no_record';
+ await dispatch({
+ type: updateFriends.type,
+ payload: {
+ friend,
+ isFriend: true,
+ },
+ });
+ await dispatch({
+ type: userXFriendshipEdited.type,
+ payload: {
+ userId: friend.id,
+ screenType,
+ data,
+ },
+ });
+ }
+ } catch (error) {
+ console.log(error);
+ }
+};
+
export const acceptFriendRequest = (
requester: ProfilePreviewType,
): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async (
diff --git a/src/utils/friends.ts b/src/utils/friends.ts
new file mode 100644
index 00000000..c10cf1de
--- /dev/null
+++ b/src/utils/friends.ts
@@ -0,0 +1,65 @@
+// Handles click on friend/requested/unfriend button
+
+import {useSelector} from 'react-redux';
+import {RootState} from '../store/rootReducer';
+import {NO_USER} from '../store/initialStates';
+import {ProfilePreviewType, ProfileType, ScreenType, UserType} from '../types';
+import {AppDispatch} from '../store/configureStore';
+import {
+ friendUnfriendUser,
+ unfriendUser,
+ updateUserXFriends,
+ updateUserXProfileAllScreens,
+} from '../store/actions';
+import {getUserAsProfilePreviewType} from './users';
+
+/*
+ * When user logged in clicks on the friend button:
+ A request is sent.
+ Which means you have to update the status of their friendshpi to requested
+ When the status is changed to requested the button should change to requested.
+ When the button is changed to requested and thr user clicks on it,
+ a request much go to the backend to delete that request
+ When that succeeds, their friendship must be updated to no-record again;
+ When the button is changed to no_record, the add friends button should be displayed again
+ */
+export const handleFriendUnfriend = async (
+ screenType: ScreenType,
+ user: UserType,
+ profile: ProfileType,
+ dispatch: AppDispatch,
+ state: RootState,
+ loggedInUser: UserType,
+) => {
+ const {friendship_status} = profile;
+ await dispatch(
+ friendUnfriendUser(
+ loggedInUser,
+ getUserAsProfilePreviewType(user, profile),
+ friendship_status,
+ screenType,
+ ),
+ );
+ await dispatch(updateUserXFriends(user.userId, state));
+ dispatch(updateUserXProfileAllScreens(user.userId, state));
+};
+
+/*
+ * When user logged in clicks on the friend button:
+ A request is sent.
+ Which means you have to update the status of their friendshpi to requested
+ When the status is changed to requested the button should change to requested.
+ When the button is changed to requested and thr user clicks on it,
+ a request much go to the backend to delete that request
+ When that succeeds, their friendship must be updated to no-record again;
+ When the button is changed to no_record, the add friends button should be displayed again
+ */
+export const handleUnfriend = async (
+ screenType: ScreenType,
+ friend: ProfilePreviewType,
+ dispatch: AppDispatch,
+ state: RootState,
+) => {
+ await dispatch(unfriendUser(friend, screenType));
+ await dispatch(updateUserXFriends(friend.id, state));
+};
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 629a0091..82c94100 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -2,3 +2,4 @@ export * from './layouts';
export * from './moments';
export * from './common';
export * from './users';
+export * from './friends';