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 { incidents, sites, capaActions, users } from '@/lib/db/schema' import { eq, not, and, inArray, sql, desc } from 'drizzle-orm' import { aliasedTable } from 'drizzle-orm' import { StatCard } from '@/components/dashboard/stat-card' const STATUS_LABELS: Record = { reported: 'Reported', triaged: 'Triaged', investigating: 'Investigating', capa_pending: 'CAPA Pending', verification: 'Verification', closed: 'Closed', } const STATUS_COLORS: Record = { reported: 'bg-gray-100 text-gray-700', triaged: 'bg-yellow-100 text-yellow-800', investigating: 'bg-blue-100 text-blue-700', capa_pending: 'bg-orange-100 text-orange-700', verification: 'bg-purple-100 text-purple-700', closed: 'bg-green-100 text-green-700', } export default async function SupervisorPage() { const session = await getSession() if (!session) redirect('/login') if (!['supervisor', 'admin'].includes(session.role)) redirect('/') if (!session.siteId) { return (

Supervisor Portal

No site assigned — contact your administrator.

) } const [siteRow] = await asAdmin(db => db.select({ name: sites.name }).from(sites).where(eq(sites.id, session.siteId!)).limit(1) ) const siteName = siteRow?.name ?? 'Your Site' // Get all incident IDs for this site const siteIncidents = await asAdmin(db => db.select({ id: incidents.id }).from(incidents).where(eq(incidents.siteId, session.siteId!)) ) const incidentIds = siteIncidents.map(r => r.id) const ownerAlias = aliasedTable(users, 'owner') const [openIncidents, closedCountRow, openCountRow, overdueCapas, allCapas] = await Promise.all([ asAdmin(db => db.select({ id: incidents.id, referenceNo: incidents.referenceNo, incidentType: incidents.incidentType, status: incidents.status, reportedAt: incidents.reportedAt, }) .from(incidents) .where(and(eq(incidents.siteId, session.siteId!), not(eq(incidents.status, 'closed')))) .orderBy(desc(incidents.reportedAt)) .limit(10) ), asAdmin(db => db.select({ count: sql`count(*)` }) .from(incidents) .where(and(eq(incidents.siteId, session.siteId!), eq(incidents.status, 'closed'))) ), asAdmin(db => db.select({ count: sql`count(*)` }) .from(incidents) .where(and(eq(incidents.siteId, session.siteId!), not(eq(incidents.status, 'closed')))) ), incidentIds.length > 0 ? asAdmin(db => db.select({ id: capaActions.id, description: capaActions.description, dueDate: capaActions.dueDate, ownerName: ownerAlias.name, }) .from(capaActions) .leftJoin(ownerAlias, eq(capaActions.ownerUserId, ownerAlias.id)) .where(and(eq(capaActions.status, 'overdue'), inArray(capaActions.incidentId, incidentIds))) ) : Promise.resolve([]), incidentIds.length > 0 ? asAdmin(db => db.select({ id: capaActions.id, status: capaActions.status }) .from(capaActions) .where(inArray(capaActions.incidentId, incidentIds)) ) : Promise.resolve([]), ]) const resolvedOpenCount = Number(openCountRow[0]?.count ?? 0) const resolvedClosedCount = Number(closedCountRow[0]?.count ?? 0) const overdueCount = overdueCapas.length const capaRows = allCapas const capaOpenCount = capaRows.filter(c => ['open', 'in_progress'].includes(c.status)).length const capaVerifiedCount = capaRows.filter(c => c.status === 'verified').length const TYPE_LABELS: Record = { injury: 'Injury', near_miss: 'Near Miss', hazard: 'Hazard', asset_damage: 'Asset Damage', environmental: 'Environmental', security: 'Security', fire: 'Fire', } return (

Supervisor Portal

{siteName}

All incidents →
{/* Stats */}
0 ? 'yellow' : 'green'} /> 0 ? 'yellow' : 'green'} /> 0 ? 'red' : 'green'} />
{/* Open incidents */}

Open Incidents

{openIncidents.length === 0 ? (

No open incidents.

) : (
{openIncidents.map(inc => (

{inc.referenceNo ?? inc.id.slice(0, 8)}

{TYPE_LABELS[inc.incidentType] ?? inc.incidentType}

{STATUS_LABELS[inc.status] ?? inc.status} ))}
)}
{/* Overdue CAPAs */} {overdueCount > 0 && (

Overdue CAPAs

{overdueCapas.map(capa => (

{capa.description}

Owner: {capa.ownerName ?? 'Unassigned'}

Due {capa.dueDate ? new Date(capa.dueDate).toLocaleDateString('en-MY') : '—'}
))}

CAPA verification rate: {capaRows.length > 0 ? Math.round((capaVerifiedCount / capaRows.length) * 100) : 'N/A'}%

)}
) }