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;