From 2d5088b984cf01256865f8b1dcf57e28f995c996 Mon Sep 17 00:00:00 2001 From: en Date: Tue, 25 Feb 2025 10:26:17 +0100 Subject: [PATCH] fix(comments): depth calculation and main button --- src/components/comment/Comment.tsx | 22 ++++---------- src/components/comment/CommentsPopup.tsx | 5 +++- src/hooks/useComments.ts | 14 +++++++-- src/hooks/useReplies.tsx | 37 ++++++++++++++++++++---- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/components/comment/Comment.tsx b/src/components/comment/Comment.tsx index 4b6f7f4..b2f54fa 100644 --- a/src/components/comment/Comment.tsx +++ b/src/components/comment/Comment.tsx @@ -28,6 +28,7 @@ import { nip19 } from 'nostr-tools' import { CommentContent } from './CommentContent' import { NoteQuoteRepostPopup } from 'components/Notes/NoteQuoteRepostPopup' import { NoteRepostPopup } from 'components/Notes/NoteRepostPopup' +import { useComments } from 'hooks/useComments' interface CommentProps { comment: CommentEvent @@ -48,7 +49,10 @@ export const Comment = ({ comment }: CommentProps) => { : isNote ? `${appRoutes.feed}/` : undefined - const [commentEvents, setCommentEvents] = useState([]) + const userState = useAppSelector((state) => state.user) + const userPubkey = userState.user?.pubkey as string | undefined + const { commentEvents } = useComments(userPubkey, undefined, comment.event.id) + const [profile, setProfile] = useState() const submit = useSubmit() @@ -59,23 +63,9 @@ export const Comment = ({ comment }: CommentProps) => { const [hasQuoted, setHasQuoted] = useState(false) const [showRepostPopup, setShowRepostPopup] = useState(false) const [showQuoteRepostPopup, setShowQuoteRepostPopup] = useState(false) - const userState = useAppSelector((state) => state.user) - const userPubkey = userState.user?.pubkey as string | undefined + useDidMount(() => { comment.event.author.fetchProfile().then((res) => setProfile(res)) - ndk - .fetchEvents({ - kinds: [NDKKind.Text, NDKKind.GenericReply], - '#e': [comment.event.id] - }) - .then((ndkEventsSet) => { - setCommentEvents( - Array.from(ndkEventsSet).map((ndkEvent) => ({ - event: ndkEvent - })) - ) - }) - const repostFilter: NDKFilter = { kinds: [NDKKind.Repost], '#e': [comment.event.id] diff --git a/src/components/comment/CommentsPopup.tsx b/src/components/comment/CommentsPopup.tsx index b7c4d80..0903c70 100644 --- a/src/components/comment/CommentsPopup.tsx +++ b/src/components/comment/CommentsPopup.tsx @@ -72,7 +72,10 @@ export const CommentsPopup = ({ title }: CommentsPopupProps) => { isComplete, root: rootEvent } = useReplies(lastETag?.[1]) - const isRoot = event.tagValue('a') === event.tagValue('A') + const isRoot = + event.kind === NDKKind.Text + ? !event.getMatchingTags('e').length + : event.tagValue('a') === event.tagValue('A') const [profile, setProfile] = useState() const { commentEvents, setCommentEvents } = useComments( event.author.pubkey, diff --git a/src/hooks/useComments.ts b/src/hooks/useComments.ts index f0349b1..29319ef 100644 --- a/src/hooks/useComments.ts +++ b/src/hooks/useComments.ts @@ -10,6 +10,7 @@ import { useEffect, useState } from 'react' import { CommentEvent, UserRelaysType } from 'types' import { log, LogType, timeout } from 'utils' import { useNDKContext } from './useNDKContext' +import _ from 'lodash' export const useComments = ( author: string | undefined, @@ -103,20 +104,27 @@ export const useComments = ( // This event has a single #e tag reference // Checks single marked event (root) and a single positional "e" tags // Allow if either old kind 1 reply to addressable or matches eTag - if (eTags.length === 1 && !(aTag || eTag === eTags[0][1])) { + if (eTags.length === 1 && !(aTag || eTag === _.first(eTags)?.[1])) { return [...prev] } - // Position "e" tags (no markets) + // Position "e" tags (no markers) // Multiple e tags, checks the last "e" tag // Last "e" tag does not match eTag if ( root.length + replies.length === 0 && eTags.length > 1 && - eTags[eTags.length - 1][1] !== eTag + _.last(eTags)?.[1] !== eTag ) { return [...prev] } + + // "e" tags with markets + // Multiple replies, checks the last "e" tag + // Only show direct replies + if (replies.length > 1 && _.last(replies)?.[1] !== eTag) { + return [...prev] + } } // Event is already included diff --git a/src/hooks/useReplies.tsx b/src/hooks/useReplies.tsx index 5513d32..47f3e03 100644 --- a/src/hooks/useReplies.tsx +++ b/src/hooks/useReplies.tsx @@ -3,9 +3,10 @@ import { NDKKind, NDKSubscriptionCacheUsage } from '@nostr-dev-kit/ndk' -import { useState } from 'react' +import { useMemo, useState } from 'react' import { useNDKContext } from './useNDKContext' import { useDidMount } from './useDidMount' +import _ from 'lodash' export const useReplies = (eTag: string | undefined) => { const { ndk } = useNDKContext() @@ -34,9 +35,10 @@ export const useReplies = (eTag: string | undefined) => { if (p.findIndex((p) => p.id === previousReply.id) === -1) { p.push(previousReply) } - return p + return [...p] }) - eDepth = previousReply.tagValue('e') + const eTags = previousReply.getMatchingTags('e') + eDepth = _.last(eTags)?.[1] } else { eDepth = undefined } @@ -44,10 +46,35 @@ export const useReplies = (eTag: string | undefined) => { setIsComplete(true) }) + const rootEvent = useMemo(() => { + let rootETag: string | undefined + for (const r of replies) { + const root = r.getMatchingTags('e', 'root') + if (root.length) { + rootETag = root[0][1] + break + } + } + const rootEvent = replies.find((r) => r.id === rootETag) + + // Root: first reply/comment, target of "Main Post" + // - addr: first comment + // - notes: root comment (marker) + return rootEvent + ? rootEvent + : isComplete + ? replies[replies.length - 1] + : undefined + }, [isComplete, replies]) + + const parentEvent = useMemo(() => { + return replies.length > 0 ? replies[0] : undefined + }, [replies]) + return { size: replies.length, isComplete, - parent: replies.length > 0 ? replies[0] : undefined, - root: isComplete ? replies[replies.length - 1] : undefined + parent: parentEvent, + root: rootEvent } }