From 3cbfdc6026ef886b7919181b69a2f252723a6bd8 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 27 Jan 2021 14:18:00 -0500
Subject: Squashed commit of the following:

commit 9298f8a31ca25f53d7fb6a0a90af783b9b01f46c
Author: Ashm Walia <ashmwalia@outlook.com>
Date:   Wed Jan 27 09:00:16 2021 -0800

    Removed redundancy

commit 2a93a92521d989664ebb8dfebe011d8df67ad40f
Author: Ashm Walia <ashmwalia@outlook.com>
Date:   Wed Jan 27 08:58:24 2021 -0800

    Sc

commit 2f5f9df6dec1e905f3abf37d124ecd92d0e3a3d9
Author: Ashm Walia <ashmwalia@outlook.com>
Date:   Wed Jan 27 08:29:56 2021 -0800

    Pre-final

commit 85c0f668665696ba8127ee1ea436d10ec0af955f
Author: Ashm Walia <ashmwalia@outlook.com>
Date:   Wed Jan 27 08:24:43 2021 -0800

    Pre-final

commit 755f4f540d3e759ff9ad3bc35c64b6f7fc83998b
Author: Ashm Walia <ashmwalia@outlook.com>
Date:   Mon Jan 25 18:00:44 2021 -0800

    Add provision to show and hide replies
---
 src/components/comments/CommentsContainer.tsx | 97 +++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 src/components/comments/CommentsContainer.tsx

(limited to 'src/components/comments/CommentsContainer.tsx')

diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
new file mode 100644
index 00000000..0a19694b
--- /dev/null
+++ b/src/components/comments/CommentsContainer.tsx
@@ -0,0 +1,97 @@
+import React, {useRef, useEffect, useState} from 'react';
+import {StyleSheet} from 'react-native';
+import {ScrollView} from 'react-native-gesture-handler';
+import {useDispatch} from 'react-redux';
+import {CommentTile} from '.';
+import {getComments} from '../../services';
+import {CommentType, ScreenType, TypeOfComment} from '../../types';
+export type CommentsContainerProps = {
+  screenType: ScreenType;
+
+  //objectId can be either moment_id or comment_id
+  objectId: 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,
+}) => {
+  const [commentsList, setCommentsList] = useState<CommentType[]>([]);
+  const dispatch = useDispatch();
+  const ref = useRef<ScrollView>(null);
+
+  useEffect(() => {
+    //Scroll only if a new comment and not a reply was posted
+    const shouldScroll = () =>
+      typeOfComment === 'Comment' && !commentObjectInFocus;
+    const loadComments = async () => {
+      const comments = await getComments(objectId, typeOfComment === 'Thread');
+      setCommentsList(comments);
+      if (setCommentsLength) {
+        setCommentsLength(comments.length);
+      }
+      setNewCommentsAvailable(false);
+    };
+    if (newCommentsAvailable) {
+      loadComments();
+      if (shouldScroll()) {
+        setTimeout(() => {
+          ref.current?.scrollToEnd();
+        }, 500);
+      }
+    }
+  }, [
+    dispatch,
+    objectId,
+    newCommentsAvailable,
+    setNewCommentsAvailable,
+    setCommentsLength,
+    typeOfComment,
+    commentObjectInFocus,
+  ]);
+
+  return (
+    <ScrollView
+      ref={ref}
+      style={styles.scrollView}
+      contentContainerStyle={styles.scrollViewContent}>
+      {commentsList &&
+        commentsList.map((comment: CommentType) => (
+          <CommentTile
+            key={comment.comment_id}
+            comment_object={comment}
+            screenType={screenType}
+            typeOfComment={typeOfComment}
+            setCommentObjectInFocus={setCommentObjectInFocus}
+          />
+        ))}
+    </ScrollView>
+  );
+};
+
+const styles = StyleSheet.create({
+  scrollView: {
+    paddingHorizontal: 20,
+  },
+  scrollViewContent: {
+    justifyContent: 'center',
+  },
+});
+
+export default CommentsContainer;
-- 
cgit v1.2.3-70-g09d2


From fb69ccebb05d2ec54d85576d23989e7309349830 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 27 Jan 2021 16:15:00 -0500
Subject: finished delete

---
 src/assets/ionicons/trash-outline.svg         |   1 +
 src/components/comments/CommentTile.tsx       | 115 +++++++++++++++++++-------
 src/components/comments/CommentsContainer.tsx |  14 ++--
 src/constants/strings.ts                      |   2 +-
 src/services/CommentService.ts                |  18 ++++
 5 files changed, 114 insertions(+), 36 deletions(-)
 create mode 100644 src/assets/ionicons/trash-outline.svg

(limited to 'src/components/comments/CommentsContainer.tsx')

