aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Chen <ivan@tagg.id>2021-05-27 11:41:09 -0400
committerGitHub <noreply@github.com>2021-05-27 11:41:09 -0400
commitb355c8702ac6271891986db12645ac5524fbdfd4 (patch)
treeb7a107de8d0c06a73a67df606556819b98b281d6 /src
parent30d50980a4af62876a6665e51158239a018d0ba2 (diff)
parent907e8fb4c12b53448e22d230d62dd42b9b1c93ed (diff)
Merge pull request #450 from shravyaramesh/tma885-remove-tag-drawer
[TMA-885] Remove tag bottom drawer
Diffstat (limited to 'src')
-rw-r--r--src/components/moments/MomentPost.tsx122
-rw-r--r--src/components/moments/MomentPostContent.tsx16
-rw-r--r--src/components/moments/MomentPostHeader.tsx6
-rw-r--r--src/components/moments/index.ts1
-rw-r--r--src/components/profile/MomentMoreInfoDrawer.tsx105
-rw-r--r--src/screens/profile/IndividualMoment.tsx39
-rw-r--r--src/services/MomentService.ts16
7 files changed, 242 insertions, 63 deletions
diff --git a/src/components/moments/MomentPost.tsx b/src/components/moments/MomentPost.tsx
new file mode 100644
index 00000000..7149a5b4
--- /dev/null
+++ b/src/components/moments/MomentPost.tsx
@@ -0,0 +1,122 @@
+import React, {useEffect, useState} from 'react';
+import {StyleSheet, View} from 'react-native';
+import {useSelector} from 'react-redux';
+import {MomentPostContent, MomentPostHeader} from '.';
+import {deleteMomentTag, loadMomentTags} from '../../services';
+import {RootState} from '../../store/rootReducer';
+import {MomentTagType, MomentType, ScreenType} from '../../types';
+import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
+
+interface MomentPostProps {
+ item: MomentType;
+ userXId: string | undefined;
+ screenType: ScreenType;
+}
+
+const ITEM_HEIGHT = SCREEN_HEIGHT * 0.9;
+
+const MomentPost: React.FC<MomentPostProps> = ({item, userXId, screenType}) => {
+ const {userId: loggedInUserId, username: loggedInUsername} = useSelector(
+ (state: RootState) => state.user.user,
+ );
+
+ const {
+ user: {username},
+ } = useSelector((state: RootState) =>
+ userXId ? state.userX[screenType][userXId] : state.user,
+ );
+ const [tags, setTags] = useState<MomentTagType[]>([]);
+ const [momentTagId, setMomentTagId] = useState<string>('');
+
+ const isOwnProfile = username === loggedInUsername;
+
+ const loadTags = async () => {
+ const response = await loadMomentTags(item.moment_id);
+ setTags(response ? response : []);
+ };
+
+ /*
+ * Load tags on initial render to pass tags data to moment header and content
+ */
+ useEffect(() => {
+ loadTags();
+ }, []);
+
+ /*
+ * Check if loggedInUser has been tagged in the picture and set the id
+ */
+ useEffect(() => {
+ const getMomentTagId = () => {
+ const ownTag: MomentTagType[] = tags.filter(
+ (tag) => tag.user.id === loggedInUserId,
+ );
+ if (ownTag?.length > 0) {
+ setMomentTagId(ownTag[0].id);
+ } else {
+ setMomentTagId('');
+ }
+ };
+ getMomentTagId();
+ }, [tags]);
+
+ /*
+ * Remove tag and update the current tags
+ */
+ const removeTag = async () => {
+ const success = await deleteMomentTag(momentTagId);
+ if (success) {
+ const filteredTags = tags.filter((tag) => tag.user.id !== loggedInUserId);
+ setTags(filteredTags);
+ }
+ };
+
+ return (
+ <View style={styles.postContainer}>
+ <MomentPostHeader
+ userXId={userXId}
+ screenType={screenType}
+ username={isOwnProfile ? loggedInUsername : username}
+ momentId={item.moment_id}
+ style={styles.postHeader}
+ momentTagId={momentTagId}
+ removeTag={removeTag}
+ />
+ <MomentPostContent
+ style={styles.postContent}
+ momentId={item.moment_id}
+ caption={item.caption}
+ pathHash={item.moment_url}
+ dateTime={item.date_created}
+ screenType={screenType}
+ momentTags={tags}
+ />
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ contentContainer: {
+ width: SCREEN_WIDTH,
+ height: SCREEN_HEIGHT,
+ paddingTop: StatusBarHeight,
+ flex: 1,
+ paddingBottom: 0,
+ },
+ content: {
+ flex: 9,
+ },
+ header: {
+ flex: 1,
+ },
+ postContainer: {
+ height: ITEM_HEIGHT,
+ width: SCREEN_WIDTH,
+ flex: 1,
+ },
+ postHeader: {
+ flex: 1,
+ },
+ postContent: {flex: 9},
+});
+
+export default MomentPost;
diff --git a/src/components/moments/MomentPostContent.tsx b/src/components/moments/MomentPostContent.tsx
index 56d317d7..f485396f 100644
--- a/src/components/moments/MomentPostContent.tsx
+++ b/src/components/moments/MomentPostContent.tsx
@@ -4,7 +4,7 @@ import {Image, StyleSheet, Text, View, ViewProps} from 'react-native';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import Animated, {Easing} from 'react-native-reanimated';
import {useDispatch, useStore} from 'react-redux';
-import {getCommentsCount, loadMomentTags} from '../../services';
+import {getCommentsCount} from '../../services';
import {RootState} from '../../store/rootReducer';
import {MomentTagType, ScreenType, UserType} from '../../types';
import {
@@ -24,6 +24,7 @@ interface MomentPostContentProps extends ViewProps {
caption: string;
pathHash: string;
dateTime: string;
+ momentTags: MomentTagType[];
}
const MomentPostContent: React.FC<MomentPostContentProps> = ({
screenType,
@@ -32,10 +33,11 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
pathHash,
dateTime,
style,
+ momentTags,
}) => {
const [elapsedTime, setElapsedTime] = useState('');
const [comments_count, setCommentsCount] = useState('');
- const [tags, setTags] = useState<MomentTagType[]>([]);
+ const [tags, setTags] = useState<MomentTagType[]>(momentTags);
const [visible, setVisible] = useState(false);
const state: RootState = useStore().getState();
const navigation = useNavigation();
@@ -49,14 +51,8 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
);
useEffect(() => {
- const loadTags = async () => {
- const response = await loadMomentTags(momentId);
- if (response) {
- setTags(response);
- }
- };
- loadTags();
- }, []);
+ setTags(momentTags);
+ }, [momentTags]);
useEffect(() => {
const fetchCommentsCount = async () => {
diff --git a/src/components/moments/MomentPostHeader.tsx b/src/components/moments/MomentPostHeader.tsx
index 3c3ee4c3..dc6a3cd9 100644
--- a/src/components/moments/MomentPostHeader.tsx
+++ b/src/components/moments/MomentPostHeader.tsx
@@ -20,6 +20,8 @@ interface MomentPostHeaderProps extends ViewProps {
screenType: ScreenType;
username: string;
momentId: string;
+ momentTagId: string;
+ removeTag: () => Promise<void>;
}
const MomentPostHeader: React.FC<MomentPostHeaderProps> = ({
@@ -28,6 +30,8 @@ const MomentPostHeader: React.FC<MomentPostHeaderProps> = ({
username,
momentId,
style,
+ momentTagId,
+ removeTag,
}) => {
const [drawerVisible, setDrawerVisible] = useState(false);
const dispatch = useDispatch();
@@ -66,6 +70,8 @@ const MomentPostHeader: React.FC<MomentPostHeaderProps> = ({
setIsOpen={setDrawerVisible}
momentId={momentId}
isOwnProfile={isOwnProfile}
+ momentTagId={momentTagId}
+ removeTag={removeTag}
dismissScreenAndUpdate={() => {
dispatch(loadUserMoments(loggedInUserId));
navigation.pop();
diff --git a/src/components/moments/index.ts b/src/components/moments/index.ts
index 6af29bc5..c1419cfd 100644
--- a/src/components/moments/index.ts
+++ b/src/components/moments/index.ts
@@ -4,3 +4,4 @@ export {default as MomentPostHeader} from './MomentPostHeader';
export {default as MomentPostContent} from './MomentPostContent';
export {default as Moment} from './Moment';
export {default as TagFriendsFooter} from './TagFriendsFoooter';
+export {default as MomentPost} from './MomentPost';
diff --git a/src/components/profile/MomentMoreInfoDrawer.tsx b/src/components/profile/MomentMoreInfoDrawer.tsx
index 77c349ca..1265497e 100644
--- a/src/components/profile/MomentMoreInfoDrawer.tsx
+++ b/src/components/profile/MomentMoreInfoDrawer.tsx
@@ -1,20 +1,40 @@
-import React from 'react';
-import {Alert, StyleSheet, TouchableOpacity, ViewProps} from 'react-native';
+import React, {useEffect, useState} from 'react';
+import {
+ Alert,
+ GestureResponderEvent,
+ StyleSheet,
+ TouchableOpacity,
+ ViewProps,
+} from 'react-native';
import MoreIcon from '../../assets/icons/more_horiz-24px.svg';
import {ERROR_DELETE_MOMENT, MOMENT_DELETED_MSG} from '../../constants/strings';
import {deleteMoment, sendReport} from '../../services';
import {GenericMoreInfoDrawer} from '../common';
+enum MomentDrawerOptions {
+ DeleteMoment = 'Delete Moment',
+ ReportIssue = 'Report an Issue',
+ RemoveTag = 'Remove yourself from moment',
+}
interface MomentMoreInfoDrawerProps extends ViewProps {
isOpen: boolean;
setIsOpen: (visible: boolean) => void;
momentId: string;
isOwnProfile: boolean;
+ momentTagId: string;
+ removeTag: () => Promise<void>;
dismissScreenAndUpdate: () => void;
}
const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
- const {momentId, setIsOpen, isOwnProfile, dismissScreenAndUpdate} = props;
+ const {
+ momentId,
+ setIsOpen,
+ isOwnProfile,
+ dismissScreenAndUpdate,
+ momentTagId,
+ removeTag,
+ } = props;
const handleDeleteMoment = async () => {
setIsOpen(false);
@@ -38,6 +58,27 @@ const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
});
};
+ const handleRemoveTag = async () => {
+ setIsOpen(false);
+ setTimeout(() => {
+ Alert.alert(
+ MomentDrawerOptions.RemoveTag,
+ 'Are you sure you want to be removed from this moment?',
+ [
+ {
+ text: 'Remove',
+ onPress: removeTag,
+ },
+ {
+ text: 'Cancel',
+ style: 'cancel',
+ },
+ ],
+ {cancelable: false},
+ );
+ }, 500);
+ };
+
const handleReportMoment = async () => {
setIsOpen(false);
setTimeout(() => {
@@ -63,6 +104,43 @@ const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
}, 500);
};
+ const [drawerButtons, setDrawerButtons] = useState<
+ [string, (event: GestureResponderEvent) => void, JSX.Element?][]
+ >([
+ isOwnProfile
+ ? [MomentDrawerOptions.DeleteMoment, handleDeleteMoment]
+ : [MomentDrawerOptions.ReportIssue, handleReportMoment],
+ ]);
+
+ /*
+ * Update bottom drawer options to contain/not contain 'remove tag' option
+ */
+ useEffect(() => {
+ const setupBottomDrawer = () => {
+ const present = drawerButtons.findIndex(
+ (button) => button[0] === MomentDrawerOptions.RemoveTag,
+ );
+ /*
+ * If user is not tagged but button is present, remove button from bottom drawer
+ * If user is tagged but button is not present, add button to bottom drawer
+ */
+ if (momentTagId !== '' && present === -1) {
+ const localDrawerButtons = drawerButtons;
+ localDrawerButtons.push([
+ MomentDrawerOptions.RemoveTag,
+ handleRemoveTag,
+ ]);
+ setDrawerButtons(localDrawerButtons);
+ } else if (momentTagId === '' && present !== -1) {
+ const filteredButtons = drawerButtons.filter(
+ (button) => button[0] !== MomentDrawerOptions.RemoveTag,
+ );
+ setDrawerButtons(filteredButtons);
+ }
+ };
+ setupBottomDrawer();
+ }, [momentTagId]);
+
return (
<>
<TouchableOpacity
@@ -72,21 +150,12 @@ const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
}}>
<MoreIcon height={30} width={30} color={'white'} />
</TouchableOpacity>
- {isOwnProfile ? (
- <GenericMoreInfoDrawer
- {...props}
- showIcons={false}
- textColor={'red'}
- buttons={[['Delete Moment', handleDeleteMoment]]}
- />
- ) : (
- <GenericMoreInfoDrawer
- {...props}
- showIcons={false}
- textColor={'red'}
- buttons={[['Report an Issue', handleReportMoment]]}
- />
- )}
+ <GenericMoreInfoDrawer
+ {...props}
+ showIcons={false}
+ textColor={'red'}
+ buttons={drawerButtons}
+ />
</>
);
};
diff --git a/src/screens/profile/IndividualMoment.tsx b/src/screens/profile/IndividualMoment.tsx
index 515cbacf..4ad4515d 100644
--- a/src/screens/profile/IndividualMoment.tsx
+++ b/src/screens/profile/IndividualMoment.tsx
@@ -4,11 +4,7 @@ import {StackNavigationProp} from '@react-navigation/stack';
import React from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {useSelector} from 'react-redux';
-import {
- IndividualMomentTitleBar,
- MomentPostContent,
- MomentPostHeader,
-} from '../../components';
+import {IndividualMomentTitleBar, MomentPost} from '../../components';
import {MainStackParams} from '../../routes';
import {RootState} from '../../store/rootreducer';
import {MomentType} from '../../types';
@@ -35,45 +31,16 @@ const IndividualMoment: React.FC<IndividualMomentProps> = ({
}) => {
const {moment_category, moment_id} = route.params.moment;
const {userXId, screenType} = route.params;
- const {username: loggedInUsername} = useSelector(
- (state: RootState) => state.user.user,
- );
- const {
- user: {username},
- } = useSelector((state: RootState) =>
- userXId ? state.userX[screenType][userXId] : state.user,
- );
const {moments} = useSelector((state: RootState) =>
userXId ? state.userX[screenType][userXId] : state.moments,
);
- const isOwnProfile = username === loggedInUsername;
const momentData = moments.filter(
(m) => m.moment_category === moment_category,
);
const initialIndex = momentData.findIndex((m) => m.moment_id === moment_id);
- const renderMomentPost = ({item}: {item: MomentType}) => (
- <View style={styles.postContainer}>
- <MomentPostHeader
- userXId={userXId}
- screenType={screenType}
- username={isOwnProfile ? loggedInUsername : username}
- momentId={item.moment_id}
- style={styles.postHeader}
- />
- <MomentPostContent
- style={styles.postContent}
- momentId={item.moment_id}
- caption={item.caption}
- pathHash={item.moment_url}
- dateTime={item.date_created}
- screenType={screenType}
- />
- </View>
- );
-
return (
<BlurView
blurType="light"
@@ -88,7 +55,9 @@ const IndividualMoment: React.FC<IndividualMomentProps> = ({
<View style={styles.content}>
<FlatList
data={momentData}
- renderItem={renderMomentPost}
+ renderItem={({item}: {item: MomentType}) => (
+ <MomentPost userXId={userXId} screenType={screenType} item={item} />
+ )}
keyExtractor={(item, index) => index.toString()}
showsVerticalScrollIndicator={false}
snapToAlignment={'start'}
diff --git a/src/services/MomentService.ts b/src/services/MomentService.ts
index 423d962c..af602dc7 100644
--- a/src/services/MomentService.ts
+++ b/src/services/MomentService.ts
@@ -169,3 +169,19 @@ export const postMomentTags = async (
return false;
}
};
+
+export const deleteMomentTag = async (moment_tag_id: string) => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ const response = await fetch(MOMENTTAG_ENDPOINT + `${moment_tag_id}/`, {
+ method: 'DELETE',
+ headers: {
+ Authorization: 'Token ' + token,
+ },
+ });
+ return response.status === 200;
+ } catch (error) {
+ console.error(error);
+ return false;
+ }
+};