import { useMemo } from "react";
import {
LineChart,
Line,
BarChart,
Bar,
PieChart,
Pie,
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
Cell,
} from "recharts";
import type { ChartType } from "../../lib/api";
interface ChartRendererProps {
chartType: ChartType;
data: Record<string, unknown>[];
title?: string;
config?: Record<string, unknown>;
}
// Default color palette
const COLORS = [
"#9bc3ff",
"#ff9b9b",
"#9bffb3",
"#ffeb9b",
"#d49bff",
"#9bfff0",
"#ff9beb",
"#b3ff9b",
];
export function ChartRenderer({
chartType,
data,
title,
config,
}: ChartRendererProps) {
// Extract data keys (excluding 'name' which is used for labels)
const dataKeys = useMemo(() => {
if (data.length === 0) return [];
const keys = Object.keys(data[0]).filter((key) => key !== "name");
return keys;
}, [data]);
// Get colors from config or use defaults
const colors = (config?.colors as string[]) || COLORS;
const renderChart = () => {
switch (chartType) {
case "line":
return (
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="#333" />
<XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
<YAxis stroke="#9bc3ff" fontSize={12} />
<Tooltip
contentStyle={{
backgroundColor: "#111",
border: "1px solid #9bc3ff",
borderRadius: "0",
}}
/>
<Legend />
{dataKeys.map((key, i) => (
<Line
key={key}
type="monotone"
dataKey={key}
stroke={colors[i % colors.length]}
strokeWidth={2}
dot={{ fill: colors[i % colors.length] }}
/>
))}
</LineChart>
);
case "bar":
return (
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="#333" />
<XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
<YAxis stroke="#9bc3ff" fontSize={12} />
<Tooltip
contentStyle={{
backgroundColor: "#111",
border: "1px solid #9bc3ff",
borderRadius: "0",
}}
/>
<Legend />
{dataKeys.map((key, i) => (
<Bar key={key} dataKey={key} fill={colors[i % colors.length]} />
))}
</BarChart>
);
case "area":
return (
<AreaChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="#333" />
<XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
<YAxis stroke="#9bc3ff" fontSize={12} />
<Tooltip
contentStyle={{
backgroundColor: "#111",
border: "1px solid #9bc3ff",
borderRadius: "0",
}}
/>
<Legend />
{dataKeys.map((key, i) => (
<Area
key={key}
type="monotone"
dataKey={key}
stroke={colors[i % colors.length]}
fill={colors[i % colors.length]}
fillOpacity={0.3}
/>
))}
</AreaChart>
);
case "pie":
// For pie charts, use the first data key as value
const valueKey = dataKeys[0] || "value";
return (
<PieChart>
<Pie
data={data}
dataKey={valueKey}
nameKey="name"
cx="50%"
cy="50%"
outerRadius={80}
label={({ name, percent }) =>
`${name}: ${((percent ?? 0) * 100).toFixed(0)}%`
}
labelLine={{ stroke: "#9bc3ff" }}
>
{data.map((_, i) => (
<Cell key={i} fill={colors[i % colors.length]} />
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: "#111",
border: "1px solid #9bc3ff",
borderRadius: "0",
}}
/>
<Legend />
</PieChart>
);
default:
return <div className="text-red-400">Unknown chart type: {chartType}</div>;
}
};
return (
<div className="w-full">
{title && (
<h4 className="text-[#9bc3ff] font-mono text-sm mb-2">{title}</h4>
)}
<div className="h-64 w-full">
<ResponsiveContainer width="100%" height="100%">
{renderChart()}
</ResponsiveContainer>
</div>
</div>
);
}