From 0baf75462c14eaf0ffa281fbca8d269771cb847b Mon Sep 17 00:00:00 2001 From: Gigi Date: Sun, 19 Oct 2025 00:34:21 +0200 Subject: [PATCH] refactor(explore): use writingsController for 'mine' posts; keep fetches non-blocking and centralized --- src/components/Explore.tsx | 99 ++++++++++++++------------------------ 1 file changed, 36 insertions(+), 63 deletions(-) diff --git a/src/components/Explore.tsx b/src/components/Explore.tsx index 3553d7bf..2b14e94c 100644 --- a/src/components/Explore.tsx +++ b/src/components/Explore.tsx @@ -27,6 +27,7 @@ import { KINDS } from '../config/kinds' import { eventToHighlight } from '../services/highlightEventProcessor' import { useStoreTimeline } from '../hooks/useStoreTimeline' import { dedupeHighlightsById, dedupeWritingsByReplaceable } from '../utils/dedupe' +import { writingsController } from '../services/writingsController' const { getArticleTitle, getArticleImage, getArticlePublished, getArticleSummary } = Helpers @@ -97,6 +98,36 @@ const Explore: React.FC = ({ relayPool, eventStore, settings, acti } }, []) + // Subscribe to writings controller for "mine" posts and seed immediately + useEffect(() => { + // Seed from controller's current state + const seed = writingsController.getWritings() + if (seed.length > 0) { + setBlogPosts(prev => { + const merged = dedupeWritingsByReplaceable([...prev, ...seed]) + return merged.sort((a, b) => { + const timeA = a.published || a.event.created_at + const timeB = b.published || b.event.created_at + return timeB - timeA + }) + }) + } + + // Stream updates + const unsub = writingsController.onWritings((posts) => { + setBlogPosts(prev => { + const merged = dedupeWritingsByReplaceable([...prev, ...posts]) + return merged.sort((a, b) => { + const timeA = a.published || a.event.created_at + const timeB = b.published || b.event.created_at + return timeB - timeA + }) + }) + }) + + return () => unsub() + }, []) + // Update visibility when login state changes useEffect(() => { if (!activeAccount) { @@ -327,31 +358,8 @@ const Explore: React.FC = ({ relayPool, eventStore, settings, acti // Fetch friends content and (optionally) nostrverse + mine content in parallel const relayUrls = Array.from(relayPool.relays.values()).map(relay => relay.url) const contactsArray = Array.from(contacts) - const myPostsPromise = fetchBlogPostsFromAuthors( - relayPool, - activeAccount ? [activeAccount.pubkey] : [], - relayUrls, - (post) => { - // Stream my posts - setBlogPosts(prev => { - const dTag = post.event.tags.find(t => t[0] === 'd')?.[1] || '' - const key = `${post.author}:${dTag}` - const existingIndex = prev.findIndex(p => { - const pDTag = p.event.tags.find(t => t[0] === 'd')?.[1] || '' - return `${p.author}:${pDTag}` === key - }) - if (existingIndex >= 0) { - const existing = prev[existingIndex] - if (post.event.created_at <= existing.event.created_at) return prev - const next = [...prev] - next[existingIndex] = post - return next.sort((a, b) => (b.published || b.event.created_at) - (a.published || a.event.created_at)) - } - const next = [...prev, post] - return next.sort((a, b) => (b.published || b.event.created_at) - (a.published || a.event.created_at)) - }) - } - ) + // Use centralized writingsController for my posts (non-blocking) + const myPostsPromise: Promise = Promise.resolve(writingsController.getWritings()) setHasLoadedMine(true) const nostrversePostsPromise = visibility.nostrverse ? fetchNostrverseBlogPosts(relayPool, relayUrls, 50, eventStore || undefined, (post) => { @@ -467,46 +475,11 @@ const Explore: React.FC = ({ relayPool, eventStore, settings, acti }, [visibility.nostrverse, activeAccount, relayPool, eventStore, hasLoadedNostrverse]) // Lazy-load my writings when user toggles "mine" on (logged in) + // No direct fetch here; writingsController streams my posts centrally useEffect(() => { - if (!activeAccount || !relayPool || !visibility.mine || hasLoadedMine) return - const relayUrls = Array.from(relayPool.relays.values()).map(relay => relay.url) + if (!activeAccount || !visibility.mine || hasLoadedMine) return setHasLoadedMine(true) - fetchBlogPostsFromAuthors( - relayPool, - [activeAccount.pubkey], - relayUrls, - (post) => { - setBlogPosts(prev => { - const dTag = post.event.tags.find(t => t[0] === 'd')?.[1] || '' - const key = `${post.author}:${dTag}` - const existingIndex = prev.findIndex(p => { - const pDTag = p.event.tags.find(t => t[0] === 'd')?.[1] || '' - return `${p.author}:${pDTag}` === key - }) - if (existingIndex >= 0) { - const existing = prev[existingIndex] - if (post.event.created_at <= existing.event.created_at) return prev - const next = [...prev] - next[existingIndex] = post - return next.sort((a, b) => (b.published || b.event.created_at) - (a.published || a.event.created_at)) - } - const next = [...prev, post] - return next.sort((a, b) => (b.published || b.event.created_at) - (a.published || a.event.created_at)) - }) - } - ).then((finalPosts) => { - setBlogPosts(prev => { - const byKey = new Map() - for (const p of [...prev, ...finalPosts]) { - const dTag = p.event.tags.find(t => t[0] === 'd')?.[1] || '' - const key = `${p.author}:${dTag}` - const existing = byKey.get(key) - if (!existing || p.event.created_at > existing.event.created_at) byKey.set(key, p) - } - return Array.from(byKey.values()).sort((a, b) => (b.published || b.event.created_at) - (a.published || a.event.created_at)) - }) - }).catch(() => {}) - }, [visibility.mine, activeAccount, relayPool, hasLoadedMine]) + }, [visibility.mine, activeAccount, hasLoadedMine]) // Pull-to-refresh const { isRefreshing, pullPosition } = usePullToRefresh({