From 55b6dac646f97e1c90572018b9073e7319e5b87a Mon Sep 17 00:00:00 2001 From: weeihan Date: Sat, 11 Jul 2026 18:39:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20reporter=20dashboard=20=E2=80=94=20user?= =?UTF-8?q?-scoped=20incident=20submissions=20with=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(protected)/reporter/page.tsx | 116 ++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 5 deletions(-) diff --git a/app/(protected)/reporter/page.tsx b/app/(protected)/reporter/page.tsx index 24dd17f..eb11791 100644 --- a/app/(protected)/reporter/page.tsx +++ b/app/(protected)/reporter/page.tsx @@ -1,9 +1,115 @@ -// app/(protected)/reporter/page.tsx -export default function ReporterHome() { +export const dynamic = 'force-dynamic' + +import Link from 'next/link' +import { createClient } from '@/lib/supabase/server' +import { redirect } from 'next/navigation' + +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-600', + 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', +} + +const TYPE_LABELS: Record = { + injury: 'Injury', near_miss: 'Near Miss', hazard: 'Hazard', + asset_damage: 'Asset Damage', environmental: 'Environmental', security: 'Security', fire: 'Fire', +} + +export default async function ReporterPage() { + const supabase = await createClient() + const { data: { user } } = await supabase.auth.getUser() + if (!user) redirect('/login') + + const { data: profile } = await supabase.from('users').select('name').eq('id', user.id).single() + + const { data: incidents } = await supabase + .from('incidents') + .select('id, reference_no, incident_type, status, reported_at, severity, sites (name)') + .eq('reported_by', user.id) + .order('reported_at', { ascending: false }) + + const rows = incidents ?? [] + const openCount = rows.filter(r => r.status !== 'closed').length + const closedCount = rows.filter(r => r.status === 'closed').length + return ( -
-

Reporter Dashboard

-

Phase 1: Incident report form coming here.

+
+
+
+

My Reports

+

Welcome, {profile?.name ?? user.email}

+
+ + + New Report + +
+ +
+
+

{rows.length}

+

Total Submitted

+
+
+

{openCount}

+

In Progress

+
+
+

{closedCount}

+

Closed

+
+
+ + {rows.length === 0 ? ( +
+

No incidents reported yet.

+ Submit your first report → +
+ ) : ( +
+ {rows.map(inc => { + const siteName = (inc.sites as unknown as { name: string } | null)?.name + return ( +
+
+
+

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

+

+ {TYPE_LABELS[inc.incident_type] ?? inc.incident_type} + {siteName ? ` · ${siteName}` : ''} + {inc.severity ? ` · Severity ${inc.severity}` : ''} +

+

+ {new Date(inc.reported_at as string).toLocaleDateString('en-MY', { + day: 'numeric', month: 'short', year: 'numeric', + })} +

+
+ + {STATUS_LABELS[inc.status] ?? inc.status} + +
+
+ ) + })} +
+ )}
) }