# Charts & Analytics Guide
## Table of Contents
1. [Overview Architecture](#overview-architecture)
2. [Parallel Routes Pattern](#parallel-routes-pattern)
3. [Chart Components](#chart-components)
4. [Stats Cards](#stats-cards)
5. [Skeleton Loading](#skeleton-loading)
6. [Adding a New Chart Section](#adding-a-new-chart-section)
---
## Overview Architecture
The analytics dashboard at `/dashboard/overview` uses **Next.js parallel routes** to load multiple chart sections independently. Each chart slot streams in as its data becomes ready — no waterfall, no blocking.
**File structure:**
```
src/app/dashboard/overview/
├── layout.tsx # Composes all slots into a grid
├── @area_stats/
│ ├── page.tsx # Async server component (fetches data)
│ ├── loading.tsx # Skeleton shown while streaming
│ └── error.tsx # Error boundary if fetch fails
├── @bar_stats/
│ ├── page.tsx
│ ├── loading.tsx
│ └── error.tsx
├── @pie_stats/
│ ├── page.tsx
│ ├── loading.tsx
│ └── error.tsx
└── @sales/
├── page.tsx
├── loading.tsx
└── error.tsx
src/features/overview/components/
├── area-graph.tsx # Client chart component
├── area-graph-skeleton.tsx # Matching skeleton
├── bar-graph.tsx
├── bar-graph-skeleton.tsx
├── pie-graph.tsx
├── pie-graph-skeleton.tsx
├── recent-sales.tsx
└── recent-sales-skeleton.tsx
```
---
## Parallel Routes Pattern
### Layout (`layout.tsx`)
The layout receives each parallel route as a prop and arranges them in a grid:
```tsx
export default function OverviewLayout({
sales,
pie_stats,
bar_stats,
area_stats
}: {
sales: React.ReactNode;
pie_stats: React.ReactNode;
bar_stats: React.ReactNode;
area_stats: React.ReactNode;
}) {
return (
{/* Stats cards row */}
Total Revenue
$45,231.89
+20.1% from last month
{/* ...more stat cards */}
{/* Charts grid — each slot loads independently */}
{area_stats}
{sales}
{bar_stats}
{pie_stats}
);
}
```
### Slot Page (`@area_stats/page.tsx`)
Each slot is an async server component that fetches data then renders the chart:
```tsx
import { delay } from '@/constants/mock-api';
import { AreaGraph } from '@/features/overview/components/area-graph';
export default async function AreaStatsPage() {
await delay(2000); // Simulates API fetch
return ;
}
```
### Slot Loading (`@area_stats/loading.tsx`)
```tsx
import { AreaGraphSkeleton } from '@/features/overview/components/area-graph-skeleton';
export default function Loading() {
return ;
}
```
### Slot Error (`@area_stats/error.tsx`)
```tsx
'use client';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Icons } from '@/components/icons';
export default function AreaStatsError({ error }: { error: Error }) {
return (
Error
Failed to load area stats: {error.message}
);
}
```
Each slot can fail independently without affecting others.
---
## Chart Components
All chart components are `'use client'` and use **Recharts** wrapped in shadcn's `ChartContainer`.
### Chart Config
Every chart defines a config object mapping data keys to labels and theme colors:
```tsx
import {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent
} from '@/components/ui/chart';
const chartConfig = {
desktop: { label: 'Desktop', color: 'var(--chart-1)' },
mobile: { label: 'Mobile', color: 'var(--chart-2)' }
} satisfies ChartConfig;
```
Theme colors `--chart-1` through `--chart-5` are defined in each theme's CSS file and automatically adapt to light/dark mode.
### Area Chart Example
```tsx
'use client';
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent
} from '@/components/ui/chart';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Icons } from '@/components/icons';
const chartData = [
{ month: 'January', desktop: 186, mobile: 80 },
{ month: 'February', desktop: 305, mobile: 200 }
// ...more months
];
const chartConfig = {
desktop: { label: 'Desktop', color: 'var(--chart-1)' },
mobile: { label: 'Mobile', color: 'var(--chart-2)' }
} satisfies ChartConfig;
export function AreaGraph() {
return (
Area Chart - Stacked
+12.5%
value.slice(0, 3)}
/>
} />
);
}
```
### Bar Chart Pattern
Same structure, using `BarChart` + `Bar`:
```tsx
} />
```
### Pie/Donut Chart Pattern
```tsx
} />
```
---
## Stats Cards
Stats cards are simple server-rendered `Card` components at the top of the layout — no parallel routes needed since they render instantly:
```tsx
Total Revenue
$45,231.89
+20.1% from last month
```
For dynamic stats that need data fetching, wrap in their own Suspense boundary or parallel route slot.
---
## Skeleton Loading
Each chart has a matching skeleton component. Pattern:
```tsx
import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
export function AreaGraphSkeleton() {
return (
);
}
```
Match the skeleton dimensions to the actual chart for smooth visual transitions.
---
## Adding a New Chart Section
To add a new chart (e.g., line chart for user growth):
### 1. Create the chart component
`src/features/overview/components/line-graph.tsx`:
```tsx
'use client';
import { Line, LineChart, CartesianGrid, XAxis } from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent
} from '@/components/ui/chart';
const chartConfig = {
users: { label: 'Users', color: 'var(--chart-3)' }
} satisfies ChartConfig;
const chartData = [
/* monthly user data */
];
export function LineGraph() {
return (
User Growth
} />
);
}
```
### 2. Create matching skeleton
`src/features/overview/components/line-graph-skeleton.tsx`
### 3. Create parallel route slot
```
src/app/dashboard/overview/@line_stats/
├── page.tsx → async, fetches data, returns
├── loading.tsx → returns
├── error.tsx → error alert
└── default.tsx → return null (fallback when route doesn't match)
```
`default.tsx` is required for parallel routes — return `null` or a fallback:
```tsx
export default function Default() {
return null;
}
```
### 4. Add slot to layout
Update `src/app/dashboard/overview/layout.tsx`:
```tsx
export default function OverviewLayout({
sales,
pie_stats,
bar_stats,
area_stats,
line_stats // ← add new slot
}: {
/* ...types */
}) {
return (
{/* existing charts */}
{line_stats}
);
}
```
### Available Recharts Components
Common chart types to use with `ChartContainer`:
- `AreaChart` + `Area` — filled area charts (stacked or standalone)
- `BarChart` + `Bar` — vertical/horizontal bars
- `LineChart` + `Line` — line/trend charts
- `PieChart` + `Pie` — pie/donut charts
- `RadarChart` + `Radar` — radar/spider charts
- `RadialBarChart` + `RadialBar` — radial progress bars
All support `ChartTooltip`, `ChartLegend`, and theme-aware colors via `var(--chart-N)`.