110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts';
|
|
|
|
interface StatusDistributionData {
|
|
status: string;
|
|
count: number;
|
|
percentage: number;
|
|
color: string;
|
|
}
|
|
|
|
interface StatusDistributionChartProps {
|
|
data: StatusDistributionData[];
|
|
className?: string;
|
|
}
|
|
|
|
export function StatusDistributionChart({ data, className }: StatusDistributionChartProps) {
|
|
// Transformer les statuts pour l'affichage
|
|
const getStatusLabel = (status: string) => {
|
|
const labels: { [key: string]: string } = {
|
|
'pending': 'En attente',
|
|
'in_progress': 'En cours',
|
|
'blocked': 'Bloquées',
|
|
'done': 'Terminées',
|
|
'archived': 'Archivées'
|
|
};
|
|
return labels[status] || status;
|
|
};
|
|
|
|
const chartData = data.map(item => ({
|
|
...item,
|
|
name: getStatusLabel(item.status),
|
|
value: item.count
|
|
}));
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const CustomTooltip = ({ active, payload }: { active?: boolean; payload?: any[] }) => {
|
|
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-1">{data.name}</p>
|
|
<p className="text-sm text-[var(--foreground)]">
|
|
{data.count} tâches ({data.percentage}%)
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const CustomLabel = (props: any) => {
|
|
const { cx, cy, midAngle, innerRadius, outerRadius, percent } = props;
|
|
if (percent < 0.05) return null; // Ne pas afficher les labels pour les petites sections
|
|
|
|
const RADIAN = Math.PI / 180;
|
|
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
|
|
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
|
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
|
|
|
return (
|
|
<text
|
|
x={x}
|
|
y={y}
|
|
fill="white"
|
|
textAnchor={x > cx ? 'start' : 'end'}
|
|
dominantBaseline="central"
|
|
fontSize={12}
|
|
fontWeight="medium"
|
|
>
|
|
{`${(percent * 100).toFixed(0)}%`}
|
|
</text>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className={className}>
|
|
<ResponsiveContainer width="100%" height={250}>
|
|
<PieChart>
|
|
<Pie
|
|
data={chartData}
|
|
cx="50%"
|
|
cy="50%"
|
|
labelLine={false}
|
|
label={CustomLabel}
|
|
outerRadius={80}
|
|
fill="#8884d8"
|
|
dataKey="value"
|
|
>
|
|
{chartData.map((entry, index) => (
|
|
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
))}
|
|
</Pie>
|
|
<Tooltip content={<CustomTooltip />} />
|
|
<Legend
|
|
verticalAlign="bottom"
|
|
height={36}
|
|
formatter={(value, entry: { color?: string }) => (
|
|
<span style={{ color: entry.color, fontSize: '12px' }}>
|
|
{value}
|
|
</span>
|
|
)}
|
|
/>
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
);
|
|
}
|