- Enhanced type definitions for the payload in CustomTooltip across multiple chart components to improve TypeScript support and maintainability.
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import {
|
|
LineChart,
|
|
Line,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
ResponsiveContainer,
|
|
} from 'recharts';
|
|
import { DailyMetrics } from '@/services/analytics/metrics';
|
|
import { parseDate, formatDateShort } from '@/lib/date-utils';
|
|
|
|
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: formatDateShort(parseDate(day.date)),
|
|
completionRate: day.completionRate,
|
|
completed: day.completed,
|
|
total: day.totalTasks,
|
|
}));
|
|
|
|
const CustomTooltip = ({
|
|
active,
|
|
payload,
|
|
label,
|
|
}: {
|
|
active?: boolean;
|
|
payload?: Array<{
|
|
payload: {
|
|
day: string;
|
|
date: string;
|
|
completionRate: number;
|
|
completed: number;
|
|
total: number;
|
|
};
|
|
}>;
|
|
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>
|
|
);
|
|
}
|