diff --git a/src/assets/ionicons/trash-outline.svg b/src/assets/ionicons/trash-outline.svg
new file mode 100644
index 00000000..4920b56a
--- /dev/null
+++ b/src/assets/ionicons/trash-outline.svg
@@ -0,0 +1 @@
+<svg xmlns='http://www.w3.org/2000/svg' class='ionicon' viewBox='0 0 512 512'><title>Trash</title><path d='M112 112l20 320c.95 18.49 14.4 32 32 32h184c17.67 0 30.87-13.51 32-32l20-320' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='32'/><path stroke='currentColor' stroke-linecap='round' stroke-miterlimit='10' stroke-width='32' d='M80 112h352'/><path d='M192 112V72h0a23.93 23.93 0 0124-24h80a23.93 23.93 0 0124 24h0v40M256 176v224M184 176l8 224M328 176l-8 224' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='32'/></svg>
\ No newline at end of file
diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
index 39605f2c..e12276a9 100644
--- a/src/components/comments/CommentTile.tsx
+++ b/src/components/comments/CommentTile.tsx
@@ -1,14 +1,18 @@
-import React, {useState} from 'react';
+import React, {Fragment, useRef, useState} from 'react';
 import {Text, View} from 'react-native-animatable';
 import {ProfilePreview} from '../profile';
 import {CommentType, ScreenType, TypeOfComment} from '../../types';
-import {StyleSheet} from 'react-native';
+import {Alert, Animated, StyleSheet} from 'react-native';
 import ClockIcon from '../../assets/icons/clock-icon-01.svg';
 import {TAGG_LIGHT_BLUE} from '../../constants';
-import {TouchableOpacity} from 'react-native-gesture-handler';
+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} from '../../services';
+import {ERROR_FAILED_TO_DELETE_COMMENT} from '../../constants/strings';
 
 /**
  * Displays users's profile picture, comment posted by them and the time difference between now and when a comment was posted.
@@ -19,6 +23,8 @@ interface CommentTileProps {
   screenType: ScreenType;
   typeOfComment: TypeOfComment;
   setCommentObjectInFocus?: (comment: CommentType | undefined) => void;
+  setNewCommentsAvailable: (available: boolean) => void;
+  canDelete: boolean;
 }
 
 const CommentTile: React.FC<CommentTileProps> = ({
@@ -26,9 +32,13 @@ const CommentTile: React.FC<CommentTileProps> = ({
   screenType,
   typeOfComment,
   setCommentObjectInFocus,
+  setNewCommentsAvailable,
+  canDelete,
 }) => {
   const timePosted = getTimePosted(comment_object.date_created);
   const [showReplies, setShowReplies] = useState<boolean>(false);
+  const swipeRef = useRef<Swipeable>(null);
+  const isThread = typeOfComment === 'Thread';
 
   /**
    * Case : A COMMENT IS IN FOCUS && REPLY SECTION IS HIDDEN
@@ -58,13 +68,46 @@ const CommentTile: React.FC<CommentTileProps> = ({
       ? `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) =>
+    canDelete ? (
+      <View style={styles.swipeActions}>
+        {renderRightAction('Delete', '#c42634', progress)}
+      </View>
+    ) : (
+      <Fragment />
+    );
+
   return (
-    <>
+    <Swipeable
+      ref={swipeRef}
+      renderRightActions={renderRightActions}
+      rightThreshold={40}
+      friction={2}
+      containerStyle={styles.swipableContainer}>
       <View
-        style={[
-          styles.container,
-          typeOfComment === 'Thread' ? styles.moreMarginWithThread : {},
-        ]}>
+        style={[styles.container, isThread ? styles.moreMarginWithThread : {}]}>
         <ProfilePreview
           profilePreview={{
             id: comment_object.commenter.id,
@@ -104,40 +147,40 @@ const CommentTile: React.FC<CommentTileProps> = ({
 
       {/*** Show replies if toggle state is true */}
       {showReplies && (
-        <View
-          style={{
-            width: SCREEN_WIDTH,
-          }}>
-          <CommentsContainer
-            objectId={comment_object.comment_id}
-            screenType={screenType}
-            setNewCommentsAvailable={() => {}}
-            newCommentsAvailable={true}
-            typeOfComment={'Thread'}
-          />
-        </View>
+        <CommentsContainer
+          objectId={comment_object.comment_id}
+          screenType={screenType}
+          setNewCommentsAvailable={() => {}}
+          newCommentsAvailable={true}
+          typeOfComment={'Thread'}
+        />
       )}
