diff --git a/app/(app)/insights/components/sprint-status-donut.tsx b/app/(app)/insights/components/sprint-status-donut.tsx new file mode 100644 index 0000000..ac4e433 --- /dev/null +++ b/app/(app)/insights/components/sprint-status-donut.tsx @@ -0,0 +1,48 @@ +'use client' + +import { PieChart, Pie, Cell, Tooltip, Legend, ResponsiveContainer } from 'recharts' +import type { StatusCount } from '@/lib/insights/sprint-status' + +interface Props { + data: StatusCount[] +} + +const STATUS_COLORS: Record = { + TO_DO: 'var(--status-todo)', + IN_PROGRESS: 'var(--status-in-progress)', + DONE: 'var(--status-done)', +} + +const STATUS_LABELS: Record = { + TO_DO: 'To do', + IN_PROGRESS: 'In progress', + DONE: 'Done', +} + +export function SprintStatusDonut({ data }: Props) { + if (data.length === 0) { + return

Geen actieve sprint-taken

+ } + + const labeled = data.map(d => ({ ...d, name: STATUS_LABELS[d.status] ?? d.status })) + + return ( + + + + {labeled.map(entry => ( + + ))} + + + + + + ) +} diff --git a/lib/insights/sprint-status.ts b/lib/insights/sprint-status.ts new file mode 100644 index 0000000..51b619a --- /dev/null +++ b/lib/insights/sprint-status.ts @@ -0,0 +1,39 @@ +import { prisma } from '@/lib/prisma' +import { productAccessFilter } from '@/lib/product-access' + +export type SprintStatusGroup = 'TO_DO' | 'IN_PROGRESS' | 'DONE' + +export interface StatusCount { + status: SprintStatusGroup + count: number +} + +// Maps REVIEW → IN_PROGRESS so donut shows 3 buckets only +function toGroup(status: string): SprintStatusGroup { + if (status === 'DONE') return 'DONE' + if (status === 'TO_DO') return 'TO_DO' + return 'IN_PROGRESS' +} + +export async function getSprintStatusBreakdown(userId: string): Promise { + const tasks = await prisma.task.findMany({ + where: { + story: { + sprint: { + status: 'ACTIVE', + product: productAccessFilter(userId), + }, + }, + }, + select: { status: true }, + }) + + const counts: Record = { TO_DO: 0, IN_PROGRESS: 0, DONE: 0 } + for (const t of tasks) { + counts[toGroup(t.status)]++ + } + + return (Object.entries(counts) as [SprintStatusGroup, number][]) + .filter(([, count]) => count > 0) + .map(([status, count]) => ({ status, count })) +}