Skip to content

Error boundary for chart, marketplace SWR cache, and page-load perf logging - #717

Merged
Chucks1093 merged 3 commits into
accesslayerorg:devfrom
davedumto:feat/error-boundary-swr-cache-nav-timing-690-691-693
Jul 28, 2026
Merged

Error boundary for chart, marketplace SWR cache, and page-load perf logging#717
Chucks1093 merged 3 commits into
accesslayerorg:devfrom
davedumto:feat/error-boundary-swr-cache-nav-timing-690-691-693

Conversation

@davedumto

Copy link
Copy Markdown

Summary

Three independent, related improvements to the marketplace/creator-profile experience: a scoped error boundary around the bonding curve chart, stale-while-revalidate caching for the marketplace list, and Navigation Timing API perf logging on the two key pages.

closes #690
closes #691
closes #693

Changes

  • Add error boundary around the bonding curve chart to prevent a chart crash from breaking the whole profile page #690 — Error boundary around the bonding curve chart: SectionErrorBoundary gained two new optional, backward-compatible props (title, description) so its fallback copy can be overridden per-section (all existing callers — LandingPage.tsx's creator list/AppErrorBoundary — are unaffected since neither prop is passed there). The bonding-curve sparkline block in CreatorCard.tsx is now wrapped in <SectionErrorBoundary title="Chart unavailable — try refreshing" description="" ...>, so a chart-render crash no longer takes down the whole card. Retry is manual only (clicking "Retry" resets the boundary) — there is no auto-retry loop. The caught error is logged via the boundary's existing componentDidCatchconsole.error.

  • Add stale-while-revalidate cache behaviour to the marketplace key list query #691 — Stale-while-revalidate cache for the marketplace list: useInfiniteCreatorMarketplace now sets staleTime: 60_000 on its useInfiniteQuery, so a cached page renders instantly (no spinner) on remount within 60s while React Query silently refetches in the background once stale. The hook exposes a new isRefreshing flag — true only while a background refetch is in flight after data has already been shown once, never during the initial load or a next-page fetch — which CreatorMarketplaceInfiniteList uses to show a small "Refreshing…" role="status" indicator. useTradeMutation's onSettled now also invalidates queryKeys.creators.all (in addition to the existing wallet-holdings invalidation), so a completed buy/sell doesn't have to wait out the 60s staleTime before the marketplace reflects the trade.

  • Add page load performance log using the Navigation Timing API on the marketplace and creator profile pages #693 — Page-load performance logging: Reworked the existing (but incomplete) useNavigationTiming hook to accept a pageName, read performance.getEntriesByType('navigation')[0] after the page becomes interactive, and log { page_name, ttfb, dcl, load_complete } via console.info('[page-load-perf]', ...). Logging is gated to import.meta.env.PROD (never fires in dev/test), debounced via a ref guard to exactly one log per mount, and happens asynchronously after the load event so it never blocks rendering. The hook's call site moved from App.tsx (fired globally on every route with no production gate or exact field names) to HomePage (page_name: 'marketplace') and CreatorDetailPage (page_name: 'creator_profile') specifically, matching the issue's scope.

Test plan

  • SectionErrorBoundary.test.tsx: 9 tests (4 pre-existing + 5 new) covering custom title/description, description omission, manual-only retry, and the componentDidCatch log — all passing.
  • useInfiniteCreatorMarketplace.test.ts: 7 tests (4 pre-existing + 3 new) covering instant cache-hit on remount, isRefreshing toggling correctly around a background refetch, and isRefreshing staying false during initial/next-page loads — all passing.
  • CreatorMarketplaceInfiniteList.test.tsx: 9 tests (6 pre-existing + 3 new) covering the "Refreshing…" indicator's visibility and that cached creators keep rendering (no skeleton regression) during a background refresh — all passing.
  • tradeCacheInvalidation.test.ts: 3 tests (2 pre-existing + 1 new) covering that queryKeys.creators.all is invalidated on trade settlement — all passing.
  • useNavigationTiming.test.ts (new file): 5 tests covering the PROD gate, exact log shape, the load-event fallback path, single-log-per-mount debouncing, and the no-entry-available case — all passing.
  • npx tsc -b (project build/typecheck) and npx eslint on all touched files are clean.
  • Ran the full vitest suite: all failures present (TransactionHistory.*, WalletActivityFeed.infiniteScroll.integration.test.tsx) are pre-existing and unrelated — confirmed by reproducing the same localStorage.clear is not a function failure with these commits fully reverted (stash test). No regressions introduced by this PR.

LandingPage.tsx (which also renders creator cards/bonding-curve charts and already consumes SectionErrorBoundary elsewhere) isn't currently wired into routes.tsx and appears to be a separate, not-yet-routed page — #690's fix was applied at the CreatorCard component level instead, so it covers every place the chart is actually rendered today, including wherever LandingPage eventually gets wired up.

…layerorg#690)

Extends SectionErrorBoundary with optional title/description props
(backward compatible, defaulting to prior copy) so the bonding curve
sparkline in CreatorCard can fail independently without taking down the
whole card or profile page. Retry is manual only (no auto-retry loop).
…esslayerorg#691)

Sets a 60s staleTime on useInfiniteCreatorMarketplace so cached pages
render instantly on remount while React Query silently refetches in
the background. Adds isRefreshing (true only during a background
refetch, never during the initial load or next-page fetch) and wires
a "Refreshing..." indicator into CreatorMarketplaceInfiniteList.
Buy/sell trades now also invalidate queryKeys.creators.all in
useTradeMutation's onSettled so the marketplace list never has to
wait out the staleTime after a completed trade.
…cesslayerorg#693)

Reworks useNavigationTiming to accept a page_name and read
performance.getEntriesByType('navigation')[0] after the page becomes
interactive, logging { page_name, ttfb, dcl, load_complete } via
console.info('[page-load-perf]', ...). Gated to import.meta.env.PROD
so it never fires in dev/test, debounced via a ref guard to exactly
one log per mount, and read asynchronously (after 'load') so it never
blocks rendering.

Moves the call site from App.tsx (global, every route) to HomePage
(marketplace) and CreatorDetailPage (creator profile) specifically,
per the issue's scope. The previous global hook lacked a production
gate and used different field names, so it didn't satisfy the ask.
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@davedumto Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093
Chucks1093 merged commit 2d71d2c into accesslayerorg:dev Jul 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants