fix(comments): depth calculation and main button
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m13s

This commit is contained in:
en 2025-02-25 10:26:17 +01:00
parent 596e782b65
commit 2d5088b984
4 changed files with 53 additions and 25 deletions

View File

@ -28,6 +28,7 @@ import { nip19 } from 'nostr-tools'
import { CommentContent } from './CommentContent' import { CommentContent } from './CommentContent'
import { NoteQuoteRepostPopup } from 'components/Notes/NoteQuoteRepostPopup' import { NoteQuoteRepostPopup } from 'components/Notes/NoteQuoteRepostPopup'
import { NoteRepostPopup } from 'components/Notes/NoteRepostPopup' import { NoteRepostPopup } from 'components/Notes/NoteRepostPopup'
import { useComments } from 'hooks/useComments'
interface CommentProps { interface CommentProps {
comment: CommentEvent comment: CommentEvent
@ -48,7 +49,10 @@ export const Comment = ({ comment }: CommentProps) => {
: isNote : isNote
? `${appRoutes.feed}/` ? `${appRoutes.feed}/`
: undefined : undefined
const [commentEvents, setCommentEvents] = useState<CommentEvent[]>([]) 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<UserProfile>() const [profile, setProfile] = useState<UserProfile>()
const submit = useSubmit() const submit = useSubmit()
@ -59,23 +63,9 @@ export const Comment = ({ comment }: CommentProps) => {
const [hasQuoted, setHasQuoted] = useState(false) const [hasQuoted, setHasQuoted] = useState(false)
const [showRepostPopup, setShowRepostPopup] = useState(false) const [showRepostPopup, setShowRepostPopup] = useState(false)
const [showQuoteRepostPopup, setShowQuoteRepostPopup] = useState(false) const [showQuoteRepostPopup, setShowQuoteRepostPopup] = useState(false)
const userState = useAppSelector((state) => state.user)
const userPubkey = userState.user?.pubkey as string | undefined
useDidMount(() => { useDidMount(() => {
comment.event.author.fetchProfile().then((res) => setProfile(res)) 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 = { const repostFilter: NDKFilter = {
kinds: [NDKKind.Repost], kinds: [NDKKind.Repost],
'#e': [comment.event.id] '#e': [comment.event.id]

View File

@ -72,7 +72,10 @@ export const CommentsPopup = ({ title }: CommentsPopupProps) => {
isComplete, isComplete,
root: rootEvent root: rootEvent
} = useReplies(lastETag?.[1]) } = 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<UserProfile>() const [profile, setProfile] = useState<UserProfile>()
const { commentEvents, setCommentEvents } = useComments( const { commentEvents, setCommentEvents } = useComments(
event.author.pubkey, event.author.pubkey,

View File

@ -10,6 +10,7 @@ import { useEffect, useState } from 'react'
import { CommentEvent, UserRelaysType } from 'types' import { CommentEvent, UserRelaysType } from 'types'
import { log, LogType, timeout } from 'utils' import { log, LogType, timeout } from 'utils'
import { useNDKContext } from './useNDKContext' import { useNDKContext } from './useNDKContext'
import _ from 'lodash'
export const useComments = ( export const useComments = (
author: string | undefined, author: string | undefined,
@ -103,20 +104,27 @@ export const useComments = (
// This event has a single #e tag reference // This event has a single #e tag reference
// Checks single marked event (root) and a single positional "e" tags // Checks single marked event (root) and a single positional "e" tags
// Allow if either old kind 1 reply to addressable or matches eTag // 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] return [...prev]
} }
// Position "e" tags (no markets) // Position "e" tags (no markers)
// Multiple e tags, checks the last "e" tag // Multiple e tags, checks the last "e" tag
// Last "e" tag does not match eTag // Last "e" tag does not match eTag
if ( if (
root.length + replies.length === 0 && root.length + replies.length === 0 &&
eTags.length > 1 && eTags.length > 1 &&
eTags[eTags.length - 1][1] !== eTag _.last(eTags)?.[1] !== eTag
) { ) {
return [...prev] 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 // Event is already included

View File

@ -3,9 +3,10 @@ import {
NDKKind, NDKKind,
NDKSubscriptionCacheUsage NDKSubscriptionCacheUsage
} from '@nostr-dev-kit/ndk' } from '@nostr-dev-kit/ndk'
import { useState } from 'react' import { useMemo, useState } from 'react'
import { useNDKContext } from './useNDKContext' import { useNDKContext } from './useNDKContext'
import { useDidMount } from './useDidMount' import { useDidMount } from './useDidMount'
import _ from 'lodash'
export const useReplies = (eTag: string | undefined) => { export const useReplies = (eTag: string | undefined) => {
const { ndk } = useNDKContext() const { ndk } = useNDKContext()
@ -34,9 +35,10 @@ export const useReplies = (eTag: string | undefined) => {
if (p.findIndex((p) => p.id === previousReply.id) === -1) { if (p.findIndex((p) => p.id === previousReply.id) === -1) {
p.push(previousReply) p.push(previousReply)
} }
return p return [...p]
}) })
eDepth = previousReply.tagValue('e') const eTags = previousReply.getMatchingTags('e')
eDepth = _.last(eTags)?.[1]
} else { } else {
eDepth = undefined eDepth = undefined
} }
@ -44,10 +46,35 @@ export const useReplies = (eTag: string | undefined) => {
setIsComplete(true) 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 { return {
size: replies.length, size: replies.length,
isComplete, isComplete,
parent: replies.length > 0 ? replies[0] : undefined, parent: parentEvent,
root: isComplete ? replies[replies.length - 1] : undefined root: rootEvent
} }
} }