aboutsummaryrefslogtreecommitdiff
path: root/src/components/comments/CommentTile.tsx
diff options
context:
space:
mode:
authorIvan Chen <ivan@tagg.id>2021-02-01 16:01:03 -0500
committerIvan Chen <ivan@tagg.id>2021-02-01 16:01:03 -0500
commit8d1013e86cf2d66671c337d49a80da157802ad86 (patch)
tree656b1656068bb6636919359d4faaf7051994ff74 /src/components/comments/CommentTile.tsx
parent951d85348acef13ec7830629205c30ad5f766bee (diff)
parent7a09cc96bf1fe468a612bb44362bbef24fccc773 (diff)
Merge branch 'master' into TMA-546-Onboarding-Page
Diffstat (limited to 'src/components/comments/CommentTile.tsx')
-rw-r--r--src/components/comments/CommentTile.tsx261
1 files changed, 233 insertions, 28 deletions
diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
index 47f25a53..be113523 100644
--- a/src/components/comments/CommentTile.tsx
+++ b/src/components/comments/CommentTile.tsx
@@ -1,10 +1,21 @@
-import React from 'react';
+/* eslint-disable radix */
+import React, {Fragment, useEffect, useRef, useState} from 'react';
import {Text, View} from 'react-native-animatable';
import {ProfilePreview} from '../profile';
-import {CommentType, ScreenType} from '../../types';
-import {StyleSheet} from 'react-native';
-import {getTimePosted} from '../../utils';
+import {CommentType, ScreenType, TypeOfComment} from '../../types';
+import {Alert, Animated, StyleSheet} from 'react-native';
import ClockIcon from '../../assets/icons/clock-icon-01.svg';
+import {TAGG_LIGHT_BLUE} from '../../constants';
+import {RectButton, TouchableOpacity} from 'react-native-gesture-handler';
+import {getTimePosted, normalize, SCREEN_WIDTH} from '../../utils';
+import Arrow from '../../assets/icons/back-arrow-colored.svg';
+import Trash from '../../assets/ionicons/trash-outline.svg';
+import CommentsContainer from './CommentsContainer';
+import Swipeable from 'react-native-gesture-handler/Swipeable';
+import {deleteComment, getCommentsCount} from '../../services';
+import {ERROR_FAILED_TO_DELETE_COMMENT} from '../../constants/strings';
+import {useSelector} from 'react-redux';
+import {RootState} from '../../store/rootReducer';
/**
* Displays users's profile picture, comment posted by them and the time difference between now and when a comment was posted.
@@ -13,54 +24,205 @@ import ClockIcon from '../../assets/icons/clock-icon-01.svg';
interface CommentTileProps {
comment_object: CommentType;
screenType: ScreenType;
+ typeOfComment: TypeOfComment;
+ setCommentObjectInFocus?: (comment: CommentType | undefined) => void;
+ newCommentsAvailable: boolean;
+ setNewCommentsAvailable: (available: boolean) => void;
+ canDelete: boolean;
}
const CommentTile: React.FC<CommentTileProps> = ({
comment_object,
screenType,
+ typeOfComment,
+ setCommentObjectInFocus,
+ newCommentsAvailable,
+ setNewCommentsAvailable,
+ canDelete,
}) => {
const timePosted = getTimePosted(comment_object.date_created);
+ const [showReplies, setShowReplies] = useState<boolean>(false);
+ const [showKeyboard, setShowKeyboard] = useState<boolean>(false);
+ const [newThreadAvailable, setNewThreadAvailable] = useState(true);
+ const swipeRef = useRef<Swipeable>(null);
+ const isThread = typeOfComment === 'Thread';
+
+ const {replyPosted} = useSelector((state: RootState) => state.user);
+
+ /**
+ * Bubbling up, for handling a new comment in a thread.
+ */
+ useEffect(() => {
+ if (newCommentsAvailable) {
+ setNewThreadAvailable(true);
+ }
+ }, [newCommentsAvailable]);
+
+ useEffect(() => {
+ if (replyPosted && typeOfComment === 'Comment') {
+ if (replyPosted.parent_comment.comment_id === comment_object.comment_id) {
+ setShowReplies(true);
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [replyPosted]);
+
+ /**
+ * Case : A COMMENT IS IN FOCUS && REPLY SECTION IS HIDDEN
+ * Bring the current comment to focus
+ * Case : No COMMENT IS IN FOCUS && REPLY SECTION IS SHOWN
+ * Unfocus comment in focus
+ */
+ const toggleAddComment = () => {
+ //Do not allow user to reply to a thread
+ if (!isThread) {
+ if (setCommentObjectInFocus) {
+ if (!showKeyboard) {
+ setCommentObjectInFocus(comment_object);
+ } else {
+ setCommentObjectInFocus(undefined);
+ }
+ }
+ setShowKeyboard(!showKeyboard);
+ }
+ };
+
+ const toggleReplies = async () => {
+ if (showReplies) {
+ //To update count of replies in case we deleted a reply
+ comment_object.replies_count = parseInt(
+ await getCommentsCount(comment_object.comment_id, true),
+ );
+ }
+ setNewThreadAvailable(true);
+ setShowReplies(!showReplies);
+ };
+
+ /**
+ * Method to compute text to be shown for replies button
+ */
+ const getRepliesText = () =>
+ showReplies
+ ? 'Hide'
+ : comment_object.replies_count > 0
+ ? `Replies (${comment_object.replies_count})`
+ : 'Replies';
+
+ const renderRightAction = (text: string, color: string, progress) => {
+ const pressHandler = async () => {
+ swipeRef.current?.close();
+ const success = await deleteComment(comment_object.comment_id, isThread);
+ if (success) {
+ setNewCommentsAvailable(true);
+ } else {
+ Alert.alert(ERROR_FAILED_TO_DELETE_COMMENT);
+ }
+ };
+ return (
+ <Animated.View>
+ <RectButton
+ style={[styles.rightAction, {backgroundColor: color}]}
+ onPress={pressHandler}>
+ <Trash width={normalize(25)} height={normalize(25)} color={'white'} />
+ <Text style={styles.actionText}>{text}</Text>
+ </RectButton>
+ </Animated.View>
+ );
+ };
+
+ const renderRightActions = (progress: Animated.AnimatedInterpolation) =>
+ canDelete ? (
+ <View style={styles.swipeActions}>
+ {renderRightAction('Delete', '#c42634', progress)}
+ </View>
+ ) : (
+ <Fragment />
+ );
+
return (
- <View style={styles.container}>
- <ProfilePreview
- profilePreview={{
- id: comment_object.commenter.id,
- username: comment_object.commenter.username,
- first_name: comment_object.commenter.first_name,
- last_name: comment_object.commenter.last_name,
- }}
- previewType={'Comment'}
- screenType={screenType}
- />
- <View style={styles.body}>
- <Text style={styles.comment}>{comment_object.comment}</Text>
- <View style={styles.clockIconAndTime}>
- <ClockIcon style={styles.clockIcon} />
- <Text style={styles.date_time}>{' ' + timePosted}</Text>
- </View>
+ <Swipeable
+ ref={swipeRef}
+ renderRightActions={renderRightActions}
+ rightThreshold={40}
+ friction={2}
+ containerStyle={styles.swipableContainer}>
+ <View
+ style={[styles.container, isThread ? styles.moreMarginWithThread : {}]}>
+ <ProfilePreview
+ profilePreview={comment_object.commenter}
+ previewType={'Comment'}
+ screenType={screenType}
+ />
+ <TouchableOpacity style={styles.body} onPress={toggleAddComment}>
+ <Text style={styles.comment}>{comment_object.comment}</Text>
+ <View style={styles.clockIconAndTime}>
+ <ClockIcon style={styles.clockIcon} />
+ <Text style={styles.date_time}>{' ' + timePosted}</Text>
+ <View style={styles.flexer} />
+ </View>
+ </TouchableOpacity>
+ {/*** Show replies text only if there are some replies present */}
+ {typeOfComment === 'Comment' && comment_object.replies_count > 0 && (
+ <TouchableOpacity
+ style={styles.repliesTextAndIconContainer}
+ onPress={toggleReplies}>
+ <Text style={styles.repliesText}>{getRepliesText()}</Text>
+ <Arrow
+ width={12}
+ height={11}
+ color={TAGG_LIGHT_BLUE}
+ style={
+ !showReplies ? styles.repliesDownArrow : styles.repliesUpArrow
+ }
+ />
+ </TouchableOpacity>
+ )}
</View>
- </View>
+
+ {/*** Show replies if toggle state is true */}
+ {showReplies && (
+ <View>
+ <CommentsContainer
+ objectId={comment_object.comment_id}
+ screenType={screenType}
+ setNewCommentsAvailable={setNewThreadAvailable}
+ newCommentsAvailable={newThreadAvailable}
+ typeOfComment={'Thread'}
+ commentId={replyPosted?.comment_id}
+ />
+ </View>
+ )}
+ </Swipeable>
);
};
const styles = StyleSheet.create({
container: {
- marginLeft: '3%',
- marginRight: '3%',
borderBottomWidth: 1,
borderColor: 'lightgray',
- marginBottom: '3%',
+ backgroundColor: 'white',
+ flexDirection: 'column',
+ flex: 1,
+ paddingTop: '3%',
+ paddingBottom: '5%',
+ marginLeft: '7%',
+ },
+ swipeActions: {
+ flexDirection: 'row',
+ },
+ moreMarginWithThread: {
+ marginLeft: '14%',
},
body: {
marginLeft: 56,
},
comment: {
- position: 'relative',
- top: -5,
marginBottom: '2%',
+ marginRight: '2%',
},
date_time: {
color: 'gray',
+ fontSize: normalize(12),
},
clockIcon: {
width: 12,
@@ -69,7 +231,50 @@ const styles = StyleSheet.create({
},
clockIconAndTime: {
flexDirection: 'row',
- marginBottom: '3%',
+ marginTop: '3%',
+ },
+ flexer: {
+ flex: 1,
+ },
+ repliesTextAndIconContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginTop: '5%',
+ marginLeft: 56,
+ },
+ repliesText: {
+ color: TAGG_LIGHT_BLUE,
+ fontWeight: '500',
+ fontSize: normalize(12),
+ marginRight: '1%',
+ },
+ repliesBody: {
+ width: SCREEN_WIDTH,
+ },
+ repliesDownArrow: {
+ transform: [{rotate: '270deg'}],
+ marginTop: '1%',
+ },
+ repliesUpArrow: {
+ transform: [{rotate: '90deg'}],
+ marginTop: '1%',
+ },
+ actionText: {
+ color: 'white',
+ fontSize: normalize(12),
+ fontWeight: '500',
+ backgroundColor: 'transparent',
+ paddingHorizontal: '5%',
+ marginTop: '5%',
+ },
+ rightAction: {
+ alignItems: 'center',
+ flex: 1,
+ justifyContent: 'center',
+ flexDirection: 'column',
+ },
+ swipableContainer: {
+ backgroundColor: 'white',
},
});