-    </>
+    </Swipeable>
   );
 };
 
 const styles = StyleSheet.create({
   container: {
-    marginHorizontal: '3%',
     borderBottomWidth: 1,
     borderColor: 'lightgray',
-    marginBottom: '3%',
+    backgroundColor: 'white',
+    paddingTop: '3%',
     flexDirection: 'column',
     flex: 1,
+    marginLeft: '7%',
+  },
+  swipeActions: {
+    flexDirection: 'row',
   },
   moreMarginWithThread: {
-    marginHorizontal: '7%',
+    marginLeft: '14%',
   },
   body: {
     marginLeft: 56,
   },
   comment: {
     marginBottom: '2%',
+    marginRight: '2%',
     top: -5,
   },
   date_time: {
@@ -153,35 +196,47 @@ const styles = StyleSheet.create({
     flexDirection: 'row',
     marginBottom: '3%',
   },
-
   flexer: {
     flex: 1,
   },
-
   repliesTextAndIconContainer: {
     flexDirection: 'row',
     alignItems: 'center',
   },
-
   repliesText: {
     color: TAGG_LIGHT_BLUE,
     fontWeight: '500',
     fontSize: normalize(12),
-    marginRight: '3%',
+    marginRight: '5%',
   },
   repliesBody: {
     width: SCREEN_WIDTH,
   },
-
   repliesDownArrow: {
     transform: [{rotate: '270deg'}],
     marginTop: '7%',
   },
-
   repliesUpArrow: {
     transform: [{rotate: '90deg'}],
     marginTop: '7%',
   },
+  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',
+  },
 });
 
 export default CommentTile;
diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
index 0a19694b..fd4b32af 100644
--- a/src/components/comments/CommentsContainer.tsx
+++ b/src/components/comments/CommentsContainer.tsx
@@ -1,9 +1,10 @@
-import React, {useRef, useEffect, useState} from 'react';
+import React, {useEffect, useRef, useState} from 'react';
 import {StyleSheet} from 'react-native';
 import {ScrollView} from 'react-native-gesture-handler';
-import {useDispatch} from 'react-redux';
+import {useDispatch, useSelector} from 'react-redux';
 import {CommentTile} from '.';
 import {getComments} from '../../services';
+import {RootState} from '../../store/rootReducer';
 import {CommentType, ScreenType, TypeOfComment} from '../../types';
 export type CommentsContainerProps = {
   screenType: ScreenType;
@@ -32,6 +33,9 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
   setCommentObjectInFocus,
   commentObjectInFocus,
 }) => {
+  const {username: loggedInUsername} = useSelector(
+    (state: RootState) => state.user.user,
+  );
   const [commentsList, setCommentsList] = useState<CommentType[]>([]);
   const dispatch = useDispatch();
   const ref = useRef<ScrollView>(null);
@@ -79,6 +83,8 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
             screenType={screenType}
             typeOfComment={typeOfComment}
             setCommentObjectInFocus={setCommentObjectInFocus}
+            setNewCommentsAvailable={setNewCommentsAvailable}
+            canDelete={comment.commenter.username === loggedInUsername}
           />
         ))}
     </ScrollView>
