Problem
QueryProvider is a client-only wrapper that forces the entire app to block on hydration before any content renders. No <Suspense> boundaries exist around heavy components (PopularItemsChart, RecentActivity, data tables). All admin pages are "use client" with no code splitting - all chart and table libraries are bundled into the initial JS payload even on pages that don't use them.
Proposed Solution
- Wrap
PopularItemsChart and RecentActivity with Next.js dynamic() (ssr: false) to split them into separate chunks
- Add
<Suspense fallback={<ChartSkeleton />}> around each dynamically imported chart
- Add
<Suspense fallback={<TableSkeleton />}> around each admin data table section
- Restructure
app/layout.tsx so the static navigation shell renders before QueryProvider hydrates
- Use
useTransition for navigation-triggered data loads
Acceptance Criteria
Problem
QueryProvideris a client-only wrapper that forces the entire app to block on hydration before any content renders. No<Suspense>boundaries exist around heavy components (PopularItemsChart,RecentActivity, data tables). All admin pages are"use client"with no code splitting - all chart and table libraries are bundled into the initial JS payload even on pages that don't use them.Proposed Solution
PopularItemsChartandRecentActivitywith Next.jsdynamic()(ssr: false) to split them into separate chunks<Suspense fallback={<ChartSkeleton />}>around each dynamically imported chart<Suspense fallback={<TableSkeleton />}>around each admin data table sectionapp/layout.tsxso the static navigation shell renders beforeQueryProviderhydratesuseTransitionfor navigation-triggered data loadsAcceptance Criteria