From 00d6bd4c46eb73353174a2d75b334f423b3c6e71 Mon Sep 17 00:00:00 2001 From: Gigi Date: Sun, 19 Oct 2025 23:02:15 +0200 Subject: [PATCH] feat: add reading progress loading section to debug page - Add state variables for reading progress events and mark-as-read reactions - Implement handler to load all reading progress events (kind:39802) for logged-in user - Implement handler to load all mark-as-read reactions (kind:7, kind:17) with MARK_AS_READ_EMOJI filter - Add two new sections to debug page with buttons and results display - Display event details including author, creation time, and relevant tags - Include timing metrics for load operations --- src/components/Debug.tsx | 263 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) diff --git a/src/components/Debug.tsx b/src/components/Debug.tsx index 04a2ec9c..809a63d4 100644 --- a/src/components/Debug.tsx +++ b/src/components/Debug.tsx @@ -102,6 +102,18 @@ const Debug: React.FC = ({ const [tLoadWritings, setTLoadWritings] = useState(null) const [tFirstWriting, setTFirstWriting] = useState(null) + // Reading Progress loading state + const [isLoadingReadingProgress, setIsLoadingReadingProgress] = useState(false) + const [readingProgressEvents, setReadingProgressEvents] = useState([]) + const [tLoadReadingProgress, setTLoadReadingProgress] = useState(null) + const [tFirstReadingProgress, setTFirstReadingProgress] = useState(null) + + // Mark-as-read reactions loading state + const [isLoadingMarkAsRead, setIsLoadingMarkAsRead] = useState(false) + const [markAsReadReactions, setMarkAsReadReactions] = useState([]) + const [tLoadMarkAsRead, setTLoadMarkAsRead] = useState(null) + const [tFirstMarkAsRead, setTFirstMarkAsRead] = useState(null) + // Live timing state const [liveTiming, setLiveTiming] = useState<{ nip44?: { type: 'encrypt' | 'decrypt'; startTime: number } @@ -109,6 +121,8 @@ const Debug: React.FC = ({ loadBookmarks?: { startTime: number } decryptBookmarks?: { startTime: number } loadHighlights?: { startTime: number } + loadReadingProgress?: { startTime: number } + loadMarkAsRead?: { startTime: number } }>({}) // Web of Trust state @@ -724,6 +738,131 @@ const Debug: React.FC = ({ setTFirstWriting(null) } + const handleLoadReadingProgress = async () => { + if (!relayPool || !activeAccount?.pubkey) { + DebugBus.warn('debug', 'Please log in to load reading progress') + return + } + + try { + setIsLoadingReadingProgress(true) + setReadingProgressEvents([]) + setTLoadReadingProgress(null) + setTFirstReadingProgress(null) + DebugBus.info('debug', 'Loading reading progress events...') + + const start = performance.now() + let firstEventTime: number | null = null + setLiveTiming(prev => ({ ...prev, loadReadingProgress: { startTime: start } })) + + const { queryEvents } = await import('../services/dataFetch') + const { KINDS } = await import('../config/kinds') + + const events = await queryEvents(relayPool, { kinds: [KINDS.ReadingProgress], authors: [activeAccount.pubkey] }, { + onEvent: (evt) => { + if (firstEventTime === null) { + firstEventTime = performance.now() - start + setTFirstReadingProgress(Math.round(firstEventTime)) + } + setReadingProgressEvents(prev => [...prev, evt]) + } + }) + + const elapsed = Math.round(performance.now() - start) + setTLoadReadingProgress(elapsed) + setLiveTiming(prev => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars + const { loadReadingProgress, ...rest } = prev + return rest + }) + + DebugBus.info('debug', `Loaded ${events.length} reading progress events in ${elapsed}ms`) + } catch (err) { + console.error('Failed to load reading progress:', err) + DebugBus.error('debug', `Failed to load reading progress: ${err instanceof Error ? err.message : String(err)}`) + } finally { + setIsLoadingReadingProgress(false) + } + } + + const handleClearReadingProgress = () => { + setReadingProgressEvents([]) + setTLoadReadingProgress(null) + setTFirstReadingProgress(null) + DebugBus.info('debug', 'Cleared reading progress data') + } + + const handleLoadMarkAsReadReactions = async () => { + if (!relayPool || !activeAccount?.pubkey) { + DebugBus.warn('debug', 'Please log in to load mark-as-read reactions') + return + } + + try { + setIsLoadingMarkAsRead(true) + setMarkAsReadReactions([]) + setTLoadMarkAsRead(null) + setTFirstMarkAsRead(null) + DebugBus.info('debug', 'Loading mark-as-read reactions...') + + const start = performance.now() + let firstEventTime: number | null = null + setLiveTiming(prev => ({ ...prev, loadMarkAsRead: { startTime: start } })) + + const { queryEvents } = await import('../services/dataFetch') + const { MARK_AS_READ_EMOJI } = await import('../services/reactionService') + + // Load both kind:7 (reactions to events) and kind:17 (reactions to URLs) + const [kind7Events, kind17Events] = await Promise.all([ + queryEvents(relayPool, { kinds: [7], authors: [activeAccount.pubkey] }, { + onEvent: (evt) => { + if (evt.content === MARK_AS_READ_EMOJI) { + if (firstEventTime === null) { + firstEventTime = performance.now() - start + setTFirstMarkAsRead(Math.round(firstEventTime)) + } + setMarkAsReadReactions(prev => [...prev, evt]) + } + } + }), + queryEvents(relayPool, { kinds: [17], authors: [activeAccount.pubkey] }, { + onEvent: (evt) => { + if (evt.content === MARK_AS_READ_EMOJI) { + if (firstEventTime === null) { + firstEventTime = performance.now() - start + setTFirstMarkAsRead(Math.round(firstEventTime)) + } + setMarkAsReadReactions(prev => [...prev, evt]) + } + } + }) + ]) + + const totalEvents = kind7Events.length + kind17Events.length + const elapsed = Math.round(performance.now() - start) + setTLoadMarkAsRead(elapsed) + setLiveTiming(prev => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars + const { loadMarkAsRead, ...rest } = prev + return rest + }) + + DebugBus.info('debug', `Loaded ${totalEvents} mark-as-read reactions in ${elapsed}ms`) + } catch (err) { + console.error('Failed to load mark-as-read reactions:', err) + DebugBus.error('debug', `Failed to load mark-as-read reactions: ${err instanceof Error ? err.message : String(err)}`) + } finally { + setIsLoadingMarkAsRead(false) + } + } + + const handleClearMarkAsRead = () => { + setMarkAsReadReactions([]) + setTLoadMarkAsRead(null) + setTFirstMarkAsRead(null) + DebugBus.info('debug', 'Cleared mark-as-read reactions data') + } + const handleLoadFriendsList = async () => { if (!relayPool || !activeAccount?.pubkey) { DebugBus.warn('debug', 'Please log in to load friends list') @@ -1348,6 +1487,130 @@ const Debug: React.FC = ({ )} + {/* Reading Progress Loading Section */} +
+

Reading Progress Loading

+
Test reading progress loading (kind: 39802) for the logged-in user
+
+ + +
+
+ + +
+ {readingProgressEvents.length > 0 && ( +
+
Loaded Reading Progress ({readingProgressEvents.length}):
+
+ {readingProgressEvents.map((evt, idx) => { + const dTag = evt.tags?.find((t: string[]) => t[0] === 'd')?.[1] + const aTag = evt.tags?.find((t: string[]) => t[0] === 'a')?.[1] + const content = evt.content || '' + + return ( +
+
Reading Progress #{idx + 1}
+
+
Author: {evt.pubkey.slice(0, 16)}...
+
Created: {new Date(evt.created_at * 1000).toLocaleString()}
+
+
+ {dTag &&
d-tag: {dTag}
} + {aTag &&
#a: {aTag}
} + {content &&
Progress: {content}
} +
+
ID: {evt.id}
+
+ ) + })} +
+
+ )} +
+ + {/* Mark-as-read Reactions Loading Section */} +
+

Mark-as-read Reactions Loading

+
Test loading mark-as-read reactions (kind: 7 and 17) with the MARK_AS_READ_EMOJI for the logged-in user
+
+ + +
+
+ + +
+ {markAsReadReactions.length > 0 && ( +
+
Loaded Mark-as-read Reactions ({markAsReadReactions.length}):
+
+ {markAsReadReactions.map((evt, idx) => { + const eTag = evt.tags?.find((t: string[]) => t[0] === 'e')?.[1] + const rTag = evt.tags?.find((t: string[]) => t[0] === 'r')?.[1] + const pTag = evt.tags?.find((t: string[]) => t[0] === 'p')?.[1] + + return ( +
+
Mark-as-read Reaction #{idx + 1}
+
+
Kind: {evt.kind}
+
Author: {evt.pubkey.slice(0, 16)}...
+
Created: {new Date(evt.created_at * 1000).toLocaleString()}
+
+
+
Emoji: {evt.content}
+ {eTag &&
#e: {eTag.slice(0, 16)}...
} + {rTag &&
#r: {rTag.length > 60 ? rTag.substring(0, 60) + '...' : rTag}
} + {pTag &&
#p: {pTag.slice(0, 16)}...
} +
+
ID: {evt.id}
+
+ ) + })} +
+
+ )} +
+ {/* Web of Trust Section */}

Web of Trust