@@ -86,9 +92,7 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
 };
 
 const styles = StyleSheet.create({
-  scrollView: {
-    paddingHorizontal: 20,
-  },
+  scrollView: {},
   scrollViewContent: {
     justifyContent: 'center',
   },
diff --git a/src/constants/strings.ts b/src/constants/strings.ts
index 77ded7be..d3c81622 100644
--- a/src/constants/strings.ts
+++ b/src/constants/strings.ts
@@ -1,4 +1,3 @@
-
 /* eslint-disable */
 // Below is the regex to convert this into a csv for the Google Sheet
 // export const (.*) = .*?(['|"|`])(.*)\2;
@@ -15,6 +14,7 @@ export const ERROR_DUP_OLD_PWD = 'You may not use a previously used password';
 export const ERROR_EMAIL_IN_USE = 'Email already in use, please try another one';
 export const ERROR_FAILED_LOGIN_INFO = 'Login failed, please try re-entering your login information';
 export const ERROR_FAILED_TO_COMMENT = 'Unable to post comment, refresh and try again!';
+export const ERROR_FAILED_TO_DELETE_COMMENT = 'Unable to delete comment, refresh and try again!';
 export const ERROR_INVALID_INVITATION_CODE = 'Invitation code invalid, try again or talk to the friend that sent it 😬';
 export const ERROR_INVALID_LOGIN = 'Invalid login, Please login again';
 export const ERROR_INVALID_PWD_CODE = 'Looks like you have entered the wrong code, please try again';
diff --git a/src/services/CommentService.ts b/src/services/CommentService.ts
index 3baf0305..a9a01d77 100644
--- a/src/services/CommentService.ts
+++ b/src/services/CommentService.ts
@@ -99,3 +99,21 @@ export const getCommentsCount = async (
   }
   return comments_count;
 };
+
+export const deleteComment = async (id: string, isThread: boolean) => {
+  try {
+    const token = await AsyncStorage.getItem('token');
+    const url = isThread ? COMMENT_THREAD_ENDPOINT : COMMENTS_ENDPOINT;
+    const response = await fetch(url + `${id}/`, {
+      method: 'DELETE',
+      headers: {
+        Authorization: 'Token ' + token,
+      },
+    });
+    return response.status === 200;
+  } catch (error) {
+    console.log('Failed to delete a comment');
+    console.log(error);
+    return false;
+  }
+};
-- 
cgit v1.2.3-70-g09d2


From 56612885167c07462363aab6b606c807f58eeba5 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 27 Jan 2021 16:27:17 -0500
Subject: fixed not refreshing

---
 src/components/comments/CommentTile.tsx       | 19 ++++++++++++++++---
 src/components/comments/CommentsContainer.tsx |  1 +
 src/services/CommentService.ts                |  1 -
 3 files changed, 17 insertions(+), 4 deletions(-)

(limited to 'src/components/comments/CommentsContainer.tsx')

diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
index e12276a9..58d2be25 100644
--- a/src/components/comments/CommentTile.tsx
+++ b/src/components/comments/CommentTile.tsx
@@ -1,4 +1,4 @@
-import React, {Fragment, useRef, useState} from 'react';
+import React, {Fragment, useEffect, useRef, useState} from 'react';
 import {Text, View} from 'react-native-animatable';
 import {ProfilePreview} from '../profile';
 import {CommentType, ScreenType, TypeOfComment} from '../../types';
@@ -23,6 +23,7 @@ interface CommentTileProps {
   screenType: ScreenType;
   typeOfComment: TypeOfComment;
   setCommentObjectInFocus?: (comment: CommentType | undefined) => void;
+  newCommentsAvailable: boolean;
   setNewCommentsAvailable: (available: boolean) => void;
   canDelete: boolean;
 }
@@ -32,14 +33,25 @@ const CommentTile: React.FC<CommentTileProps> = ({
   screenType,
   typeOfComment,
   setCommentObjectInFocus,
+  newCommentsAvailable,
   setNewCommentsAvailable,
   canDelete,
 }) => {
   const timePosted = getTimePosted(comment_object.date_created);
   const [showReplies, setShowReplies] = useState<boolean>(false);
+  const [newThreadAvailable, setNewThreadAvailable] = useState(true);
   const swipeRef = useRef<Swipeable>(null);
   const isThread = typeOfComment === 'Thread';
 
+  /**
+   * Bubbling up, for handling a new comment in a thread.
+   */
+  useEffect(() => {
+    if (newCommentsAvailable) {
+      setNewThreadAvailable(true);
+    }
+  }, [newCommentsAvailable]);
+
   /**
    * Case : A COMMENT IS IN FOCUS && REPLY SECTION IS HIDDEN
    *     Bring the current comment to focus
@@ -52,6 +64,7 @@ const CommentTile: React.FC<CommentTileProps> = ({
       if (!showReplies) {
         setCommentObjectInFocus(comment_object);
       } else {
+        setNewThreadAvailable(true);
         setCommentObjectInFocus(undefined);
       }
     }
@@ -150,8 +163,8 @@ const CommentTile: React.FC<CommentTileProps> = ({
         <CommentsContainer
           objectId={comment_object.comment_id}
           screenType={screenType}
-          setNewCommentsAvailable={() => {}}
-          newCommentsAvailable={true}
+          setNewCommentsAvailable={setNewThreadAvailable}
+          newCommentsAvailable={newThreadAvailable}
           typeOfComment={'Thread'}
         />
       )}
diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
index fd4b32af..d8134caf 100644
--- a/src/components/comments/CommentsContainer.tsx
+++ b/src/components/comments/CommentsContainer.tsx
@@ -83,6 +83,7 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
             screenType={screenType}
             typeOfComment={typeOfComment}
             setCommentObjectInFocus={setCommentObjectInFocus}
+            newCommentsAvailable={newCommentsAvailable}
             setNewCommentsAvailable={setNewCommentsAvailable}
             canDelete={comment.commenter.username === loggedInUsername}
           />
diff --git a/src/services/CommentService.ts b/src/services/CommentService.ts
index a9a01d77..2faaa8db 100644
--- a/src/services/CommentService.ts
+++ b/src/services/CommentService.ts
@@ -23,7 +23,6 @@ export const getComments = async (
     const status = response.status;
     if (status === 200) {
       comments = await response.json();
-      console.log(comments[0]);
     } else {
       console.log('Could not load comments');
     }
-- 
cgit v1.2.3-70-g09d2


From 0e86cd3c972e54cf700cca65bb2493e84056276c Mon Sep 17 00:00:00 2001
From: Ashm Walia <ashmwalia@outlook.com>
Date: Fri, 29 Jan 2021 10:55:14 -0800
Subject: kind of works

---
 src/components/comments/CommentTile.tsx       | 27 ++++++----
 src/components/comments/CommentsContainer.tsx | 75 ++++++++++++++++++---------
 src/components/notifications/Notification.tsx |  1 +
 src/routes/main/MainStackNavigator.tsx        |  1 +
 src/screens/main/NotificationsScreen.tsx      |  2 +-
 src/screens/profile/IndividualMoment.tsx      |  9 ++--
 src/screens/profile/MomentCommentsScreen.tsx  |  5 +-
 7 files changed, 77 insertions(+), 43 deletions(-)

(limited to 'src/components/comments/CommentsContainer.tsx')

diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
index b631a985..347954b5 100644
--- a/src/components/comments/CommentTile.tsx
+++ b/src/components/comments/CommentTile.tsx
@@ -6,7 +6,12 @@ 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 {
+  getTimePosted,
+  normalize,
+  SCREEN_HEIGHT,
+  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';
@@ -155,14 +160,16 @@ const CommentTile: React.FC<CommentTileProps> = ({
       </View>
 
       {/*** Show replies if toggle state is true */}
-      {showReplies && (
-        <CommentsContainer
-          objectId={comment_object.comment_id}
-          screenType={screenType}
-          setNewCommentsAvailable={setNewThreadAvailable}
-          newCommentsAvailable={newThreadAvailable}
-          typeOfComment={'Thread'}
-        />
+      {showReplies && comment_object.replies_count > 0 && (
+        <View style={{height: SCREEN_HEIGHT / 2.4}}>
+          <CommentsContainer
+            objectId={comment_object.comment_id}
+            screenType={screenType}
+            setNewCommentsAvailable={setNewThreadAvailable}
+            newCommentsAvailable={newThreadAvailable}
+            typeOfComment={'Thread'}
+          />
+        </View>
       )}
     </Swipeable>
   );
@@ -173,9 +180,9 @@ const styles = StyleSheet.create({
     borderBottomWidth: 1,
     borderColor: 'lightgray',
     backgroundColor: 'white',
-    paddingTop: '3%',
     flexDirection: 'column',
     flex: 1,
+    paddingTop: '3%',
     marginLeft: '7%',
   },
   swipeActions: {
diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
index d8134caf..d2f11b96 100644
--- a/src/components/comments/CommentsContainer.tsx
+++ b/src/components/comments/CommentsContainer.tsx
@@ -1,16 +1,17 @@
 import React, {useEffect, useRef, useState} from 'react';
 import {StyleSheet} from 'react-native';
-import {ScrollView} from 'react-native-gesture-handler';
+import {FlatList} from 'react-native-gesture-handler';
 import {useDispatch, useSelector} from 'react-redux';
 import {CommentTile} from '.';
 import {getComments} from '../../services';
 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;
@@ -32,18 +33,21 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
   typeOfComment,
   setCommentObjectInFocus,
   commentObjectInFocus,
+  commentId,
 }) => {
   const {username: loggedInUsername} = useSelector(
     (state: RootState) => state.user.user,
   );
   const [commentsList, setCommentsList] = useState<CommentType[]>([]);
   const dispatch = useDispatch();
-  const ref = useRef<ScrollView>(null);
+  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 === 'Comment' && !commentObjectInFocus) ||
+      typeOfComment === 'Thread';
     const loadComments = async () => {
       const comments = await getComments(objectId, typeOfComment === 'Thread');
       setCommentsList(comments);
@@ -55,9 +59,15 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
     if (newCommentsAvailable) {
       loadComments();
       if (shouldScroll()) {
-        setTimeout(() => {
-          ref.current?.scrollToEnd();
-        }, 500);
+        if (commentId) {
+          const index = commentsList.findIndex(
+            (item) => item.comment_id === commentId,
+          );
+          setInitialIndex(index);
+        } else {
+          setInitialIndex(commentsList.length - 1);
+          ref.current?.scrollToEnd({animated: true});
+        }
       }
     }
   }, [
@@ -68,27 +78,44 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
     setCommentsLength,
     typeOfComment,
     commentObjectInFocus,
+    commentId,
+    commentsList,
   ]);
 
+  const ITEM_HEIGHT = SCREEN_HEIGHT / 7.5;
+
+  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 (
-    <ScrollView
+    <FlatList
+      data={commentsList}
       ref={ref}
-      style={styles.scrollView}
-      contentContainerStyle={styles.scrollViewContent}>
-      {commentsList &&
-        commentsList.map((comment: CommentType) => (
-          <CommentTile
-            key={comment.comment_id}
-            comment_object={comment}
-            screenType={screenType}
-            typeOfComment={typeOfComment}
-            setCommentObjectInFocus={setCommentObjectInFocus}
-            newCommentsAvailable={newCommentsAvailable}
-            setNewCommentsAvailable={setNewCommentsAvailable}
-            canDelete={comment.commenter.username === loggedInUsername}
-          />
-        ))}
-    </ScrollView>
+      keyExtractor={(item, index) => index.toString()}
+      decelerationRate={'fast'}
+      snapToAlignment={'start'}
+      snapToInterval={ITEM_HEIGHT}
+      renderItem={renderComment}
+      showsVerticalScrollIndicator={false}
+      initialScrollIndex={initialIndex}
+      contentContainerStyle={styles.scrollViewContent}
+      getItemLayout={(data, index) => ({
+        length: ITEM_HEIGHT,
+        offset: ITEM_HEIGHT * index,
+        index,
+      })}
+      pagingEnabled
+    />
   );
 };
 
