export const dynamic = 'force-dynamic' import Link from 'next/link' import { asAdmin } from '@/lib/db/with-user' import { redirect } from 'next/navigation' import { getSession } from '@/lib/auth/get-session' import { capaActions, incidents } from '@/lib/db/schema' import { eq, asc } from 'drizzle-orm' import { StatCard } from '@/components/dashboard/stat-card' import { CapaOwnerActions } from '@/components/capa/capa-owner-actions' import { CapaOwnerNotesForm } from '@/components/capa/capa-owner-notes-form' const STATUS_LABELS: Record = { open: 'Open', in_progress: 'In Progress', overdue: 'Overdue', pending_verification: 'Pending Verification', verified: 'Verified', reopened: 'Reopened', closed: 'Closed', } const STATUS_COLORS: Record = { open: 'bg-gray-100 text-gray-700', in_progress: 'bg-blue-100 text-blue-700', overdue: 'bg-red-100 text-red-700', pending_verification: 'bg-purple-100 text-purple-700', verified: 'bg-green-100 text-green-700', reopened: 'bg-orange-100 text-orange-700', closed: 'bg-gray-100 text-gray-500', } export default async function CapaOwnerPage() { const session = await getSession() if (!session) redirect('/login') if (!['capa_owner', 'admin', 'hse', 'supervisor'].includes(session.role)) redirect('/') const rows = await asAdmin(db => db.select({ id: capaActions.id, description: capaActions.description, dueDate: capaActions.dueDate, priority: capaActions.priority, status: capaActions.status, incidentId: capaActions.incidentId, ownerNotes: capaActions.ownerNotes, incidentRefNo: incidents.referenceNo, }) .from(capaActions) .leftJoin(incidents, eq(capaActions.incidentId, incidents.id)) .where(eq(capaActions.ownerUserId, session.sub)) .orderBy(asc(capaActions.dueDate)) ) 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 = { high: 'text-red-600 font-semibold', med: 'text-orange-500 font-medium', low: 'text-gray-400', } const activeRows = rows.filter(c => !['verified', 'closed'].includes(c.status)) const doneRows = rows.filter(c => ['verified', 'closed'].includes(c.status)) return (

My CAPAs

0 ? 'yellow' : 'green'} /> 0 ? 'red' : 'green'} />
{activeRows.length === 0 ? (

No active CAPAs assigned to you.

) : (
{activeRows.map(capa => { const isOverdue = isCapaOverdue(capa) return (

{capa.description}

{capa.incidentRefNo && ( {capa.incidentRefNo} )}
{STATUS_LABELS[capa.status] ?? capa.status}

{capa.dueDate ? `Due ${new Date(capa.dueDate).toLocaleDateString('en-MY')}` : 'No due date'}

{capa.priority && (

{capa.priority.toUpperCase()} priority

)}
{capa.status !== 'pending_verification' && ( )}
) })}
)} {doneRows.length > 0 && (

Completed ({doneCount})

{doneRows.map(capa => (

{capa.description}

{STATUS_LABELS[capa.status] ?? capa.status}
))}
)}
) }