A sales dashboard exploring Async React and dynamic data fetching with Next.js 16's Cache Components. Features cascading filters (Region → Country + City in parallel, Category → Subcategory), streaming, URL-driven filter state, and optimistic updates with pending UI.
Built with Next.js 16, React 19, TailwindCSS v4, and shadcn/ui (Base UI).
bun install
bun run devOpen http://localhost:3000 in your browser.
app/ # Pages and layouts
components/
dashboard/ # Dashboard charts, wrappers, filters
design/ # Action prop components
ui/ # shadcn/ui primitives
data/
actions/ # Server Actions
queries/ # Data fetching with cache()
lib/
fetcher.ts # Shared SWR fetcher
- components/ui — shadcn/ui components. Add with
bunx shadcn@latest add <component-name> - components/design — Components that expose Action props and handle async coordination internally
Every page folder should contain everything it needs. Components and functions live at the nearest shared space in the hierarchy.
Naming: PascalCase for components, kebab-case for files/folders, camelCase for functions/hooks. Suffix transition-based functions with "Action".
Cache Components: Uses cacheComponents: true to statically render server components that don't access dynamic data. Keep pages non-async and push dynamic data access into <Suspense> boundaries to maximize the static shell. Use "use cache" with cacheLife() to explicitly cache additional components or functions.
Async React: Replace manual isLoading/isError state with React 19's coordination primitives — useTransition for tracking async work, useOptimistic for instant feedback, Suspense for loading boundaries, and use() for reading promises during render. See AGENTS.md for detailed patterns and examples.
- Fetching data — Queries in
data/queries/, wrapped withcache(). Await in Server Components directly, or pass the promise to a client component and unwrap withuse(). Use SWR withlib/fetcher.tsfor dependent or interactive client-side fetches (e.g. cascading filter options). - Mutating data — Server Actions in
data/actions/with"use server". Invalidate withrevalidateTag(). UseuseTransition+useOptimisticfor pending state and instant feedback. - Navigation — Wrap route changes in
useTransitionto getisPendingfor loading UI. - Caching — Add
"use cache"withcacheLife()to pages, components, or functions to include them in the static shell. - Errors —
error.tsxfor boundaries,not-found.tsx+notFound()for 404s. Errors thrown inside transitions automatically reach the nearest error boundary.
Uses ESLint and Prettier with format-on-save in VS Code. Configuration in eslint.config.mjs and .prettierrc. Open the .code-workspace file to ensure correct extensions are set.
bun run buildDeploy to Vercel for the easiest experience.
See the Next.js deployment docs for more details.