From 876ea5ed8e22471160dc49da912e9d889507e1ea Mon Sep 17 00:00:00 2001 From: janpeter visser Date: Sat, 2 May 2026 16:18:15 +0200 Subject: [PATCH] =?UTF-8?q?feat(insights):=20add=20BacklogHealthCard=20?= =?UTF-8?q?=E2=80=94=20counters=20+=20stuck-tasks=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three counter tiles (green checkmark when 0, amber warning icon otherwise) and a table of stuck tasks with orange/red day-colouring and router.push deeplinks to /products/[id]/solo?task=... Co-Authored-By: Claude Sonnet 4.6 --- .../insights/components/backlog-health.tsx | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 app/(app)/insights/components/backlog-health.tsx diff --git a/app/(app)/insights/components/backlog-health.tsx b/app/(app)/insights/components/backlog-health.tsx new file mode 100644 index 0000000..fbf23c9 --- /dev/null +++ b/app/(app)/insights/components/backlog-health.tsx @@ -0,0 +1,90 @@ +'use client' + +import { useRouter } from 'next/navigation' +import { CheckCircle, AlertTriangle, XCircle } from 'lucide-react' +import type { BacklogHealth, StuckTask } from '@/lib/insights/backlog-health' + +interface Props { + data: BacklogHealth +} + +function Counter({ label, count }: { label: string; count: number }) { + const healthy = count === 0 + return ( +
+ {healthy ? ( + + ) : ( + + )} + {count} + {label} +
+ ) +} + +function daysStuckClass(days: number): string { + if (days >= 14) return 'bg-priority-critical/15 text-priority-critical font-semibold' + if (days >= 7) return 'bg-priority-medium/15 text-priority-medium font-semibold' + return '' +} + +function StuckTable({ tasks }: { tasks: StuckTask[] }) { + const router = useRouter() + + if (tasks.length === 0) { + return ( +

Geen stuck tasks 🎉

+ ) + } + + return ( + + + + + + + + + + + {tasks.map(t => ( + router.push(`/products/${t.productId}/solo?task=${t.taskId}`)} + > + + + + + + ))} + +
TaakProductDaysSprint
{t.title}{t.productName} + {t.daysStuck}d + + {t.sprintGoal ?? '—'} +
+ ) +} + +export function BacklogHealthCard({ data }: Props) { + return ( +
+
+ + + +
+ +
+

+ Stuck tasks +

+ +
+
+ ) +}