From 5a03aa688dccdee671dd6e685a046d89831bd24e Mon Sep 17 00:00:00 2001 From: Joe Parks <26990067+jowparks@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:01:14 -0700 Subject: [PATCH] fix: keep older-blocks pagination in shadow delta view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shadow-delta branch hardcoded nextCursor: null, so "Older blocks →" disappeared whenever shadow delta was enabled. Derive the cursor from the oldest shadow block on a full page (via the API's exclusive `before` param) and thread the URL cursor through the shadow fetch so paging works. --- app/internal-explorer/blocks/page.tsx | 15 +++++---- .../library/shadow-pagination.test.ts | 31 +++++++++++++++++++ .../library/shadow-pagination.ts | 14 +++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 app/internal-explorer/library/shadow-pagination.test.ts create mode 100644 app/internal-explorer/library/shadow-pagination.ts diff --git a/app/internal-explorer/blocks/page.tsx b/app/internal-explorer/blocks/page.tsx index d90d7c3..2ef1ad7 100644 --- a/app/internal-explorer/blocks/page.tsx +++ b/app/internal-explorer/blocks/page.tsx @@ -13,6 +13,7 @@ import { ActiveBlockButton } from '../components/ActiveBlockButton'; import { explorerApi } from '../library/client'; import { formatInteger } from '../library/explorer-format'; import { explorerHref } from '../library/links'; +import { nextShadowCursor } from '../library/shadow-pagination'; import type { BlocksResponse, ShadowBlockSummary } from '../library/types'; import { useExplorerChain } from '../library/useExplorerChain'; import { useShadowDelta } from '../library/useShadowDelta'; @@ -76,13 +77,13 @@ function BlocksContent() { setShadowCandidates({}); explorerApi - .recentShadowBlocks(chain, { limit: PAGE_LIMIT }, controller.signal) + .recentShadowBlocks(chain, { limit: PAGE_LIMIT, before: cursor }, controller.signal) .then(async (shadows) => { if (cancelled) return; if (shadows.length === 0) { setData({ blocks: [], - page: { cursor: null, limit: PAGE_LIMIT, latestBlockNumber: 0, nextCursor: null, hasMore: false }, + page: { cursor: cursor ?? null, limit: PAGE_LIMIT, latestBlockNumber: 0, nextCursor: null, hasMore: false }, }); return; } @@ -101,15 +102,17 @@ function BlocksContent() { .map((shadow) => [shadow.canonicalHash!.toLowerCase(), [shadow]]), ); + const nextCursor = nextShadowCursor(shadows, PAGE_LIMIT); + setShadowCandidates(candidates); setData({ blocks: orderedBlocks, page: { - cursor: null, + cursor: cursor ?? null, limit: PAGE_LIMIT, latestBlockNumber: orderedBlocks[0]?.number ?? 0, - nextCursor: null, - hasMore: false, + nextCursor, + hasMore: nextCursor !== null, }, }); }) @@ -125,7 +128,7 @@ function BlocksContent() { cancelled = true; controller.abort(); }; - }, [chain, showShadowDelta]); + }, [chain, cursor, showShadowDelta]); return (