diff --git a/src/components/notifications/Notification.tsx b/src/components/notifications/Notification.tsx
index 94367304..c754f941 100644
--- a/src/components/notifications/Notification.tsx
+++ b/src/components/notifications/Notification.tsx
@@ -122,6 +122,7 @@ const Notification: React.FC<NotificationProps> = (props) => {
             navigation.push('MomentCommentsScreen', {
               moment_id: moment.moment_id,
               screenType,
+              comment_id: notification_object?.comment_id,
             });
           }, 500);
         }
diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx
index bd838ef2..663aeaea 100644
--- a/src/routes/main/MainStackNavigator.tsx
+++ b/src/routes/main/MainStackNavigator.tsx
@@ -37,6 +37,7 @@ export type MainStackParams = {
     moment_id: string;
     userXId: string | undefined;
     screenType: ScreenType;
+    comment_id?: string;
   };
   FriendsListScreen: {
     userXId: string | undefined;
diff --git a/src/screens/main/NotificationsScreen.tsx b/src/screens/main/NotificationsScreen.tsx
index 4bdee942..d9952aa8 100644
--- a/src/screens/main/NotificationsScreen.tsx
+++ b/src/screens/main/NotificationsScreen.tsx
@@ -70,7 +70,7 @@ const NotificationsScreen: React.FC = () => {
 
       //Called when user leaves the screen
       return () => resetNewNotificationFlag();
-    }, [newNotificationReceived]),
+    }, [newNotificationReceived, dispatch, refreshNotifications]),
   );
 
   // handles storing and fetching the "previously viewed" information
