From a4253a80f580227a1cbc97773869f5feabf8aa0f Mon Sep 17 00:00:00 2001 From: weeihan Date: Thu, 30 Jul 2026 08:41:41 +0800 Subject: [PATCH] feat(capa): allow overdue CAPAs to be acted on, fix owner page stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CapaOwnerActions: add 'overdue' to open/reopened branch so DB-overdue CAPAs show 'Mark In Progress' button (cron transitions open→overdue) - capa-owner page: compute overdue at runtime (dueDate < today) so stats and red highlight are correct even before cron runs - openCount now excludes overdue items to avoid double-counting - Add CapaOwnerActions test suite covering all status transitions Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01HEYxFQiCyxJvnBCoZeYzB9 --- app/(protected)/capa-owner/page.tsx | 12 ++++-- components/capa/capa-owner-actions.tsx | 2 +- .../capa/capa-owner-actions.test.tsx | 40 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/components/capa/capa-owner-actions.test.tsx diff --git a/app/(protected)/capa-owner/page.tsx b/app/(protected)/capa-owner/page.tsx index aa113b9..86ae460 100644 --- a/app/(protected)/capa-owner/page.tsx +++ b/app/(protected)/capa-owner/page.tsx @@ -52,8 +52,14 @@ export default async function CapaOwnerPage() { .orderBy(asc(capaActions.dueDate)) ) - const openCount = rows.filter(c => ['open', 'in_progress', 'reopened'].includes(c.status)).length - const overdueCount = rows.filter(c => c.status === 'overdue').length + const today = new Date().toISOString().slice(0, 10) + function isCapaOverdue(c: { status: string; dueDate: string | null }): boolean { + if (c.status === 'overdue') return true + return (c.status === 'open' || c.status === 'in_progress') && !!c.dueDate && c.dueDate < today + } + + const openCount = rows.filter(c => ['open', 'in_progress', 'reopened'].includes(c.status) && !isCapaOverdue(c)).length + const overdueCount = rows.filter(c => isCapaOverdue(c)).length const doneCount = rows.filter(c => ['verified', 'closed'].includes(c.status)).length const PRIORITY_COLORS: Record = { @@ -82,7 +88,7 @@ export default async function CapaOwnerPage() { ) : (
{activeRows.map(capa => { - const isOverdue = capa.status === 'overdue' + const isOverdue = isCapaOverdue(capa) return (
diff --git a/components/capa/capa-owner-actions.tsx b/components/capa/capa-owner-actions.tsx index d63eb05..0f2f334 100644 --- a/components/capa/capa-owner-actions.tsx +++ b/components/capa/capa-owner-actions.tsx @@ -31,7 +31,7 @@ export function CapaOwnerActions({ capaId, currentStatus }: Props) { } } - if (currentStatus === 'open' || currentStatus === 'reopened') { + if (currentStatus === 'open' || currentStatus === 'reopened' || currentStatus === 'overdue') { return (