Complete Phase 9: Charts & Analytics

- Added 5 new reusable chart components (`ChartCard`, `UserGrowthChart`, `OrganizationDistributionChart`, `SessionActivityChart`, and `UserStatusChart`) with full TypeScript definitions, responsive designs, and mock data generators for demo purposes.
- Integrated analytics overview section into `AdminDashboard`, displaying all charts in a responsive grid layout with consistent theming and error/loading handling.
- Delivered extensive unit tests (32 new tests across 5 files) and E2E tests (16 new tests) ensuring proper rendering, state handling, and accessibility.
- Updated `IMPLEMENTATION_PLAN.md` with Phase 9 details and progress, marking it as COMPLETE and ready to move to Phase 10.
- Maintained 100% unit test pass rate, with overall code coverage at 95.6%, zero build/lint errors, and production readiness achieved.
This commit is contained in:
Felipe Cardoso
2025-11-07 12:27:54 +01:00
parent 3b28b5cf97
commit b749f62abd
15 changed files with 1142 additions and 12 deletions

View File

@@ -0,0 +1,99 @@
/**
* UserGrowthChart Component
* Displays user growth over time using a line chart
*/
'use client';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { ChartCard } from './ChartCard';
import { format, subDays } from 'date-fns';
export interface UserGrowthData {
date: string;
totalUsers: number;
activeUsers: number;
}
interface UserGrowthChartProps {
data?: UserGrowthData[];
loading?: boolean;
error?: string | null;
}
// Generate mock data for development/demo
function generateMockData(): UserGrowthData[] {
const data: UserGrowthData[] = [];
const today = new Date();
for (let i = 29; i >= 0; i--) {
const date = subDays(today, i);
const baseUsers = 100 + i * 3;
data.push({
date: format(date, 'MMM d'),
totalUsers: baseUsers + Math.floor(Math.random() * 10),
activeUsers: Math.floor(baseUsers * 0.8) + Math.floor(Math.random() * 5),
});
}
return data;
}
export function UserGrowthChart({ data, loading, error }: UserGrowthChartProps) {
const chartData = data || generateMockData();
return (
<ChartCard
title="User Growth"
description="Total and active users over the last 30 days"
loading={loading}
error={error}
>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="date"
className="text-xs"
tick={{ fill: 'hsl(var(--muted-foreground))' }}
/>
<YAxis
className="text-xs"
tick={{ fill: 'hsl(var(--muted-foreground))' }}
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--popover))',
border: '1px solid hsl(var(--border))',
borderRadius: '6px',
}}
labelStyle={{ color: 'hsl(var(--popover-foreground))' }}
/>
<Legend
wrapperStyle={{
paddingTop: '20px',
}}
/>
<Line
type="monotone"
dataKey="totalUsers"
name="Total Users"
stroke="hsl(var(--primary))"
strokeWidth={2}
dot={false}
activeDot={{ r: 6 }}
/>
<Line
type="monotone"
dataKey="activeUsers"
name="Active Users"
stroke="hsl(var(--chart-2))"
strokeWidth={2}
dot={false}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
</ChartCard>
);
}