diff --git a/src/screens/profile/IndividualMoment.tsx b/src/screens/profile/IndividualMoment.tsx
index ea0c8fb6..8c1dc327 100644
--- a/src/screens/profile/IndividualMoment.tsx
+++ b/src/screens/profile/IndividualMoment.tsx
@@ -4,12 +4,12 @@ import {StackNavigationProp} from '@react-navigation/stack';
 import React from 'react';
 import {FlatList, StyleSheet, View} from 'react-native';
 import {useSelector} from 'react-redux';
-import {ProfileStackParams} from 'src/routes/main/ProfileStack';
 import {
   IndividualMomentTitleBar,
   MomentPostContent,
   MomentPostHeader,
 } from '../../components';
+import {MainStackParams} from '../../routes';
 import {RootState} from '../../store/rootreducer';
 import {MomentType} from '../../types';
 import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
@@ -17,12 +17,9 @@ import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
 /**
  * Individual moment view opened when user clicks on a moment tile
  */
-type IndividualMomentRouteProp = RouteProp<
-  ProfileStackParams,
-  'IndividualMoment'
->;
+type IndividualMomentRouteProp = RouteProp<MainStackParams, 'IndividualMoment'>;
 type IndividualMomentNavigationProp = StackNavigationProp<
-  ProfileStackParams,
+  MainStackParams,
   'IndividualMoment'
 >;
 interface IndividualMomentProps {
diff --git a/src/screens/profile/MomentCommentsScreen.tsx b/src/screens/profile/MomentCommentsScreen.tsx
index 58422f0f..5c3b8579 100644
--- a/src/screens/profile/MomentCommentsScreen.tsx
+++ b/src/screens/profile/MomentCommentsScreen.tsx
@@ -28,7 +28,7 @@ interface MomentCommentsScreenProps {
 
 const MomentCommentsScreen: React.FC<MomentCommentsScreenProps> = ({route}) => {
   const navigation = useNavigation();
-  const {moment_id, screenType} = route.params;
+  const {moment_id, screenType, comment_id} = route.params;
 
   //Receives comment length from child CommentsContainer
   const [commentsLength, setCommentsLength] = useState<number>(0);
@@ -55,6 +55,7 @@ const MomentCommentsScreen: React.FC<MomentCommentsScreenProps> = ({route}) => {
         <View style={styles.body}>
           <CommentsContainer
             objectId={moment_id}
+            commentId={comment_id}
             screenType={screenType}
             setCommentsLength={setCommentsLength}
             newCommentsAvailable={newCommentsAvailable}
@@ -107,7 +108,7 @@ const styles = StyleSheet.create({
     fontWeight: '400',
   },
   body: {
-    width: SCREEN_WIDTH,
+    width: SCREEN_WIDTH * 0.9,
     height: SCREEN_HEIGHT * 0.8,
     paddingTop: '3%',
   },
-- 
cgit v1.2.3-70-g09d2


From b34ae3fa04934616934bd50e9a472e19036ec2fa Mon Sep 17 00:00:00 2001
From: Ashm Walia <ashmwalia@outlook.com>
Date: Fri, 29 Jan 2021 11:03:55 -0800
Subject: Fix

---
 src/components/comments/CommentsContainer.tsx | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'src/components/comments/CommentsContainer.tsx')

diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
index d2f11b96..a0e94828 100644
--- a/src/components/comments/CommentsContainer.tsx
+++ b/src/components/comments/CommentsContainer.tsx
@@ -65,8 +65,9 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
           );
           setInitialIndex(index);
         } else {
-          setInitialIndex(commentsList.length - 1);
-          ref.current?.scrollToEnd({animated: true});
+          setTimeout(() => {
+            ref.current?.scrollToEnd({animated: true});
+          }, 500);
         }
       }
     }
