localgreenchain/components/analytics/charts/PieChart.tsx
Claude 816c3b3f2e
Implement Agent 7: Advanced Analytics Dashboard
Add comprehensive analytics system with:
- Analytics data layer (aggregator, metrics, trends, cache)
- 6 API endpoints (overview, plants, transport, farms, sustainability, export)
- 6 chart components (LineChart, BarChart, PieChart, AreaChart, Gauge, Heatmap)
- 5 dashboard widgets (KPICard, TrendIndicator, DataTable, DateRangePicker, FilterPanel)
- 5 dashboard pages (overview, plants, transport, farms, sustainability)
- Export functionality (CSV, JSON)

Dependencies added: recharts, d3, date-fns

Also includes minor fixes:
- Fix EnvironmentalForm spread type error
- Fix AgentOrchestrator Map iteration issues
- Fix next.config.js image domains undefined error
- Add downlevelIteration to tsconfig
2025-11-23 04:02:07 +00:00

123 lines
2.9 KiB
TypeScript

/**
* Pie Chart Component
* Displays distribution data as a pie chart
*/
import {
PieChart as RechartsPieChart,
Pie,
Cell,
Tooltip,
Legend,
ResponsiveContainer,
} from 'recharts';
interface PieChartProps {
data: any[];
dataKey: string;
nameKey: string;
title?: string;
colors?: string[];
height?: number;
showLegend?: boolean;
innerRadius?: number;
outerRadius?: number;
formatter?: (value: number) => string;
}
const DEFAULT_COLORS = [
'#10b981', '#3b82f6', '#8b5cf6', '#f59e0b', '#ef4444',
'#06b6d4', '#ec4899', '#84cc16', '#f97316', '#6366f1',
];
export default function PieChart({
data,
dataKey,
nameKey,
title,
colors = DEFAULT_COLORS,
height = 300,
showLegend = true,
innerRadius = 0,
outerRadius = 80,
formatter = (value) => value.toLocaleString(),
}: PieChartProps) {
const RADIAN = Math.PI / 180;
const renderCustomizedLabel = ({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
percent,
}: any) => {
if (percent < 0.05) return null;
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="bold"
>
{`${(percent * 100).toFixed(0)}%`}
</text>
);
};
return (
<div className="bg-white rounded-lg shadow-lg p-6">
{title && <h3 className="text-lg font-bold text-gray-900 mb-4">{title}</h3>}
<ResponsiveContainer width="100%" height={height}>
<RechartsPieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={renderCustomizedLabel}
innerRadius={innerRadius}
outerRadius={outerRadius}
paddingAngle={2}
dataKey={dataKey}
nameKey={nameKey}
>
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={colors[index % colors.length]}
stroke="#fff"
strokeWidth={2}
/>
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #e5e7eb',
borderRadius: '8px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)',
}}
formatter={(value: number) => [formatter(value), '']}
/>
{showLegend && (
<Legend
layout="horizontal"
verticalAlign="bottom"
align="center"
wrapperStyle={{ paddingTop: '20px' }}
/>
)}
</RechartsPieChart>
</ResponsiveContainer>
</div>
);
}