feat: implement robust highlight loading with fallback mechanisms

- Add detailed logging to track highlight loading process
- Implement fallback timeout mechanism to retry highlight loading after 2 seconds
- Add backup effect that triggers when article coordinate changes
- Ensure highlights are loaded reliably after article content is fully loaded
- Add console logging to help debug highlight loading issues
This commit is contained in:
Gigi
2025-10-25 00:59:26 +02:00
parent e2472606dd
commit 0a62924b78
2 changed files with 102 additions and 21 deletions

View File

@@ -246,7 +246,10 @@ const Bookmarks: React.FC<BookmarksProps> = ({
setCurrentArticleCoordinate, setCurrentArticleCoordinate,
setCurrentArticleEventId, setCurrentArticleEventId,
setCurrentArticle, setCurrentArticle,
settings settings,
currentArticleCoordinate,
currentArticleEventId,
highlightsLoading
}) })
// Load external URL if /r/* route is used // Load external URL if /r/* route is used

View File

@@ -34,6 +34,9 @@ interface UseArticleLoaderProps {
setCurrentArticleEventId: (id: string | undefined) => void setCurrentArticleEventId: (id: string | undefined) => void
setCurrentArticle?: (article: NostrEvent) => void setCurrentArticle?: (article: NostrEvent) => void
settings?: UserSettings settings?: UserSettings
currentArticleCoordinate?: string
currentArticleEventId?: string
highlightsLoading?: boolean
} }
export function useArticleLoader({ export function useArticleLoader({
@@ -49,7 +52,10 @@ export function useArticleLoader({
setCurrentArticleCoordinate, setCurrentArticleCoordinate,
setCurrentArticleEventId, setCurrentArticleEventId,
setCurrentArticle, setCurrentArticle,
settings settings,
currentArticleCoordinate,
currentArticleEventId,
highlightsLoading
}: UseArticleLoaderProps) { }: UseArticleLoaderProps) {
const location = useLocation() const location = useLocation()
const mountedRef = useRef(true) const mountedRef = useRef(true)
@@ -230,8 +236,8 @@ export function useArticleLoader({
setCurrentArticle?.(article.event) setCurrentArticle?.(article.event)
} }
// Fetch highlights after content is shown // Fetch highlights after content is shown - ensure this happens reliably
try { const fetchHighlightsForCurrentArticle = async () => {
if (!mountedRef.current) return if (!mountedRef.current) return
const le = latestEvent as NostrEvent | null const le = latestEvent as NostrEvent | null
@@ -240,6 +246,7 @@ export function useArticleLoader({
const eventId = le ? le.id : undefined const eventId = le ? le.id : undefined
if (coord && eventId) { if (coord && eventId) {
console.log('Loading highlights for article:', coord, eventId)
setHighlightsLoading(true) setHighlightsLoading(true)
// Clear highlights that don't belong to this article coordinate // Clear highlights that don't belong to this article coordinate
setHighlights((prev) => { setHighlights((prev) => {
@@ -248,28 +255,41 @@ export function useArticleLoader({
return h.eventReference === coord || h.eventReference === eventId return h.eventReference === coord || h.eventReference === eventId
}) })
}) })
await fetchHighlightsForArticle(
relayPool, try {
coord, await fetchHighlightsForArticle(
eventId, relayPool,
(highlight) => { coord,
if (!mountedRef.current) return eventId,
if (currentRequestIdRef.current !== requestId) return (highlight) => {
setHighlights((prev: Highlight[]) => { if (!mountedRef.current) return
if (prev.some((h: Highlight) => h.id === highlight.id)) return prev if (currentRequestIdRef.current !== requestId) return
const next = [highlight, ...prev] console.log('Received highlight:', highlight.id, highlight.content.substring(0, 50))
return next.sort((a, b) => b.created_at - a.created_at) setHighlights((prev: Highlight[]) => {
}) if (prev.some((h: Highlight) => h.id === highlight.id)) return prev
}, const next = [highlight, ...prev]
settingsRef.current, return next.sort((a, b) => b.created_at - a.created_at)
false, // force })
eventStore || undefined },
) settingsRef.current,
false, // force
eventStore || undefined
)
console.log('Finished loading highlights for article:', coord)
} catch (err) {
console.error('Failed to fetch highlights for article:', coord, err)
}
} else { } else {
console.log('No article coordinate or event ID available for highlights')
// No article event to fetch highlights for - clear and don't show loading // No article event to fetch highlights for - clear and don't show loading
setHighlights([]) setHighlights([])
setHighlightsLoading(false) setHighlightsLoading(false)
} }
}
// Always try to fetch highlights, even if we don't have the latest event yet
try {
await fetchHighlightsForCurrentArticle()
} catch (err) { } catch (err) {
console.error('Failed to fetch highlights:', err) console.error('Failed to fetch highlights:', err)
} finally { } finally {
@@ -277,6 +297,24 @@ export function useArticleLoader({
setHighlightsLoading(false) setHighlightsLoading(false)
} }
} }
// Add a fallback mechanism to ensure highlights are loaded
// This helps with cases where the initial highlight loading might fail
const fallbackTimeout = setTimeout(async () => {
if (mountedRef.current && currentRequestIdRef.current === requestId) {
console.log('Fallback: Attempting to load highlights again...')
try {
await fetchHighlightsForCurrentArticle()
} catch (err) {
console.error('Fallback highlight loading failed:', err)
}
}
}, 2000) // Retry after 2 seconds
// Clean up timeout if component unmounts or new article loads
return () => {
clearTimeout(fallbackTimeout)
}
} catch (err) { } catch (err) {
console.error('Failed to load article:', err) console.error('Failed to load article:', err)
if (mountedRef.current && currentRequestIdRef.current === requestId) { if (mountedRef.current && currentRequestIdRef.current === requestId) {
@@ -310,4 +348,44 @@ export function useArticleLoader({
setCurrentArticleEventId, setCurrentArticleEventId,
setCurrentArticle setCurrentArticle
]) ])
// Additional effect to ensure highlights are loaded when article coordinate changes
// This provides a backup mechanism in case the main loading doesn't work
useEffect(() => {
if (!relayPool || !eventStore) return
const loadHighlightsIfNeeded = async () => {
// Only load if we have a coordinate but no highlights are loading
if (currentArticleCoordinate && currentArticleEventId && !highlightsLoading) {
console.log('Backup: Loading highlights for coordinate:', currentArticleCoordinate)
try {
setHighlightsLoading(true)
await fetchHighlightsForArticle(
relayPool,
currentArticleCoordinate,
currentArticleEventId,
(highlight) => {
setHighlights((prev: Highlight[]) => {
if (prev.some((h: Highlight) => h.id === highlight.id)) return prev
const next = [highlight, ...prev]
return next.sort((a, b) => b.created_at - a.created_at)
})
},
settingsRef.current,
false, // force
eventStore
)
} catch (err) {
console.error('Backup highlight loading failed:', err)
} finally {
setHighlightsLoading(false)
}
}
}
// Small delay to ensure the main loading has a chance to work first
const timeout = setTimeout(loadHighlightsIfNeeded, 1000)
return () => clearTimeout(timeout)
}, [currentArticleCoordinate, currentArticleEventId, relayPool, eventStore, highlightsLoading])
} }