diff options
Diffstat (limited to 'src/components/comments')
-rw-r--r-- | src/components/comments/AddComment.tsx | 16 | ||||
-rw-r--r-- | src/components/comments/CommentTile.tsx | 114 | ||||
-rw-r--r-- | src/components/comments/CommentsContainer.tsx | 97 |
3 files changed, 149 insertions, 78 deletions
diff --git a/src/components/comments/AddComment.tsx b/src/components/comments/AddComment.tsx index 44f49748..56011f05 100644 --- a/src/components/comments/AddComment.tsx +++ b/src/components/comments/AddComment.tsx @@ -8,10 +8,11 @@ import { View, } from 'react-native'; import {TextInput, TouchableOpacity} from 'react-native-gesture-handler'; -import {useSelector} from 'react-redux'; +import {useDispatch, useSelector} from 'react-redux'; import UpArrowIcon from '../../assets/icons/up_arrow.svg'; import {TAGG_LIGHT_BLUE} from '../../constants'; import {postComment} from '../../services'; +import {updateReplyPosted} from '../../store/actions'; import {RootState} from '../../store/rootreducer'; import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; @@ -38,6 +39,7 @@ const AddComment: React.FC<AddCommentProps> = ({ const [keyboardVisible, setKeyboardVisible] = React.useState(false); const {avatar} = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); const addComment = async () => { const trimmed = comment.trim(); @@ -52,6 +54,18 @@ const AddComment: React.FC<AddCommentProps> = ({ if (postedComment) { setComment(''); + + //Set new reply posted object + //This helps us show the latest reply on top + //Data set is kind of stale but it works + if (isCommentInFocus) { + dispatch( + updateReplyPosted({ + comment_id: postedComment.comment_id, + parent_comment: {comment_id: objectId}, + }), + ); + } setNewCommentsAvailable(true); } }; diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx index e775a609..be113523 100644 --- a/src/components/comments/CommentTile.tsx +++ b/src/components/comments/CommentTile.tsx @@ -1,3 +1,4 @@ +/* eslint-disable radix */ import React, {Fragment, useEffect, useRef, useState} from 'react'; import {Text, View} from 'react-native-animatable'; import {ProfilePreview} from '../profile'; @@ -6,19 +7,15 @@ 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_HEIGHT, - SCREEN_WIDTH, -} from '../../utils'; +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} from '../../services'; +import {deleteComment, getCommentsCount} from '../../services'; import {ERROR_FAILED_TO_DELETE_COMMENT} from '../../constants/strings'; -import {min} from 'moment'; +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. @@ -45,10 +42,13 @@ const CommentTile: React.FC<CommentTileProps> = ({ }) => { 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. */ @@ -58,23 +58,43 @@ const CommentTile: React.FC<CommentTileProps> = ({ } }, [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 - * In any case toggle value of showReplies */ - const toggleReplies = () => { - if (setCommentObjectInFocus) { - if (!showReplies) { - setCommentObjectInFocus(comment_object); - } else { - setNewThreadAvailable(true); - setNewCommentsAvailable(true); - setCommentObjectInFocus(undefined); + 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); }; @@ -110,7 +130,7 @@ const CommentTile: React.FC<CommentTileProps> = ({ ); }; - const renderRightActions = (progress) => + const renderRightActions = (progress: Animated.AnimatedInterpolation) => canDelete ? ( <View style={styles.swipeActions}> {renderRightAction('Delete', '#c42634', progress)} @@ -133,48 +153,42 @@ const CommentTile: React.FC<CommentTileProps> = ({ previewType={'Comment'} screenType={screenType} /> - <TouchableOpacity style={styles.body} onPress={toggleReplies}> + <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} /> - - {/*** Show replies text only if there are some replies present */} - {typeOfComment === 'Comment' && comment_object.replies_count > 0 && ( - <View style={styles.repliesTextAndIconContainer}> - <Text style={styles.repliesText}>{getRepliesText()}</Text> - <Arrow - width={12} - height={11} - color={TAGG_LIGHT_BLUE} - style={ - !showReplies - ? styles.repliesDownArrow - : styles.repliesUpArrow - } - /> - </View> - )} </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> {/*** Show replies if toggle state is true */} - {showReplies && comment_object.replies_count > 0 && ( - <View - style={{ - height: Math.min( - SCREEN_HEIGHT / 2.4, - (SCREEN_HEIGHT / 7.5) * comment_object.replies_count, - ), - }}> + {showReplies && ( + <View> <CommentsContainer objectId={comment_object.comment_id} screenType={screenType} setNewCommentsAvailable={setNewThreadAvailable} newCommentsAvailable={newThreadAvailable} typeOfComment={'Thread'} + commentId={replyPosted?.comment_id} /> </View> )} @@ -190,6 +204,7 @@ const styles = StyleSheet.create({ flexDirection: 'column', flex: 1, paddingTop: '3%', + paddingBottom: '5%', marginLeft: '7%', }, swipeActions: { @@ -204,7 +219,6 @@ const styles = StyleSheet.create({ comment: { marginBottom: '2%', marginRight: '2%', - top: -5, }, date_time: { color: 'gray', @@ -217,7 +231,7 @@ const styles = StyleSheet.create({ }, clockIconAndTime: { flexDirection: 'row', - marginBottom: '3%', + marginTop: '3%', }, flexer: { flex: 1, @@ -225,23 +239,25 @@ const styles = StyleSheet.create({ repliesTextAndIconContainer: { flexDirection: 'row', alignItems: 'center', + marginTop: '5%', + marginLeft: 56, }, repliesText: { color: TAGG_LIGHT_BLUE, fontWeight: '500', fontSize: normalize(12), - marginRight: '5%', + marginRight: '1%', }, repliesBody: { width: SCREEN_WIDTH, }, repliesDownArrow: { transform: [{rotate: '270deg'}], - marginTop: '7%', + marginTop: '1%', }, repliesUpArrow: { transform: [{rotate: '90deg'}], - marginTop: '7%', + marginTop: '1%', }, actionText: { color: 'white', diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx index a0e94828..c72da2b7 100644 --- a/src/components/comments/CommentsContainer.tsx +++ b/src/components/comments/CommentsContainer.tsx @@ -4,6 +4,7 @@ import {FlatList} from 'react-native-gesture-handler'; import {useDispatch, useSelector} from 'react-redux'; import {CommentTile} from '.'; import {getComments} from '../../services'; +import {updateReplyPosted} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import {CommentType, ScreenType, TypeOfComment} from '../../types'; import {SCREEN_HEIGHT} from '../../utils'; @@ -41,36 +42,28 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({ const [commentsList, setCommentsList] = useState<CommentType[]>([]); const dispatch = useDispatch(); const ref = useRef<FlatList<CommentType>>(null); - const [initialIndex, setInitialIndex] = useState<number>(0); useEffect(() => { - //Scroll only if a new comment and not a reply was posted - const shouldScroll = () => - (typeOfComment === 'Comment' && !commentObjectInFocus) || - typeOfComment === 'Thread'; const loadComments = async () => { - const comments = await getComments(objectId, typeOfComment === 'Thread'); - setCommentsList(comments); - if (setCommentsLength) { - setCommentsLength(comments.length); - } - setNewCommentsAvailable(false); + await getComments(objectId, typeOfComment === 'Thread').then( + (comments) => { + if (comments && subscribedToLoadComments) { + setCommentsList(comments); + if (setCommentsLength) { + setCommentsLength(comments.length); + } + setNewCommentsAvailable(false); + } + }, + ); }; + let subscribedToLoadComments = true; if (newCommentsAvailable) { loadComments(); - if (shouldScroll()) { - if (commentId) { - const index = commentsList.findIndex( - (item) => item.comment_id === commentId, - ); - setInitialIndex(index); - } else { - setTimeout(() => { - ref.current?.scrollToEnd({animated: true}); - }, 500); - } - } } + return () => { + subscribedToLoadComments = false; + }; }, [ dispatch, objectId, @@ -78,12 +71,61 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({ setNewCommentsAvailable, setCommentsLength, typeOfComment, - commentObjectInFocus, - commentId, - commentsList, ]); - const ITEM_HEIGHT = SCREEN_HEIGHT / 7.5; + // eslint-disable-next-line no-shadow + const swapCommentTo = (commentId: string, toIndex: number) => { + const index = commentsList.findIndex( + (item) => item.comment_id === commentId, + ); + if (index > 0) { + let comments = [...commentsList]; + const temp = comments[index]; + comments[index] = comments[toIndex]; + comments[toIndex] = temp; + setCommentsList(comments); + } + }; + + useEffect(() => { + //Scroll only if a new comment and not a reply was posted + const shouldScroll = () => + typeOfComment === 'Comment' && !commentObjectInFocus; + + const performAction = () => { + if (commentId) { + swapCommentTo(commentId, 0); + } else if (shouldScroll()) { + setTimeout(() => { + ref.current?.scrollToEnd({animated: true}); + }, 500); + } + }; + if (commentsList) { + //Bring the relevant comment to top if a comment id is present else scroll if necessary + performAction(); + } + + //Clean up the reply id present in store + return () => { + if (commentId && typeOfComment === 'Thread') { + setTimeout(() => { + dispatch(updateReplyPosted(undefined)); + }, 200); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [commentsList, commentId]); + + //WIP : TODO : Bring the comment in focus above the keyboard + // useEffect(() => { + // if (commentObjectInFocus && commentsList.length >= 3) { + // swapCommentTo(commentObjectInFocus.comment_id, 2); + // } + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [commentObjectInFocus]); + + const ITEM_HEIGHT = SCREEN_HEIGHT / 7.0; const renderComment = ({item}: {item: CommentType}) => ( <CommentTile @@ -108,7 +150,6 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({ snapToInterval={ITEM_HEIGHT} renderItem={renderComment} showsVerticalScrollIndicator={false} - initialScrollIndex={initialIndex} contentContainerStyle={styles.scrollViewContent} getItemLayout={(data, index) => ({ length: ITEM_HEIGHT, |