-- 
cgit v1.2.3-70-g09d2


From a3000926cb26d9ca2afba116d875653783fb622b Mon Sep 17 00:00:00 2001
From: Ashm Walia <ashmwalia@outlook.com>
Date: Sun, 31 Jan 2021 02:25:53 -0800
Subject: Fixed

---
 src/components/comments/AddComment.tsx        |  16 +++-
 src/components/comments/CommentTile.tsx       | 114 +++++++++++++++-----------
 src/components/comments/CommentsContainer.tsx |  97 +++++++++++++++-------
 src/components/notifications/Notification.tsx |  80 +++++++++++++-----
 src/store/actions/user.ts                     |  18 ++++
 src/store/initialStates.ts                    |   2 +
 src/store/reducers/userReducer.ts             |   6 ++
 src/types/types.ts                            |  13 ++-
 8 files changed, 243 insertions(+), 103 deletions(-)

(limited to 'src/components/comments/CommentsContainer.tsx')

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,
diff --git a/src/components/notifications/Notification.tsx b/src/components/notifications/Notification.tsx
index c754f941..e40153ea 100644
--- a/src/components/notifications/Notification.tsx
+++ b/src/components/notifications/Notification.tsx
@@ -1,18 +1,29 @@
 import {useNavigation} from '@react-navigation/native';
 import React, {useEffect, useState} from 'react';
-import {Image, StyleSheet, Text, View} from 'react-native';
+import {Alert, Image, StyleSheet, Text, View} from 'react-native';
 import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
 import {useDispatch, useStore} from 'react-redux';
-import {loadImageFromURL, loadMomentThumbnail} from '../../services';
+import {
+  loadImageFromURL,
+  loadMoments,
+  loadMomentThumbnail,
+} from '../../services';
 import {
   acceptFriendRequest,
   declineFriendRequest,
   loadUserNotifications,
+  updateReplyPosted,
   updateUserXFriends,
 } from '../../store/actions';
 import {RootState} from '../../store/rootReducer';
 import {MomentType, NotificationType, ScreenType} from '../../types';
-import {fetchUserX, SCREEN_HEIGHT, userXInStore} from '../../utils';
+import {
+  fetchUserX,
+  getTokenOrLogout,
+  handleOpenSocialUrlOnBrowser,
+  SCREEN_HEIGHT,
+  userXInStore,
+} from '../../utils';
 import AcceptDeclineButtons from '../common/AcceptDeclineButtons';
 
 interface NotificationProps {
@@ -60,7 +71,11 @@ const Notification: React.FC<NotificationProps> = (props) => {
       }
     };
     if (notification_type === 'CMT' && notification_object) {
-      loadMomentImage(notification_object.moment_id);
+      loadMomentImage(
+        notification_object.moment_id
+          ? notification_object.moment_id
+          : notification_object.parent_comment.moment_id,
+      );
       return () => {
         mounted = false;
       };
@@ -84,35 +99,56 @@ const Notification: React.FC<NotificationProps> = (props) => {
         });
         break;
       case 'CMT':
-        // find the moment we need to display
+        //Notification object is set to null if the comment / comment_thread / moment gets deleted
+        if (!notification_object) {
+          Alert.alert('The comment / moment was probably deleted by the user');
+          break;
+        }
+        let {moment_id} = notification_object;
+        let {comment_id} = notification_object;
+
+        //If this is a thread, get comment_id and moment_id from parent_comment
+        if (!notification_object?.moment_id) {
+          moment_id = notification_object?.parent_comment?.moment_id;
+          comment_id = notification_object?.parent_comment?.comment_id;
+        }
+
+        console.log('Problem');
+
+        // Now find the moment we need to display
         let moment: MomentType | undefined = loggedInUserMoments?.find(
-          (m) => m.moment_id === notification_object?.moment_id,
+          (m) => m.moment_id === moment_id,
         );
         let userXId;
 
-        //This needs to be done if user replies to a comment on a moment that is not user's own moment
+        // If moment does not belong to the logged in user, then the comment was probably a reply to logged in user's comment
+        // on userX's moment
+        // Load moments for userX
         if (!moment) {
+          let moments: MomentType[] = [];
           try {
             if (!userXInStore(state, screenType, id)) {
-              await fetchUserX(
-                dispatch,
-                {userId: id, username: username},
-                screenType,
-              );
+              console.log('Problem');
+              const token = await getTokenOrLogout(dispatch);
+              moments = await loadMoments(id, token);
+            } else {
+              moments = state.userX[screenType][id].moments;
             }
-
-            //Wait for data to be loaded
-            setTimeout(() => {}, 200);
-            const {moments} = state.userX[screenType][id];
-            moment = moments?.find(
-              (m) => m.moment_id === notification_object?.moment_id,
-            );
-            userXId = id;
           } catch (err) {
             console.log(err);
           }
+
+          setTimeout(() => {}, 700);
+          moment = moments?.find((m) => m.moment_id === moment_id);
+          userXId = id;
         }
