/ src / hooks / use-replies.ts
use-replies.ts
 1  import { useMemo } from 'react';
 2  import { Comment, useAccountComments } from '@plebbit/plebbit-react-hooks';
 3  import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils';
 4  
 5  const useReplies = (comment: Comment) => {
 6    // flatten all replies including nested ones from the original comment
 7    const flattenedReplies = useMemo(() => flattenCommentsPages(comment?.replies), [comment?.replies]);
 8  
 9    // generate a Set of CIDs from flattened replies for quick lookup
10    const replyCids = useMemo(() => new Set(flattenedReplies.map((reply) => reply?.cid)), [flattenedReplies]);
11  
12    const { accountComments } = useAccountComments();
13  
14    const filteredAccountComments = useMemo(() => {
15      const commentMap = new Map(accountComments.map((c) => [c.cid, c]));
16  
17      return accountComments.filter((accountComment) => {
18        let currentCid = accountComment.parentCid;
19        while (currentCid && currentCid !== comment?.cid) {
20          if (replyCids.has(currentCid)) {
21            return true;
22          }
23          const parent = commentMap.get(currentCid);
24          if (!parent) {
25            return false;
26          }
27          currentCid = parent.parentCid;
28        }
29        return currentCid === comment?.cid;
30      });
31    }, [accountComments, comment?.cid, replyCids]);
32  
33    // the account's replies have a delay before getting published, so get them locally from accountComments instead
34    const accountRepliesNotYetPublished = useMemo(() => {
35      const replies = flattenedReplies || [];
36      const replyCids = new Set(replies.map((reply: Comment) => reply?.cid));
37      // filter out the account comments already in comment.replies, so they don't appear twice
38      return filteredAccountComments.filter((accountReply) => !replyCids.has(accountReply?.cid));
39    }, [flattenedReplies, filteredAccountComments]);
40  
41    const repliesAndNotYetPublishedReplies = useMemo(() => {
42      const repliesSortedByPinnedAndTimestamp = [...accountRepliesNotYetPublished.reverse(), ...(flattenedReplies || [])];
43  
44      return repliesSortedByPinnedAndTimestamp.sort((a: Comment, b: Comment) => {
45        // Sort by pinned status first, with pinned comments at the top
46        if (a.pinned && !b.pinned) {
47          return -1;
48        } else if (!a.pinned && b.pinned) {
49          return 1;
50        }
51        // If both are pinned or both are not pinned, sort by timestamp
52        return a.timestamp - b.timestamp;
53      });
54    }, [flattenedReplies, accountRepliesNotYetPublished]);
55  
56    // if the comment is a fake comment for description or rules, return an empty array
57    if (comment?.isDescription || comment?.isRules) {
58      return [];
59    }
60  
61    return repliesAndNotYetPublishedReplies;
62  };
63  
64  export default useReplies;