- Changed project name from "towercontrol-temp" to "towercontrol" in package-lock.json and package.json. - Added Recharts library for data visualization in the dashboard. - Updated TODO.md to reflect completion of analytics and metrics integration tasks. - Enhanced RecentTasks component to utilize TaskPriority type for better type safety. - Minor layout adjustments in RecentTasks for improved UI.
101 lines
3.2 KiB
TypeScript
101 lines
3.2 KiB
TypeScript
'use client';
|
|
|
|
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend, PieLabelRenderProps } from 'recharts';
|
|
import { Card } from '@/components/ui/Card';
|
|
|
|
interface PriorityData {
|
|
priority: string;
|
|
count: number;
|
|
percentage: number;
|
|
[key: string]: string | number; // Index signature pour Recharts
|
|
}
|
|
|
|
interface PriorityDistributionChartProps {
|
|
data: PriorityData[];
|
|
title?: string;
|
|
}
|
|
|
|
// Couleurs pour chaque priorité
|
|
const PRIORITY_COLORS = {
|
|
'Faible': '#10b981', // green-500
|
|
'Moyenne': '#f59e0b', // amber-500
|
|
'Élevée': '#8b5cf6', // violet-500
|
|
'Urgente': '#ef4444', // red-500
|
|
'Non définie': '#6b7280' // gray-500
|
|
};
|
|
|
|
export function PriorityDistributionChart({ data, title = "Distribution des Priorités" }: PriorityDistributionChartProps) {
|
|
// Tooltip personnalisé
|
|
const CustomTooltip = ({ active, payload }: { active?: boolean; payload?: Array<{ payload: PriorityData }> }) => {
|
|
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="text-sm font-medium mb-1">{data.priority}</p>
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
{data.count} tâches ({data.percentage}%)
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// Légende personnalisée
|
|
const CustomLegend = ({ payload }: { payload?: Array<{ value: string; color: string }> }) => {
|
|
return (
|
|
<div className="flex flex-wrap justify-center gap-4 mt-4">
|
|
{payload?.map((entry, index: number) => (
|
|
<div key={index} className="flex items-center gap-2">
|
|
<div
|
|
className="w-3 h-3 rounded-full"
|
|
style={{ backgroundColor: entry.color }}
|
|
></div>
|
|
<span className="text-sm text-[var(--muted-foreground)]">
|
|
{entry.value}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Label personnalisé pour afficher les pourcentages
|
|
const renderLabel = (props: PieLabelRenderProps) => {
|
|
const percentage = typeof props.percent === 'number' ? props.percent * 100 : 0;
|
|
return percentage > 5 ? `${Math.round(percentage)}%` : '';
|
|
};
|
|
|
|
return (
|
|
<Card className="p-6">
|
|
<h3 className="text-lg font-semibold mb-4">{title}</h3>
|
|
<div className="h-64">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<PieChart>
|
|
<Pie
|
|
data={data}
|
|
cx="50%"
|
|
cy="50%"
|
|
labelLine={false}
|
|
label={renderLabel}
|
|
outerRadius={80}
|
|
fill="#8884d8"
|
|
dataKey="count"
|
|
nameKey="priority"
|
|
>
|
|
{data.map((entry, index) => (
|
|
<Cell
|
|
key={`cell-${index}`}
|
|
fill={PRIORITY_COLORS[entry.priority as keyof typeof PRIORITY_COLORS] || '#6b7280'}
|
|
/>
|
|
))}
|
|
</Pie>
|
|
<Tooltip content={<CustomTooltip />} />
|
|
<Legend content={<CustomLegend />} />
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|