From e918dc631b1b7b07ac1b80f0be3bfc9e5b7bb62a Mon Sep 17 00:00:00 2001 From: mysterio123865 Date: Wed, 29 Jul 2026 20:32:38 +0100 Subject: [PATCH] feat(perf): log page-load timing on portfolio page (#726) Wire useNavigationTiming('portfolio') into LandingPage so production builds emit the same Navigation Timing metrics as marketplace and profile. Co-authored-by: Cursor --- src/hooks/__tests__/useNavigationTiming.test.ts | 11 +++++++++-- src/hooks/useNavigationTiming.ts | 5 ++++- src/pages/LandingPage.tsx | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/hooks/__tests__/useNavigationTiming.test.ts b/src/hooks/__tests__/useNavigationTiming.test.ts index 63b4e7c..d9fb690 100644 --- a/src/hooks/__tests__/useNavigationTiming.test.ts +++ b/src/hooks/__tests__/useNavigationTiming.test.ts @@ -1,7 +1,7 @@ /** * Unit tests for useNavigationTiming — logs TTFB/DCL/load-complete via the - * Navigation Timing API after each mount of the marketplace and creator - * profile pages (#693). + * Navigation Timing API after each mount of the marketplace, creator + * profile, and portfolio pages (#693, #726). */ import { renderHook } from '@testing-library/react'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -254,6 +254,13 @@ describe('useNavigationTiming (#678) — page-load-perf log acceptance criteria' '[page-load-perf]', expect.objectContaining({ page_name: 'creator_profile' }) ); + + // Portfolio route (#726). + renderHook(() => useNavigationTiming('portfolio')); + expect(infoSpy).toHaveBeenLastCalledWith( + '[page-load-perf]', + expect.objectContaining({ page_name: 'portfolio' }) + ); }); it('does not emit a log when PerformanceNavigationTiming is unavailable', () => { diff --git a/src/hooks/useNavigationTiming.ts b/src/hooks/useNavigationTiming.ts index 79ae500..c08b86a 100644 --- a/src/hooks/useNavigationTiming.ts +++ b/src/hooks/useNavigationTiming.ts @@ -23,7 +23,10 @@ function readNavigationTiming(pageName: string): PageLoadTiming | null { /** * Logs page-load performance (TTFB / DOM Content Loaded / load complete) via - * the Navigation Timing API after the page becomes interactive (#693). + * the Navigation Timing API after the page becomes interactive (#693, #726). + * + * Used on marketplace, creator profile, and portfolio pages with + * `page_name` of `'marketplace'`, `'creator_profile'`, or `'portfolio'`. * * - Production only (`import.meta.env.PROD`) — never fires in dev/test, so * it can't add noise or overhead to local development. diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 1795546..0d6c73f 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -67,6 +67,7 @@ import { getPortfolioValueHelperText, } from '@/utils/portfolioValue.utils'; import { usePrefersReducedMotion } from '@/hooks/usePrefersReducedMotion'; +import { useNavigationTiming } from '@/hooks/useNavigationTiming'; import { CREATOR_LIST_SORT_LAYOUT_TRANSITION } from '@/utils/creatorListSortTransition'; import { creatorListKey } from '@/utils/creatorListKey.utils'; import { Check, ChevronDown, Copy, RefreshCw } from 'lucide-react'; @@ -240,6 +241,8 @@ type SortOption = 'featured' | 'price-asc' | 'price-desc' | 'supply-desc'; type CreatorListMode = 'pagination' | 'infinite'; function LandingPage() { + useNavigationTiming('portfolio'); + const [creators, setCreators] = useState([]); // Creators used for wallet holdings; kept separate from the marketplace // list so an empty API holdings response can show zero positions while