From f1778babb672be9f1df0692a39cb2d02f2a07958 Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Wed, 18 Feb 2026 09:40:18 -0600 Subject: [PATCH] fix: mobile action bar layout + infinite scroll stats/author drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - NoteCard: replace fixed gap-6 action bar with justify-between + max-w-xs on mobile so stats never overflow or wrap on narrow screens - usePageBatch: new hook that batches author/stats prefetches per page instead of across the whole accumulated feed. The old approach used a single query key built from ALL loaded event IDs; adding page 2 changed the key, abandoned the old cache entry, and fired a fresh request for every item — causing stats and author data to visually disappear on pages 2 and 3. Now each page gets its own stable cache entry that is never invalidated by subsequent page loads. - Feed: swap useAuthors + useBatchEventStats calls for usePageBatch Co-authored-by: shakespeare.diy --- src/components/Feed.tsx | 27 ++----- src/components/NoteCard.tsx | 16 ++--- src/hooks/usePageBatch.ts | 140 ++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 src/hooks/usePageBatch.ts diff --git a/src/components/Feed.tsx b/src/components/Feed.tsx index b9bafcd4..505ff953 100644 --- a/src/components/Feed.tsx +++ b/src/components/Feed.tsx @@ -11,8 +11,7 @@ import LoginDialog from '@/components/auth/LoginDialog'; import SignupDialog from '@/components/auth/SignupDialog'; import { useFeed } from '@/hooks/useFeed'; import { useCurrentUser } from '@/hooks/useCurrentUser'; -import { useAuthors } from '@/hooks/useAuthors'; -import { useBatchEventStats } from '@/hooks/useTrending'; +import { usePageBatch } from '@/hooks/usePageBatch'; import { cn } from '@/lib/utils'; import type { FeedItem } from '@/hooks/useFeed'; @@ -68,26 +67,10 @@ export function Feed() { return items; }, [data?.pages]); - // Batch-prefetch all author profiles in a single relay query instead of - // firing N individual useAuthor() calls from each NoteCard. The results - // are seeded into the ['author', pubkey] cache so NoteCard's own - // useAuthor() resolves instantly from cache. - const feedPubkeys = useMemo(() => { - const keys = new Set(); - for (const item of feedItems) { - keys.add(item.event.pubkey); - if (item.repostedBy) keys.add(item.repostedBy); - } - return [...keys]; - }, [feedItems]); - useAuthors(feedPubkeys); - - // Batch-prefetch interaction stats for all visible events in a single - // relay query instead of firing 2 queries per NoteCard. - const feedEventIds = useMemo(() => { - return feedItems.map((item) => item.event.id); - }, [feedItems]); - useBatchEventStats(feedEventIds); + // Batch-prefetch authors and stats per page so that each page's cache + // entry is stable — adding a new page doesn't invalidate previous pages' + // already-fetched data. + usePageBatch(data?.pages ?? []); const handleLogin = () => { setLoginDialogOpen(false); diff --git a/src/components/NoteCard.tsx b/src/components/NoteCard.tsx index fe1437cf..c93f4e79 100644 --- a/src/components/NoteCard.tsx +++ b/src/components/NoteCard.tsx @@ -250,22 +250,22 @@ export function NoteCard({ event, className, repostedBy, compact }: NoteCardProp {/* Action buttons — hidden in compact/embed mode */} {!compact && ( <> -
+
@@ -278,16 +278,16 @@ export function NoteCard({ event, className, repostedBy, compact }: NoteCardProp