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/CommentsContainer.tsx | |
parent | 951d85348acef13ec7830629205c30ad5f766bee (diff) | |
parent | 7a09cc96bf1fe468a612bb44362bbef24fccc773 (diff) |
Merge branch 'master' into TMA-546-Onboarding-Page
Diffstat (limited to 'src/components/comments/CommentsContainer.tsx')
-rw-r--r-- | src/components/comments/CommentsContainer.tsx | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx new file mode 100644 index 00000000..c72da2b7 --- /dev/null +++ b/src/components/comments/CommentsContainer.tsx @@ -0,0 +1,171 @@ +import React, {useEffect, useRef, useState} from 'react'; +import {StyleSheet} from 'react-native'; +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'; +export type CommentsContainerProps = { + screenType: ScreenType; + //objectId can be either moment_id or comment_id + objectId: string; + commentId?: string; + setCommentsLength?: (count: number) => void; + newCommentsAvailable: boolean; + setNewCommentsAvailable: (value: boolean) => void; + typeOfComment: TypeOfComment; + setCommentObjectInFocus?: (comment: CommentType | undefined) => void; + commentObjectInFocus?: CommentType; +}; + +/** + * Comments Container to be used for both comments and replies + */ + +const CommentsContainer: React.FC<CommentsContainerProps> = ({ + screenType, + objectId, + setCommentsLength, + newCommentsAvailable, + setNewCommentsAvailable, + typeOfComment, + setCommentObjectInFocus, + commentObjectInFocus, + commentId, +}) => { + const {username: loggedInUsername} = useSelector( + (state: RootState) => state.user.user, + ); + const [commentsList, setCommentsList] = useState<CommentType[]>([]); + const dispatch = useDispatch(); + const ref = useRef<FlatList<CommentType>>(null); + + useEffect(() => { + const loadComments = async () => { + 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(); + } + return () => { + subscribedToLoadComments = false; + }; + }, [ + dispatch, + objectId, + newCommentsAvailable, + setNewCommentsAvailable, + setCommentsLength, + typeOfComment, + ]); + + // 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 + key={item.comment_id} + comment_object={item} + screenType={screenType} + typeOfComment={typeOfComment} + setCommentObjectInFocus={setCommentObjectInFocus} + newCommentsAvailable={newCommentsAvailable} + setNewCommentsAvailable={setNewCommentsAvailable} + canDelete={item.commenter.username === loggedInUsername} + /> + ); + + return ( + <FlatList + data={commentsList} + ref={ref} + keyExtractor={(item, index) => index.toString()} + decelerationRate={'fast'} + snapToAlignment={'start'} + snapToInterval={ITEM_HEIGHT} + renderItem={renderComment} + showsVerticalScrollIndicator={false} + contentContainerStyle={styles.scrollViewContent} + getItemLayout={(data, index) => ({ + length: ITEM_HEIGHT, + offset: ITEM_HEIGHT * index, + index, + })} + pagingEnabled + /> + ); +}; + +const styles = StyleSheet.create({ + scrollView: {}, + scrollViewContent: { + justifyContent: 'center', + }, +}); + +export default CommentsContainer; |