+
+        console.log(moment);
+        //Now if moment was found, navigate to the respective moment
         if (moment) {
+          if (notification_object?.parent_comment) {
+            dispatch(updateReplyPosted(notification_object));
+          }
           navigation.push('IndividualMoment', {
             moment,
             userXId: userXId, // we're only viewing our own moment here
@@ -120,9 +156,9 @@ const Notification: React.FC<NotificationProps> = (props) => {
           });
           setTimeout(() => {
             navigation.push('MomentCommentsScreen', {
-              moment_id: moment.moment_id,
+              moment_id: moment_id,
               screenType,
-              comment_id: notification_object?.comment_id,
+              comment_id: comment_id,
             });
           }, 500);
         }
diff --git a/src/store/actions/user.ts b/src/store/actions/user.ts
index 0b1ea789..af942592 100644
--- a/src/store/actions/user.ts
+++ b/src/store/actions/user.ts
@@ -1,3 +1,4 @@
+import { CommentThreadType } from './../../types/types';
 import {RootState} from '../rootReducer';
 import {UserType} from '../../types/types';
 import {loadProfileInfo, loadAvatar, loadCover} from '../../services';
@@ -9,6 +10,7 @@ import {
   profileCompletionStageUpdated,
   setIsOnboardedUser,
   setNewNotificationReceived,
+  setReplyPosted,
 } from '../reducers';
 import {getTokenOrLogout} from '../../utils';
 
@@ -111,6 +113,22 @@ export const updateNewNotificationReceived = (
   }
 };
 
+export const updateReplyPosted = (
+  replyPosted: CommentThreadType | undefined,
+): ThunkAction<Promise<void>, RootState, unknown, Action<string>> => async (
+  dispatch,
+) => {
+  console.log(replyPosted);
+  try {
+    dispatch({
+      type: setReplyPosted.type,
+      payload: {replyPosted},
+    });
+  } catch (error) {
+    console.log(error);
+  }
+};
+
 export const logout = (): ThunkAction<
   Promise<void>,
   RootState,
diff --git a/src/store/initialStates.ts b/src/store/initialStates.ts
index 2a5b76db..8d137a5d 100644
--- a/src/store/initialStates.ts
+++ b/src/store/initialStates.ts
@@ -1,3 +1,4 @@
+import {CommentThreadType} from './../types/types';
 import {
   ExploreSectionType,
   MomentType,
@@ -44,6 +45,7 @@ export const NO_USER_DATA = {
   cover: <string | null>'',
   isOnboardedUser: false,
   newNotificationReceived: false,
+  replyPosted: <CommentThreadType | undefined>undefined,
 };
 
 export const NO_FRIENDS_DATA = {
diff --git a/src/store/reducers/userReducer.ts b/src/store/reducers/userReducer.ts
index ce497677..0ef739ac 100644
--- a/src/store/reducers/userReducer.ts
+++ b/src/store/reducers/userReducer.ts
@@ -53,6 +53,11 @@ const userDataSlice = createSlice({
     setNewNotificationReceived: (state, action) => {
       state.newNotificationReceived = action.payload.newNotificationReceived;
     },
+
+    setReplyPosted: (state, action) => {
+      console.log(action.payload.replyPosted);
+      state.replyPosted = action.payload.replyPosted;
+    },
   },
 });
 
@@ -63,5 +68,6 @@ export const {
   profileCompletionStageUpdated,
   setIsOnboardedUser,
   setNewNotificationReceived,
+  setReplyPosted,
 } = userDataSlice.actions;
 export const userDataReducer = userDataSlice.reducer;
diff --git a/src/types/types.ts b/src/types/types.ts
index 1d800423..1775cd5f 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -88,13 +88,20 @@ export interface MomentType {
   thumbnail_url: string;
 }
 
-export interface CommentType {
+export interface CommentBaseType {
   comment_id: string;
   comment: string;
   date_created: string;
+  commenter: ProfilePreviewType;
+}
+
+export interface CommentType extends CommentBaseType {
   moment_id: string;
   replies_count: number;
-  commenter: ProfilePreviewType;
+}
+
+export interface CommentThreadType extends CommentBaseType {
+  parent_comment: CommentType;
 }
 
 export type PreviewType =
@@ -173,7 +180,7 @@ export type NotificationType = {
   actor: ProfilePreviewType;
   verbage: string;
   notification_type: 'DFT' | 'FRD_REQ' | 'FRD_ACPT' | 'FRD_DEC' | 'CMT';
-  notification_object: CommentType | undefined;
+  notification_object: CommentType | CommentThreadType | undefined;
   timestamp: string;
   unread: boolean;
 };
-- 
cgit v1.2.3-70-g09d2

