feat: metrics on Manager page
This commit is contained in:
97
components/dashboard/charts/CompletionRateChart.tsx
Normal file
97
components/dashboard/charts/CompletionRateChart.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
'use client';
|
||||
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
||||
import { DailyMetrics } from '@/services/metrics';
|
||||
|
||||
interface CompletionRateChartProps {
|
||||
data: DailyMetrics[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function CompletionRateChart({ data, className }: CompletionRateChartProps) {
|
||||
// Transformer les données pour le graphique
|
||||
const chartData = data.map(day => ({
|
||||
day: day.dayName.substring(0, 3), // Lun, Mar, etc.
|
||||
date: new Date(day.date).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' }),
|
||||
completionRate: day.completionRate,
|
||||
completed: day.completed,
|
||||
total: day.totalTasks
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: any[]; label?: string }) => {
|
||||
if (active && payload && payload.length) {
|
||||
const data = payload[0].payload;
|
||||
return (
|
||||
<div className="bg-[var(--card)] border border-[var(--border)] rounded-lg p-3 shadow-lg">
|
||||
<p className="font-medium mb-2">{`${label} (${data.date})`}</p>
|
||||
<p className="text-sm text-[var(--foreground)]">
|
||||
Taux de completion: {data.completionRate.toFixed(1)}%
|
||||
</p>
|
||||
<p className="text-sm text-[var(--muted-foreground)]">
|
||||
{data.completed} / {data.total} tâches
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Calculer la moyenne pour la ligne de référence
|
||||
const averageRate = data.reduce((sum, day) => sum + day.completionRate, 0) / data.length;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<ResponsiveContainer width="100%" height={250}>
|
||||
<LineChart
|
||||
data={chartData}
|
||||
margin={{ top: 20, right: 30, left: 20, bottom: 5 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
|
||||
<XAxis
|
||||
dataKey="day"
|
||||
stroke="var(--muted-foreground)"
|
||||
fontSize={12}
|
||||
/>
|
||||
<YAxis
|
||||
stroke="var(--muted-foreground)"
|
||||
fontSize={12}
|
||||
domain={[0, 100]}
|
||||
tickFormatter={(value) => `${value}%`}
|
||||
/>
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="completionRate"
|
||||
stroke="#10b981"
|
||||
strokeWidth={3}
|
||||
dot={{ fill: "#10b981", strokeWidth: 2, r: 4 }}
|
||||
activeDot={{ r: 6, stroke: "#10b981", strokeWidth: 2 }}
|
||||
/>
|
||||
{/* Ligne de moyenne */}
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey={() => averageRate}
|
||||
stroke="#94a3b8"
|
||||
strokeWidth={1}
|
||||
strokeDasharray="5 5"
|
||||
dot={false}
|
||||
activeDot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
{/* Légende */}
|
||||
<div className="flex items-center justify-center gap-4 mt-2 text-xs text-[var(--muted-foreground)]">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-0.5 bg-green-500"></div>
|
||||
<span>Taux quotidien</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-0.5 bg-gray-400 border-dashed"></div>
|
||||
<span>Moyenne ({averageRate.toFixed(1)}%)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user