* feat: getBurndownData helper + computeBurndownDays (lib/insights/burndown.ts) Server-side aggregatie per active sprint: bouwt time-series met remaining en ideal per dag. Inclusief 4 Vitest-unit-tests voor de pure computeBurndownDays functie. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: voeg recharts toe aan dependencies Vereist door BurndownChart component in lib/insights. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: BurndownChart component (Recharts LineChart, ideal vs remaining) LineChart met two series: ideal (grijs, dashed) en remaining (status-in-progress blauw). ResponsiveContainer 100% x 240px, empty-state bij lege days-array. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
49 lines
1.2 KiB
TypeScript
49 lines
1.2 KiB
TypeScript
'use client'
|
|
|
|
import {
|
|
LineChart,
|
|
Line,
|
|
XAxis,
|
|
YAxis,
|
|
Tooltip,
|
|
Legend,
|
|
ResponsiveContainer,
|
|
} from 'recharts'
|
|
import type { BurndownSprint } from '@/lib/insights/burndown'
|
|
|
|
interface Props {
|
|
sprint: BurndownSprint
|
|
}
|
|
|
|
export function BurndownChart({ sprint }: Props) {
|
|
if (sprint.days.length === 0) {
|
|
return <p className="text-muted-foreground text-sm">Geen sprint-data</p>
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<h3 className="text-sm font-medium text-foreground">
|
|
{sprint.productName} — {sprint.sprintGoal}
|
|
</h3>
|
|
<ResponsiveContainer width="100%" height={240}>
|
|
<LineChart data={sprint.days}>
|
|
<XAxis dataKey="day" tick={{ fontSize: 11 }} />
|
|
<YAxis allowDecimals={false} tick={{ fontSize: 11 }} />
|
|
<Tooltip />
|
|
<Legend />
|
|
<Line
|
|
dataKey="ideal"
|
|
stroke="var(--muted-foreground)"
|
|
strokeDasharray="4 4"
|
|
dot={false}
|
|
/>
|
|
<Line
|
|
dataKey="remaining"
|
|
stroke="var(--status-in-progress)"
|
|
dot={false}
|
|
/>
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
)
|
|
}
|