|
|
|
@ -22,6 +22,8 @@ |
|
|
|
let loading = $state(true); |
|
|
|
let loading = $state(true); |
|
|
|
let replyingTo = $state<NostrEvent | null>(null); |
|
|
|
let replyingTo = $state<NostrEvent | null>(null); |
|
|
|
let loadingPromise: Promise<void> | null = null; // Track ongoing load to prevent concurrent calls |
|
|
|
let loadingPromise: Promise<void> | null = null; // Track ongoing load to prevent concurrent calls |
|
|
|
|
|
|
|
let nestedSubscriptionActive = $state(false); // Track if nested subscription is active |
|
|
|
|
|
|
|
let isProcessingUpdate = $state(false); // Prevent recursive update processing |
|
|
|
|
|
|
|
|
|
|
|
const isKind1 = $derived(event?.kind === 1); |
|
|
|
const isKind1 = $derived(event?.kind === 1); |
|
|
|
const rootKind = $derived(event?.kind || null); |
|
|
|
const rootKind = $derived(event?.kind || null); |
|
|
|
@ -33,6 +35,13 @@ |
|
|
|
// Reload comments when threadId changes |
|
|
|
// Reload comments when threadId changes |
|
|
|
$effect(() => { |
|
|
|
$effect(() => { |
|
|
|
if (!threadId) { |
|
|
|
if (!threadId) { |
|
|
|
|
|
|
|
// Reset state when threadId is cleared |
|
|
|
|
|
|
|
comments = []; |
|
|
|
|
|
|
|
kind1Replies = []; |
|
|
|
|
|
|
|
yakBacks = []; |
|
|
|
|
|
|
|
zapReceipts = []; |
|
|
|
|
|
|
|
nestedSubscriptionActive = false; |
|
|
|
|
|
|
|
isProcessingUpdate = false; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -41,6 +50,10 @@ |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reset subscription flag when loading new thread |
|
|
|
|
|
|
|
nestedSubscriptionActive = false; |
|
|
|
|
|
|
|
isProcessingUpdate = false; |
|
|
|
|
|
|
|
|
|
|
|
// Load comments - filters will adapt based on whether event is available |
|
|
|
// Load comments - filters will adapt based on whether event is available |
|
|
|
// Ensure nostrClient is initialized first |
|
|
|
// Ensure nostrClient is initialized first |
|
|
|
loadingPromise = nostrClient.initialize().then(() => { |
|
|
|
loadingPromise = nostrClient.initialize().then(() => { |
|
|
|
@ -148,53 +161,119 @@ |
|
|
|
return !!eTag; |
|
|
|
return !!eTag; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function handleReplyUpdate(updated: NostrEvent[]) { |
|
|
|
|
|
|
|
// Prevent recursive calls |
|
|
|
|
|
|
|
if (isProcessingUpdate) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Batch updates to prevent flickering |
|
|
|
|
|
|
|
requestAnimationFrame(() => { |
|
|
|
|
|
|
|
isProcessingUpdate = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
let hasNewReplies = false; |
|
|
|
|
|
|
|
const commentsMap = new Map(comments.map(c => [c.id, c])); |
|
|
|
|
|
|
|
const kind1RepliesMap = new Map(kind1Replies.map(r => [r.id, r])); |
|
|
|
|
|
|
|
const yakBacksMap = new Map(yakBacks.map(y => [y.id, y])); |
|
|
|
|
|
|
|
const zapReceiptsMap = new Map(zapReceipts.map(z => [z.id, z])); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const reply of updated) { |
|
|
|
|
|
|
|
// Skip if we already have this reply |
|
|
|
|
|
|
|
if (commentsMap.has(reply.id) || kind1RepliesMap.has(reply.id) || |
|
|
|
|
|
|
|
yakBacksMap.has(reply.id) || zapReceiptsMap.has(reply.id)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if this reply references the root OR is a reply to any existing comment/reply |
|
|
|
|
|
|
|
const parentId = getParentEventId(reply); |
|
|
|
|
|
|
|
const isReplyToRoot = referencesRoot(reply); |
|
|
|
|
|
|
|
const isReplyToExisting = parentId && ( |
|
|
|
|
|
|
|
parentId === threadId || |
|
|
|
|
|
|
|
commentsMap.has(parentId) || |
|
|
|
|
|
|
|
kind1RepliesMap.has(parentId) || |
|
|
|
|
|
|
|
yakBacksMap.has(parentId) || |
|
|
|
|
|
|
|
zapReceiptsMap.has(parentId) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isReplyToRoot && !isReplyToExisting) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the reply to the appropriate map |
|
|
|
|
|
|
|
if (reply.kind === 1111) { |
|
|
|
|
|
|
|
commentsMap.set(reply.id, reply); |
|
|
|
|
|
|
|
hasNewReplies = true; |
|
|
|
|
|
|
|
} else if (reply.kind === 1) { |
|
|
|
|
|
|
|
kind1RepliesMap.set(reply.id, reply); |
|
|
|
|
|
|
|
hasNewReplies = true; |
|
|
|
|
|
|
|
} else if (reply.kind === 1244) { |
|
|
|
|
|
|
|
yakBacksMap.set(reply.id, reply); |
|
|
|
|
|
|
|
hasNewReplies = true; |
|
|
|
|
|
|
|
} else if (reply.kind === 9735) { |
|
|
|
|
|
|
|
zapReceiptsMap.set(reply.id, reply); |
|
|
|
|
|
|
|
hasNewReplies = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Only update state if we have new replies |
|
|
|
|
|
|
|
if (hasNewReplies) { |
|
|
|
|
|
|
|
comments = Array.from(commentsMap.values()); |
|
|
|
|
|
|
|
kind1Replies = Array.from(kind1RepliesMap.values()); |
|
|
|
|
|
|
|
yakBacks = Array.from(yakBacksMap.values()); |
|
|
|
|
|
|
|
zapReceipts = Array.from(zapReceiptsMap.values()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
isProcessingUpdate = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function loadComments() { |
|
|
|
async function loadComments() { |
|
|
|
if (!threadId) { |
|
|
|
if (!threadId) { |
|
|
|
loading = false; |
|
|
|
loading = false; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
loading = true; |
|
|
|
const allRelays = relayManager.getProfileReadRelays(); |
|
|
|
|
|
|
|
const replyFilters: any[] = [ |
|
|
|
|
|
|
|
{ kinds: [1111], '#e': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [1111], '#E': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [1111], '#a': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [1111], '#A': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [1], '#e': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [1244], '#e': [threadId] }, |
|
|
|
|
|
|
|
{ kinds: [9735], '#e': [threadId] } |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fetchEvents with useCache:true returns cached data immediately if available, |
|
|
|
|
|
|
|
// then fetches fresh data in background. Only show loading if no cache. |
|
|
|
try { |
|
|
|
try { |
|
|
|
// Use all relay sources: profileRelays + defaultRelays + user's inboxes + user's localrelays + cache |
|
|
|
// Quick cache check - if we have cache, don't show loading |
|
|
|
// getProfileReadRelays() includes: defaultRelays + profileRelays + user inbox (which includes local relays from kind 10432) |
|
|
|
const quickCacheCheck = await nostrClient.fetchEvents( |
|
|
|
const allRelays = relayManager.getProfileReadRelays(); |
|
|
|
replyFilters, |
|
|
|
|
|
|
|
allRelays, |
|
|
|
const replyFilters: any[] = []; |
|
|
|
{ useCache: true, cacheResults: false, timeout: 50 } |
|
|
|
|
|
|
|
|
|
|
|
// Always fetch kind 1111 comments - check both e and E tags, and a and A tags |
|
|
|
|
|
|
|
replyFilters.push( |
|
|
|
|
|
|
|
{ kinds: [1111], '#e': [threadId] }, // Lowercase e tag |
|
|
|
|
|
|
|
{ kinds: [1111], '#E': [threadId] }, // Uppercase E tag (NIP-22) |
|
|
|
|
|
|
|
{ kinds: [1111], '#a': [threadId] }, // Lowercase a tag (some clients use wrong tags) |
|
|
|
|
|
|
|
{ kinds: [1111], '#A': [threadId] } // Uppercase A tag (NIP-22 for addressable events) |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// For kind 1 events, fetch kind 1 replies |
|
|
|
if (quickCacheCheck.length === 0) { |
|
|
|
// Also fetch kind 1 replies for any event (some apps use kind 1 for everything) |
|
|
|
loading = true; // Only show loading if no cache |
|
|
|
replyFilters.push({ kinds: [1], '#e': [threadId] }); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Fetch yak backs (kind 1244) - voice replies |
|
|
|
|
|
|
|
replyFilters.push({ kinds: [1244], '#e': [threadId] }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fetch zap receipts (kind 9735) |
|
|
|
|
|
|
|
replyFilters.push({ kinds: [9735], '#e': [threadId] }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Loading comments for threadId:', threadId, 'event kind:', event?.kind); |
|
|
|
|
|
|
|
console.log('CommentThread: Filters:', replyFilters); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now fetch with full options - returns cached immediately, fetches fresh in background |
|
|
|
const allReplies = await nostrClient.fetchEvents( |
|
|
|
const allReplies = await nostrClient.fetchEvents( |
|
|
|
replyFilters, |
|
|
|
replyFilters, |
|
|
|
allRelays, |
|
|
|
allRelays, |
|
|
|
{ useCache: true, cacheResults: true, timeout: 10000 } |
|
|
|
{ |
|
|
|
|
|
|
|
useCache: true, |
|
|
|
|
|
|
|
cacheResults: true, |
|
|
|
|
|
|
|
timeout: 10000, |
|
|
|
|
|
|
|
onUpdate: handleReplyUpdate |
|
|
|
|
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Fetched', allReplies.length, 'replies'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Filter to only replies that reference the root |
|
|
|
// Filter to only replies that reference the root |
|
|
|
const rootReplies = allReplies.filter(reply => referencesRoot(reply)); |
|
|
|
const rootReplies = allReplies.filter(reply => referencesRoot(reply)); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Root replies:', rootReplies.length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Separate by type |
|
|
|
// Separate by type |
|
|
|
comments = rootReplies.filter(e => e.kind === 1111); |
|
|
|
comments = rootReplies.filter(e => e.kind === 1111); |
|
|
|
@ -202,20 +281,66 @@ |
|
|
|
yakBacks = rootReplies.filter(e => e.kind === 1244); |
|
|
|
yakBacks = rootReplies.filter(e => e.kind === 1244); |
|
|
|
zapReceipts = rootReplies.filter(e => e.kind === 9735); |
|
|
|
zapReceipts = rootReplies.filter(e => e.kind === 9735); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Separated - comments:', comments.length, 'kind1Replies:', kind1Replies.length, 'yakBacks:', yakBacks.length, 'zapReceipts:', zapReceipts.length); |
|
|
|
loading = false; // Hide loading now that we have data (cached or fresh) |
|
|
|
|
|
|
|
|
|
|
|
// Recursively fetch all nested replies (non-blocking - let it run in background) |
|
|
|
// Recursively fetch all nested replies (non-blocking - let it run in background) |
|
|
|
fetchNestedReplies().catch((error) => { |
|
|
|
fetchNestedReplies().then(() => { |
|
|
|
|
|
|
|
subscribeToNestedReplies(); |
|
|
|
|
|
|
|
}).catch((error) => { |
|
|
|
console.error('Error fetching nested replies:', error); |
|
|
|
console.error('Error fetching nested replies:', error); |
|
|
|
|
|
|
|
subscribeToNestedReplies(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
console.error('Error loading comments:', error); |
|
|
|
console.error('Error loading comments:', error); |
|
|
|
} finally { |
|
|
|
|
|
|
|
loading = false; |
|
|
|
loading = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function subscribeToNestedReplies() { |
|
|
|
|
|
|
|
// Prevent duplicate subscriptions |
|
|
|
|
|
|
|
if (nestedSubscriptionActive) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Subscribe to replies to any existing comments/replies |
|
|
|
|
|
|
|
const allRelays = relayManager.getProfileReadRelays(); |
|
|
|
|
|
|
|
const allReplyIds = new Set([ |
|
|
|
|
|
|
|
...comments.map(c => c.id), |
|
|
|
|
|
|
|
...kind1Replies.map(r => r.id), |
|
|
|
|
|
|
|
...yakBacks.map(y => y.id), |
|
|
|
|
|
|
|
...zapReceipts.map(z => z.id) |
|
|
|
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (allReplyIds.size === 0) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nestedSubscriptionActive = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use a single subscription that covers all reply IDs |
|
|
|
|
|
|
|
const nestedFilters: any[] = [ |
|
|
|
|
|
|
|
{ kinds: [1111], '#e': Array.from(allReplyIds) }, |
|
|
|
|
|
|
|
{ kinds: [1111], '#E': Array.from(allReplyIds) }, |
|
|
|
|
|
|
|
{ kinds: [1], '#e': Array.from(allReplyIds) }, |
|
|
|
|
|
|
|
{ kinds: [1244], '#e': Array.from(allReplyIds) }, |
|
|
|
|
|
|
|
{ kinds: [9735], '#e': Array.from(allReplyIds) } |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nostrClient.fetchEvents( |
|
|
|
|
|
|
|
nestedFilters, |
|
|
|
|
|
|
|
allRelays, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
useCache: true, |
|
|
|
|
|
|
|
cacheResults: true, |
|
|
|
|
|
|
|
onUpdate: handleReplyUpdate |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
).catch(error => { |
|
|
|
|
|
|
|
console.error('Error subscribing to nested replies:', error); |
|
|
|
|
|
|
|
nestedSubscriptionActive = false; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function fetchNestedReplies() { |
|
|
|
async function fetchNestedReplies() { |
|
|
|
// Use all relay sources: profileRelays + defaultRelays + user's inboxes + user's localrelays + cache |
|
|
|
// Use all relay sources: profileRelays + defaultRelays + user's inboxes + user's localrelays + cache |
|
|
|
const allRelays = relayManager.getProfileReadRelays(); |
|
|
|
const allRelays = relayManager.getProfileReadRelays(); |
|
|
|
@ -309,8 +434,6 @@ |
|
|
|
// Second pass: determine parent-child relationships |
|
|
|
// Second pass: determine parent-child relationships |
|
|
|
for (const item of items) { |
|
|
|
for (const item of items) { |
|
|
|
const parentId = getParentEventId(item.event); |
|
|
|
const parentId = getParentEventId(item.event); |
|
|
|
console.log('CommentThread: sortThreadItems - item:', item.type, item.event.id.slice(0, 8), 'parentId:', parentId ? parentId.slice(0, 8) : 'null', 'threadId:', threadId.slice(0, 8)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parentId) { |
|
|
|
if (parentId) { |
|
|
|
if (parentId === threadId) { |
|
|
|
if (parentId === threadId) { |
|
|
|
// This is a direct reply to the root OP |
|
|
|
// This is a direct reply to the root OP |
|
|
|
@ -318,23 +441,19 @@ |
|
|
|
replyMap.set(threadId, []); |
|
|
|
replyMap.set(threadId, []); |
|
|
|
} |
|
|
|
} |
|
|
|
replyMap.get(threadId)!.push(item.event.id); |
|
|
|
replyMap.get(threadId)!.push(item.event.id); |
|
|
|
console.log('CommentThread: Added to replyMap for root threadId:', threadId.slice(0, 8)); |
|
|
|
|
|
|
|
} else if (allEventIds.has(parentId)) { |
|
|
|
} else if (allEventIds.has(parentId)) { |
|
|
|
// This is a reply to another reply |
|
|
|
// This is a reply to another reply |
|
|
|
if (!replyMap.has(parentId)) { |
|
|
|
if (!replyMap.has(parentId)) { |
|
|
|
replyMap.set(parentId, []); |
|
|
|
replyMap.set(parentId, []); |
|
|
|
} |
|
|
|
} |
|
|
|
replyMap.get(parentId)!.push(item.event.id); |
|
|
|
replyMap.get(parentId)!.push(item.event.id); |
|
|
|
console.log('CommentThread: Added to replyMap for parent:', parentId.slice(0, 8)); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Parent not found - treat as root item (orphaned reply) |
|
|
|
// Parent not found - treat as root item (orphaned reply) |
|
|
|
rootItems.push(item); |
|
|
|
rootItems.push(item); |
|
|
|
console.log('CommentThread: Added to rootItems (orphaned)'); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// No parent - treat as root item (direct reply without parent tag) |
|
|
|
// No parent - treat as root item (direct reply without parent tag) |
|
|
|
rootItems.push(item); |
|
|
|
rootItems.push(item); |
|
|
|
console.log('CommentThread: Added to rootItems (no parent)'); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -387,10 +506,7 @@ |
|
|
|
...yakBacks.map(y => ({ event: y, type: 'yak' as const })), |
|
|
|
...yakBacks.map(y => ({ event: y, type: 'yak' as const })), |
|
|
|
...zapReceipts.map(z => ({ event: z, type: 'zap' as const })) |
|
|
|
...zapReceipts.map(z => ({ event: z, type: 'zap' as const })) |
|
|
|
]; |
|
|
|
]; |
|
|
|
console.log('CommentThread: getThreadItems - items before sort:', items.length, items.map(i => ({ type: i.type, id: i.event.id.slice(0, 8) }))); |
|
|
|
return sortThreadItems(items); |
|
|
|
const sorted = sortThreadItems(items); |
|
|
|
|
|
|
|
console.log('CommentThread: getThreadItems - items after sort:', sorted.length, sorted.map(i => ({ type: i.type, id: i.event.id.slice(0, 8) }))); |
|
|
|
|
|
|
|
return sorted; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function handleReply(replyEvent: NostrEvent) { |
|
|
|
function handleReply(replyEvent: NostrEvent) { |
|
|
|
@ -436,33 +552,31 @@ |
|
|
|
// Fetch zap receipts (kind 9735) |
|
|
|
// Fetch zap receipts (kind 9735) |
|
|
|
replyFilters.push({ kinds: [9735], '#e': [threadId] }); |
|
|
|
replyFilters.push({ kinds: [9735], '#e': [threadId] }); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Reloading comments after publish for threadId:', threadId); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Don't use cache when reloading after publishing - we want fresh data |
|
|
|
// Don't use cache when reloading after publishing - we want fresh data |
|
|
|
const allReplies = await nostrClient.fetchEvents( |
|
|
|
const allReplies = await nostrClient.fetchEvents( |
|
|
|
replyFilters, |
|
|
|
replyFilters, |
|
|
|
allRelays, |
|
|
|
allRelays, |
|
|
|
{ useCache: false, cacheResults: true, timeout: 10000 } |
|
|
|
{ useCache: false, cacheResults: true, timeout: 10000 } |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Fetched', allReplies.length, 'replies (fresh)'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Filter to only replies that reference the root |
|
|
|
// Filter to only replies that reference the root |
|
|
|
const rootReplies = allReplies.filter(reply => referencesRoot(reply)); |
|
|
|
const rootReplies = allReplies.filter(reply => referencesRoot(reply)); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Root replies:', rootReplies.length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Separate by type |
|
|
|
// Separate by type |
|
|
|
comments = rootReplies.filter(e => e.kind === 1111); |
|
|
|
comments = rootReplies.filter(e => e.kind === 1111); |
|
|
|
kind1Replies = rootReplies.filter(e => e.kind === 1); |
|
|
|
kind1Replies = rootReplies.filter(e => e.kind === 1); |
|
|
|
yakBacks = rootReplies.filter(e => e.kind === 1244); |
|
|
|
yakBacks = rootReplies.filter(e => e.kind === 1244); |
|
|
|
zapReceipts = rootReplies.filter(e => e.kind === 9735); |
|
|
|
zapReceipts = rootReplies.filter(e => e.kind === 9735); |
|
|
|
|
|
|
|
|
|
|
|
console.log('CommentThread: Separated - comments:', comments.length, 'kind1Replies:', kind1Replies.length, 'yakBacks:', yakBacks.length, 'zapReceipts:', zapReceipts.length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Recursively fetch all nested replies (non-blocking - let it run in background) |
|
|
|
// Recursively fetch all nested replies (non-blocking - let it run in background) |
|
|
|
fetchNestedReplies().catch((error) => { |
|
|
|
fetchNestedReplies().then(() => { |
|
|
|
|
|
|
|
// After fetching nested replies, set up a single persistent subscription |
|
|
|
|
|
|
|
// This subscription will handle all future updates for nested replies |
|
|
|
|
|
|
|
subscribeToNestedReplies(); |
|
|
|
|
|
|
|
}).catch((error) => { |
|
|
|
console.error('Error fetching nested replies:', error); |
|
|
|
console.error('Error fetching nested replies:', error); |
|
|
|
|
|
|
|
// Still set up subscription even if fetch fails |
|
|
|
|
|
|
|
subscribeToNestedReplies(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
|