|
|
|
@ -316,6 +316,11 @@ function isPollVoteKind(evt: Pick<NEvent, 'kind'>): boolean { |
|
|
|
return evt.kind === ExtendedKind.POLL_RESPONSE |
|
|
|
return evt.kind === ExtendedKind.POLL_RESPONSE |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Zap-poll (6969): kind 9735 receipts are paid votes — hide from “Antworten” so amounts/options are not tied to identities here. */ |
|
|
|
|
|
|
|
function isZapPollThreadZapReceipt(evt: Pick<NEvent, 'kind'>, op: Pick<NEvent, 'kind'>): boolean { |
|
|
|
|
|
|
|
return op.kind === ExtendedKind.ZAP_POLL && evt.kind === kinds.Zap |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function threadBacklinkRelationLabel(item: NEvent, t: TFunction): string { |
|
|
|
function threadBacklinkRelationLabel(item: NEvent, t: TFunction): string { |
|
|
|
if (item.kind === kinds.Highlights) return t('highlighted this note') |
|
|
|
if (item.kind === kinds.Highlights) return t('highlighted this note') |
|
|
|
if (item.kind === kinds.ShortTextNote) return t('quoted this note') |
|
|
|
if (item.kind === kinds.ShortTextNote) return t('quoted this note') |
|
|
|
@ -444,6 +449,7 @@ function ReplyNoteList({ |
|
|
|
if (replyIdSet.has(evt.id)) return |
|
|
|
if (replyIdSet.has(evt.id)) return |
|
|
|
if (isNip25ReactionKind(evt.kind)) return |
|
|
|
if (isNip25ReactionKind(evt.kind)) return |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(evt, event)) return |
|
|
|
if ( |
|
|
|
if ( |
|
|
|
shouldHideThreadResponseEvent( |
|
|
|
shouldHideThreadResponseEvent( |
|
|
|
evt, |
|
|
|
evt, |
|
|
|
@ -475,7 +481,10 @@ function ReplyNoteList({ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { zaps: zapsPartitioned, nonZaps } = partitionZapReceipts(replyEvents) |
|
|
|
const { zaps: zapsPartitioned, nonZaps } = partitionZapReceipts(replyEvents) |
|
|
|
const zaps = filterZapReceiptsByReplyThreshold(zapsPartitioned, zapReplyThreshold) |
|
|
|
const zaps = |
|
|
|
|
|
|
|
event.kind === ExtendedKind.ZAP_POLL |
|
|
|
|
|
|
|
? [] |
|
|
|
|
|
|
|
: filterZapReceiptsByReplyThreshold(zapsPartitioned, zapReplyThreshold) |
|
|
|
const replyScoreById = |
|
|
|
const replyScoreById = |
|
|
|
sort === 'top' || sort === 'controversial' || sort === 'most-zapped' |
|
|
|
sort === 'top' || sort === 'controversial' || sort === 'most-zapped' |
|
|
|
? new Map( |
|
|
|
? new Map( |
|
|
|
@ -566,7 +575,8 @@ function ReplyNoteList({ |
|
|
|
hideContentMentioningMutedUsers, |
|
|
|
hideContentMentioningMutedUsers, |
|
|
|
sort, |
|
|
|
sort, |
|
|
|
zapReplyThreshold, |
|
|
|
zapReplyThreshold, |
|
|
|
isDiscussionRoot |
|
|
|
isDiscussionRoot, |
|
|
|
|
|
|
|
event.kind |
|
|
|
]) |
|
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
const replyIdSet = useMemo(() => new Set(replies.map((r) => r.id)), [replies]) |
|
|
|
const replyIdSet = useMemo(() => new Set(replies.map((r) => r.id)), [replies]) |
|
|
|
@ -589,10 +599,11 @@ function ReplyNoteList({ |
|
|
|
/** Quotes + time-sorted feeds must not interleave zap receipts chronologically */ |
|
|
|
/** Quotes + time-sorted feeds must not interleave zap receipts chronologically */ |
|
|
|
const zapsThenTimeSorted = (merged: NEvent[], direction: 'asc' | 'desc') => { |
|
|
|
const zapsThenTimeSorted = (merged: NEvent[], direction: 'asc' | 'desc') => { |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(merged) |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(merged) |
|
|
|
|
|
|
|
const zapsShown = event.kind === ExtendedKind.ZAP_POLL ? [] : zaps |
|
|
|
const sortedNon = [...nonZaps].sort((a, b) => |
|
|
|
const sortedNon = [...nonZaps].sort((a, b) => |
|
|
|
direction === 'asc' ? a.created_at - b.created_at : b.created_at - a.created_at |
|
|
|
direction === 'asc' ? a.created_at - b.created_at : b.created_at - a.created_at |
|
|
|
) |
|
|
|
) |
|
|
|
return moveReportsToEndPreserveOrder(replyFeedZapsFirst(sortedNon, zaps)) |
|
|
|
return moveReportsToEndPreserveOrder(replyFeedZapsFirst(sortedNon, zapsShown)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!showQuotes) return replies |
|
|
|
if (!showQuotes) return replies |
|
|
|
@ -602,6 +613,7 @@ function ReplyNoteList({ |
|
|
|
// E/A: zaps (sats desc) → thread replies (1 / 1111 / 1244, excluding #q-only) → tail (quotes, highlights, long-form refs)
|
|
|
|
// E/A: zaps (sats desc) → thread replies (1 / 1111 / 1244, excluding #q-only) → tail (quotes, highlights, long-form refs)
|
|
|
|
if (rootInfo?.type === 'E' || rootInfo?.type === 'A') { |
|
|
|
if (rootInfo?.type === 'E' || rootInfo?.type === 'A') { |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(replies) |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(replies) |
|
|
|
|
|
|
|
const zapsShown = event.kind === ExtendedKind.ZAP_POLL ? [] : zaps |
|
|
|
const middle = nonZaps.filter((e) => !isEaThreadTailBacklinkCandidate(e, rootInfo)) |
|
|
|
const middle = nonZaps.filter((e) => !isEaThreadTailBacklinkCandidate(e, rootInfo)) |
|
|
|
const tailFromReplies = nonZaps.filter((e) => isEaThreadTailBacklinkCandidate(e, rootInfo)) |
|
|
|
const tailFromReplies = nonZaps.filter((e) => isEaThreadTailBacklinkCandidate(e, rootInfo)) |
|
|
|
const tailSeen = new Set<string>() |
|
|
|
const tailSeen = new Set<string>() |
|
|
|
@ -614,12 +626,13 @@ function ReplyNoteList({ |
|
|
|
for (const e of tailFromReplies) pushTail(e) |
|
|
|
for (const e of tailFromReplies) pushTail(e) |
|
|
|
for (const e of quoteOnly) pushTail(e) |
|
|
|
for (const e of quoteOnly) pushTail(e) |
|
|
|
const tailSorted = partitionAndSortBacklinkTail(tail) |
|
|
|
const tailSorted = partitionAndSortBacklinkTail(tail) |
|
|
|
return [...replyFeedZapsFirst(middle, zaps), ...tailSorted] |
|
|
|
return [...replyFeedZapsFirst(middle, zapsShown), ...tailSorted] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Web article / URL thread (NIP-22): same zaps → middle → tail layout as E/A
|
|
|
|
// Web article / URL thread (NIP-22): same zaps → middle → tail layout as E/A
|
|
|
|
if (rootInfo?.type === 'I') { |
|
|
|
if (rootInfo?.type === 'I') { |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(replies) |
|
|
|
const { zaps, nonZaps } = partitionZapReceipts(replies) |
|
|
|
|
|
|
|
const zapsShownI = event.kind === ExtendedKind.ZAP_POLL ? [] : zaps |
|
|
|
const middle = nonZaps.filter((e) => !isWebThreadTailKind(e.kind)) |
|
|
|
const middle = nonZaps.filter((e) => !isWebThreadTailKind(e.kind)) |
|
|
|
const tailFromReplies = nonZaps.filter((e) => isWebThreadTailKind(e.kind)) |
|
|
|
const tailFromReplies = nonZaps.filter((e) => isWebThreadTailKind(e.kind)) |
|
|
|
const tailSeen = new Set<string>() |
|
|
|
const tailSeen = new Set<string>() |
|
|
|
@ -632,7 +645,7 @@ function ReplyNoteList({ |
|
|
|
for (const e of tailFromReplies) pushTail(e) |
|
|
|
for (const e of tailFromReplies) pushTail(e) |
|
|
|
for (const e of quoteOnly) pushTail(e) |
|
|
|
for (const e of quoteOnly) pushTail(e) |
|
|
|
const tailSorted = partitionAndSortBacklinkTail(tail) |
|
|
|
const tailSorted = partitionAndSortBacklinkTail(tail) |
|
|
|
return [...replyFeedZapsFirst(middle, zaps), ...tailSorted] |
|
|
|
return [...replyFeedZapsFirst(middle, zapsShownI), ...tailSorted] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const merged = [...replies, ...quoteOnly] |
|
|
|
const merged = [...replies, ...quoteOnly] |
|
|
|
@ -646,7 +659,7 @@ function ReplyNoteList({ |
|
|
|
return [...sortedReplies, ...sortedQuotes] |
|
|
|
return [...sortedReplies, ...sortedQuotes] |
|
|
|
} |
|
|
|
} |
|
|
|
return zapsThenTimeSorted(merged, 'desc') |
|
|
|
return zapsThenTimeSorted(merged, 'desc') |
|
|
|
}, [replies, filteredQuoteEvents, showQuotes, sort, replyIdSet, rootInfo]) |
|
|
|
}, [replies, filteredQuoteEvents, showQuotes, sort, replyIdSet, rootInfo, event.kind]) |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (!rootInfo) return |
|
|
|
if (!rootInfo) return |
|
|
|
@ -950,7 +963,7 @@ function ReplyNoteList({ |
|
|
|
try { |
|
|
|
try { |
|
|
|
const ev = await eventService.fetchEvent(id) |
|
|
|
const ev = await eventService.fetchEvent(id) |
|
|
|
if (cancelled) return |
|
|
|
if (cancelled) return |
|
|
|
if (ev && replyMatchesThreadForList(ev, event, threadRoot, true) && !isPollVoteKind(ev)) { |
|
|
|
if (ev && replyMatchesThreadForList(ev, event, threadRoot, true) && !isPollVoteKind(ev) && !isZapPollThreadZapReceipt(ev, event)) { |
|
|
|
batch.push(ev) |
|
|
|
batch.push(ev) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
discussionStatsHydratedReplyIdsRef.current.delete(id) |
|
|
|
discussionStatsHydratedReplyIdsRef.current.delete(id) |
|
|
|
@ -991,6 +1004,7 @@ function ReplyNoteList({ |
|
|
|
const onNewReply = useCallback( |
|
|
|
const onNewReply = useCallback( |
|
|
|
(evt: NEvent) => { |
|
|
|
(evt: NEvent) => { |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(evt, event)) return |
|
|
|
if ( |
|
|
|
if ( |
|
|
|
shouldHideThreadResponseEvent( |
|
|
|
shouldHideThreadResponseEvent( |
|
|
|
evt, |
|
|
|
evt, |
|
|
|
@ -1007,7 +1021,7 @@ function ReplyNoteList({ |
|
|
|
discussionFeedCache.setCachedReplies(rootInfo, [...without, evt]) |
|
|
|
discussionFeedCache.setCachedReplies(rootInfo, [...without, evt]) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
[addReplies, rootInfo, mutePubkeySet, hideContentMentioningMutedUsers] |
|
|
|
[addReplies, rootInfo, mutePubkeySet, hideContentMentioningMutedUsers, event] |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
@ -1039,8 +1053,12 @@ function ReplyNoteList({ |
|
|
|
// Session LRU (timeline / note-stats / prior panels): thread replies before relay round-trip
|
|
|
|
// Session LRU (timeline / note-stats / prior panels): thread replies before relay round-trip
|
|
|
|
if (rootInfo.type === 'E' || rootInfo.type === 'A') { |
|
|
|
if (rootInfo.type === 'E' || rootInfo.type === 'A') { |
|
|
|
const fromSession = eventService.getSessionThreadInteractionEvents(rootInfo) |
|
|
|
const fromSession = eventService.getSessionThreadInteractionEvents(rootInfo) |
|
|
|
if (fromSession.length > 0) { |
|
|
|
const fromSessionForUi = |
|
|
|
addReplies(fromSession) |
|
|
|
event.kind === ExtendedKind.ZAP_POLL |
|
|
|
|
|
|
|
? fromSession.filter((e) => !isZapPollThreadZapReceipt(e, event)) |
|
|
|
|
|
|
|
: fromSession |
|
|
|
|
|
|
|
if (fromSessionForUi.length > 0) { |
|
|
|
|
|
|
|
addReplies(fromSessionForUi) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1048,8 +1066,12 @@ function ReplyNoteList({ |
|
|
|
const cachedData = discussionFeedCache.getCachedReplies(rootInfo) |
|
|
|
const cachedData = discussionFeedCache.getCachedReplies(rootInfo) |
|
|
|
const hasCache = cachedData !== null |
|
|
|
const hasCache = cachedData !== null |
|
|
|
|
|
|
|
|
|
|
|
if (hasCache) { |
|
|
|
if (hasCache && cachedData) { |
|
|
|
addReplies(cachedData) |
|
|
|
const cachedForUi = |
|
|
|
|
|
|
|
event.kind === ExtendedKind.ZAP_POLL |
|
|
|
|
|
|
|
? cachedData.filter((e) => !isZapPollThreadZapReceipt(e, event)) |
|
|
|
|
|
|
|
: cachedData |
|
|
|
|
|
|
|
addReplies(cachedForUi) |
|
|
|
setLoading(false) |
|
|
|
setLoading(false) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
setLoading(true) |
|
|
|
setLoading(true) |
|
|
|
@ -1111,19 +1133,36 @@ function ReplyNoteList({ |
|
|
|
]) |
|
|
|
]) |
|
|
|
).sort((a, b) => a - b) |
|
|
|
).sort((a, b) => a - b) |
|
|
|
const opRefChunks = chunkKindsForThreadReq(NOTE_STATS_OP_REFERENCE_KINDS_WITHOUT_HIGHLIGHT) |
|
|
|
const opRefChunks = chunkKindsForThreadReq(NOTE_STATS_OP_REFERENCE_KINDS_WITHOUT_HIGHLIGHT) |
|
|
|
|
|
|
|
const kindsNoteCommentVoiceZap: number[] = [ |
|
|
|
|
|
|
|
kinds.ShortTextNote, |
|
|
|
|
|
|
|
ExtendedKind.COMMENT, |
|
|
|
|
|
|
|
ExtendedKind.VOICE_COMMENT, |
|
|
|
|
|
|
|
kinds.Zap |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
const kindsNoteCommentVoice: number[] = [ |
|
|
|
|
|
|
|
kinds.ShortTextNote, |
|
|
|
|
|
|
|
ExtendedKind.COMMENT, |
|
|
|
|
|
|
|
ExtendedKind.VOICE_COMMENT |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
const kindsPrimaryThread = |
|
|
|
|
|
|
|
event.kind === ExtendedKind.ZAP_POLL ? kindsNoteCommentVoice : kindsNoteCommentVoiceZap |
|
|
|
|
|
|
|
const kindsUpperEThread: number[] = |
|
|
|
|
|
|
|
event.kind === ExtendedKind.ZAP_POLL |
|
|
|
|
|
|
|
? [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT] |
|
|
|
|
|
|
|
: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap] |
|
|
|
|
|
|
|
|
|
|
|
if (rootInfo.type === 'E') { |
|
|
|
if (rootInfo.type === 'E') { |
|
|
|
// Fetch all reply types for event-based replies (keep ≤4 kinds per filter — some relays
|
|
|
|
// Fetch all reply types for event-based replies (keep ≤4 kinds per filter — some relays
|
|
|
|
// NOTICE "too many kinds N" and drop the whole REQ if kind 7 is bundled with four others).
|
|
|
|
// NOTICE "too many kinds N" and drop the whole REQ if kind 7 is bundled with four others).
|
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
'#e': [rootInfo.id], |
|
|
|
'#e': [rootInfo.id], |
|
|
|
kinds: [kinds.ShortTextNote, ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsPrimaryThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
}) |
|
|
|
}) |
|
|
|
// Also fetch with uppercase E tag for replaceable events
|
|
|
|
// Also fetch with uppercase E tag for replaceable events
|
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
'#E': [rootInfo.id], |
|
|
|
'#E': [rootInfo.id], |
|
|
|
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsUpperEThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
}) |
|
|
|
}) |
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
@ -1153,12 +1192,12 @@ function ReplyNoteList({ |
|
|
|
filters.push( |
|
|
|
filters.push( |
|
|
|
{ |
|
|
|
{ |
|
|
|
'#a': [rootInfo.id], |
|
|
|
'#a': [rootInfo.id], |
|
|
|
kinds: [kinds.ShortTextNote, ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsPrimaryThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
{ |
|
|
|
'#A': [rootInfo.id], |
|
|
|
'#A': [rootInfo.id], |
|
|
|
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsUpperEThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
) |
|
|
|
@ -1168,12 +1207,12 @@ function ReplyNoteList({ |
|
|
|
const eSnap = rootInfo.eventId.trim().toLowerCase() |
|
|
|
const eSnap = rootInfo.eventId.trim().toLowerCase() |
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
'#e': [eSnap], |
|
|
|
'#e': [eSnap], |
|
|
|
kinds: [kinds.ShortTextNote, ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsPrimaryThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
}) |
|
|
|
}) |
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
'#E': [eSnap], |
|
|
|
'#E': [eSnap], |
|
|
|
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT, kinds.Zap], |
|
|
|
kinds: kindsUpperEThread, |
|
|
|
limit: LIMIT |
|
|
|
limit: LIMIT |
|
|
|
}) |
|
|
|
}) |
|
|
|
filters.push({ |
|
|
|
filters.push({ |
|
|
|
@ -1225,6 +1264,7 @@ function ReplyNoteList({ |
|
|
|
? (evt: NEvent) => { |
|
|
|
? (evt: NEvent) => { |
|
|
|
if (fetchGeneration !== replyFetchGenRef.current) return |
|
|
|
if (fetchGeneration !== replyFetchGenRef.current) return |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
if (isPollVoteKind(evt)) return |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(evt, event)) return |
|
|
|
if (!isRssArticleUrlThreadInteraction(evt, urlThreadRootInfo.id)) return |
|
|
|
if (!isRssArticleUrlThreadInteraction(evt, urlThreadRootInfo.id)) return |
|
|
|
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers)) |
|
|
|
if (shouldHideThreadResponseEvent(evt, mutePubkeySet, hideContentMentioningMutedUsers)) |
|
|
|
return |
|
|
|
return |
|
|
|
@ -1247,6 +1287,7 @@ function ReplyNoteList({ |
|
|
|
// Filter and add replies (URL threads include kind 9802 highlights of this page)
|
|
|
|
// Filter and add replies (URL threads include kind 9802 highlights of this page)
|
|
|
|
const regularReplies = allReplies.filter((evt) => { |
|
|
|
const regularReplies = allReplies.filter((evt) => { |
|
|
|
if (isPollVoteKind(evt)) return false |
|
|
|
if (isPollVoteKind(evt)) return false |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(evt, event)) return false |
|
|
|
const match = replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot) |
|
|
|
const match = replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot) |
|
|
|
if (!match) return false |
|
|
|
if (!match) return false |
|
|
|
return !shouldHideThreadResponseEvent( |
|
|
|
return !shouldHideThreadResponseEvent( |
|
|
|
@ -1267,7 +1308,11 @@ function ReplyNoteList({ |
|
|
|
// This ensures we keep all previously seen replies and add any new ones
|
|
|
|
// This ensures we keep all previously seen replies and add any new ones
|
|
|
|
// addReplies will deduplicate, so it's safe to call even if some replies are already displayed
|
|
|
|
// addReplies will deduplicate, so it's safe to call even if some replies are already displayed
|
|
|
|
if (mergedCachedReplies) { |
|
|
|
if (mergedCachedReplies) { |
|
|
|
addReplies(mergedCachedReplies) |
|
|
|
const mergedForUi = |
|
|
|
|
|
|
|
event.kind === ExtendedKind.ZAP_POLL |
|
|
|
|
|
|
|
? mergedCachedReplies.filter((e) => !isZapPollThreadZapReceipt(e, event)) |
|
|
|
|
|
|
|
: mergedCachedReplies |
|
|
|
|
|
|
|
addReplies(mergedForUi) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Fallback: if cache somehow failed, at least add the fetched replies
|
|
|
|
// Fallback: if cache somehow failed, at least add the fetched replies
|
|
|
|
logger.warn('[ReplyNoteList] Cache returned null after store, using fetched replies only') |
|
|
|
logger.warn('[ReplyNoteList] Cache returned null after store, using fetched replies only') |
|
|
|
@ -1468,6 +1513,7 @@ function ReplyNoteList({ |
|
|
|
const events = await client.loadMoreTimeline(timelineKey, until, LIMIT) |
|
|
|
const events = await client.loadMoreTimeline(timelineKey, until, LIMIT) |
|
|
|
const olderEvents = events.filter((evt) => { |
|
|
|
const olderEvents = events.filter((evt) => { |
|
|
|
if (isPollVoteKind(evt)) return false |
|
|
|
if (isPollVoteKind(evt)) return false |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(evt, event)) return false |
|
|
|
if (!rootInfo) return false |
|
|
|
if (!rootInfo) return false |
|
|
|
const matchesThread = replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot) |
|
|
|
const matchesThread = replyMatchesThreadForList(evt, event, rootInfo, isDiscussionRoot) |
|
|
|
if (!matchesThread) return false |
|
|
|
if (!matchesThread) return false |
|
|
|
@ -1515,6 +1561,7 @@ function ReplyNoteList({ |
|
|
|
const shouldShowFeedItem = useCallback( |
|
|
|
const shouldShowFeedItem = useCallback( |
|
|
|
(item: NEvent) => { |
|
|
|
(item: NEvent) => { |
|
|
|
if (isPollVoteKind(item)) return false |
|
|
|
if (isPollVoteKind(item)) return false |
|
|
|
|
|
|
|
if (isZapPollThreadZapReceipt(item, event)) return false |
|
|
|
if (shouldHideThreadResponseEvent(item, mutePubkeySet, hideContentMentioningMutedUsers)) { |
|
|
|
if (shouldHideThreadResponseEvent(item, mutePubkeySet, hideContentMentioningMutedUsers)) { |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
@ -1541,7 +1588,8 @@ function ReplyNoteList({ |
|
|
|
hideUntrustedInteractions, |
|
|
|
hideUntrustedInteractions, |
|
|
|
isUserTrusted, |
|
|
|
isUserTrusted, |
|
|
|
rootInfo?.type, |
|
|
|
rootInfo?.type, |
|
|
|
repliesMap |
|
|
|
repliesMap, |
|
|
|
|
|
|
|
event |
|
|
|
] |
|
|
|
] |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|