Files
knur-app/components/volume-trend-chart.tsx
Dominik Klarkowski d908965c95 init
2026-06-22 11:32:27 +02:00

106 lines
2.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import {
Bar,
BarChart,
Legend,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
type WorkoutDataPoint = {
label: string;
date: string;
name: string;
volumeKg: number;
};
type Props = {
data: WorkoutDataPoint[];
};
const COLORS: Record<string, string> = {};
const PALETTE = ["var(--color-accent)", "#5b9bd5", "#70ad47", "#ffc000", "#ed7d31"];
function getColor(name: string): string {
if (!COLORS[name]) {
COLORS[name] = PALETTE[Object.keys(COLORS).length % PALETTE.length];
}
return COLORS[name];
}
export function VolumeTrendChart({ data }: Props) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) {
return (
<div className="w-full rounded-lg border border-muted/40 bg-surface p-4">
<div className="mb-2 h-4 w-56 animate-pulse rounded bg-muted/30" />
<div className="h-[220px] animate-pulse rounded bg-muted/20" />
</div>
);
}
const workoutNames = [...new Set(data.map((d) => d.name))];
const chartData: Record<string, string | number>[] = [];
const grouped = new Map<string, Record<string, string | number>>();
for (const point of data) {
const key = point.date;
if (!grouped.has(key)) {
grouped.set(key, { label: point.label });
}
const entry = grouped.get(key)!;
entry[point.name] = ((entry[point.name] as number) || 0) + point.volumeKg;
}
for (const entry of grouped.values()) {
chartData.push(entry);
}
return (
<div className="w-full rounded-lg border border-muted/40 bg-surface p-4">
<div className="mb-2 text-sm text-fg/60">
Trend wolumenu treningowego wg typu
</div>
<ResponsiveContainer width="100%" height={220}>
<BarChart data={chartData} margin={{ top: 8, right: 8, left: 0, bottom: 0 }}>
<XAxis dataKey="label" stroke="var(--color-fg)" opacity={0.5} fontSize={11} />
<YAxis stroke="var(--color-fg)" opacity={0.5} fontSize={11} width={48} />
<Tooltip
cursor={{ fill: "var(--color-bg)" }}
contentStyle={{
background: "var(--color-bg)",
border: "1px solid var(--color-muted)",
borderRadius: 8,
fontSize: 12,
color: "var(--color-fg)",
}}
formatter={(value) => [
`${Math.round(Number(value)).toLocaleString("pl-PL")} kg`,
"Wolumen",
]}
/>
<Legend
wrapperStyle={{ fontSize: 12, color: "var(--color-fg)" }}
/>
{workoutNames.map((name) => (
<Bar
key={name}
dataKey={name}
fill={getColor(name)}
radius={[4, 4, 0, 0]}
stackId="volume"
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
);
}