diff options
author | Ivan Chen <ivan@tagg.id> | 2021-02-01 16:01:03 -0500 |
---|---|---|
committer | Ivan Chen <ivan@tagg.id> | 2021-02-01 16:01:03 -0500 |
commit | 8d1013e86cf2d66671c337d49a80da157802ad86 (patch) | |
tree | 656b1656068bb6636919359d4faaf7051994ff74 /src/components/comments/CommentTile.tsx | |
parent | 951d85348acef13ec7830629205c30ad5f766bee (diff) | |
parent | 7a09cc96bf1fe468a612bb44362bbef24fccc773 (diff) |
Merge branch 'master' into TMA-546-Onboarding-Page
Diffstat (limited to 'src/components/comments/CommentTile.tsx')
-rw-r--r-- | src/components/comments/CommentTile.tsx | 261 |
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', }, }); |