Spaces:
Sleeping
Sleeping
File size: 4,635 Bytes
3d4aa49 81c5264 fb78bf0 3d4aa49 5ee1afb 2cd7977 359f0ff 3d4aa49 2cd7977 73a5a82 81c5264 73a5a82 2cd7977 359f0ff 3d4aa49 5ee1afb 3d4aa49 fb78bf0 5ee1afb fb78bf0 3d4aa49 fb78bf0 5ee1afb fb78bf0 3d4aa49 73a5a82 81c5264 73a5a82 81c5264 73a5a82 81c5264 73a5a82 81c5264 73a5a82 008ec3f 81c5264 73a5a82 3d4aa49 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import {
BarChart, Bar, LineChart, Line, Legend,
XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer, Label,
} from 'recharts';
import './Charts.css';
const PAIN_DURING_COLOR = '#ef4444';
const PAIN_AFTER_COLOR = '#3b82f6';
const PAIN_CHARTS = [
{
location: 'left_knee',
title: 'Left Knee Pain',
duringKey: 'left_knee_during',
afterKey: 'left_knee_after',
},
{
location: 'right_knee',
title: 'Right Knee Pain',
duringKey: 'right_knee_during',
afterKey: 'right_knee_after',
},
];
function Charts({ data, painData }) {
if (!data || data.length === 0) {
return (
<div className="charts card">
<p className="empty-message">Log some runs to see your progress over time.</p>
</div>
);
}
// Shorten week labels for x-axis: "2026-W10" → "W10"
const chartData = data.map((d) => ({
...d,
label: d.week.replace(/^\d{4}-/, ''),
}));
// Determine which locations have data
const activePainCharts = painData?.locations
? PAIN_CHARTS.filter((chart) => {
const loc = painData.locations[chart.location];
return loc && loc.points.length > 0;
})
: [];
return (
<div className="charts">
<div className="chart-container card">
<h2>Weekly Distance</h2>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="label" />
<YAxis>
<Label value="Km" angle={-90} position="insideLeft" style={{ textAnchor: 'middle', fill: '#6b7280' }} />
</YAxis>
<Tooltip />
<Bar dataKey="distance" fill="var(--color-primary)" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
<div className="chart-container card">
<h2>Training Load Over Time</h2>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="label" />
<YAxis>
<Label value="Load" angle={-90} position="insideLeft" style={{ textAnchor: 'middle', fill: '#6b7280' }} />
</YAxis>
<Tooltip />
<Line
type="monotone"
dataKey="training_load"
stroke="var(--color-secondary)"
strokeWidth={2}
dot={{ r: 4 }}
/>
</LineChart>
</ResponsiveContainer>
</div>
{activePainCharts.map((chart) => {
const loc = painData.locations[chart.location];
return (
<div key={chart.location} className="chart-container card">
<h2>{chart.title}</h2>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={loc.points}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="label" padding={{ left: 20, right: 20 }} />
<YAxis domain={[0, 10]}>
<Label value="Pain" angle={-90} position="insideLeft" style={{ textAnchor: 'middle', fill: '#6b7280' }} />
</YAxis>
<Tooltip
content={({ payload }) => {
if (!payload || payload.length === 0) return null;
const pt = payload[0].payload;
const items = payload.filter((p) => p.value != null);
return (
<div className="pain-tooltip">
<p>{pt.date}</p>
{items.map((p) => (
<p key={p.name} style={{ color: p.color }}>{p.name}: {p.value}</p>
))}
</div>
);
}}
/>
<Legend wrapperStyle={{ paddingLeft: '65px' }} />
<Line
name="During"
dataKey="during"
stroke={PAIN_DURING_COLOR}
strokeWidth={1.5}
dot={{ fill: PAIN_DURING_COLOR, r: 4 }}
connectNulls
/>
<Line
name="After"
dataKey="after"
stroke={PAIN_AFTER_COLOR}
strokeWidth={1.5}
strokeDasharray="5 3"
dot={{ fill: PAIN_AFTER_COLOR, r: 4 }}
connectNulls
/>
</LineChart>
</ResponsiveContainer>
</div>
);
})}
</div>
);
}
export default Charts;
|