feat(db): phase 4 group 6 — server component pages to Drizzle
Converts all 18 server component page files from Supabase client queries to Drizzle ORM using asAdmin. Adds getSession() + redirect to the three pages (hse/incidents, hse/incidents/[id], hse/dashboard) that lacked it. Maps snake_case component prop shapes explicitly where required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { asAdmin } from '@/lib/db/with-user'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { getSession } from '@/lib/auth/get-session'
|
||||
import { incidents, sites, capaActions } from '@/lib/db/schema'
|
||||
import { eq, gte, lt, and } from 'drizzle-orm'
|
||||
import { StatCard } from '@/components/dashboard/stat-card'
|
||||
import { RiskFlagsPanel } from '@/components/dashboard/risk-flags-panel'
|
||||
|
||||
@@ -11,34 +13,53 @@ export default async function ManagementPage() {
|
||||
if (!session) redirect('/login')
|
||||
if (!['management', 'admin'].includes(session.role)) redirect('/')
|
||||
|
||||
const supabase = await createClient()
|
||||
|
||||
const now = new Date()
|
||||
const thisMonthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString()
|
||||
const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString()
|
||||
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
const [
|
||||
{ data: allIncidents },
|
||||
{ data: thisMonthIncidents },
|
||||
{ data: lastMonthIncidents },
|
||||
{ data: recentIncidents },
|
||||
{ data: overdueCapas },
|
||||
] = await Promise.all([
|
||||
supabase.from('incidents').select('id, severity, status, incident_type, medical_status, sites (name)'),
|
||||
supabase.from('incidents').select('id').gte('reported_at', thisMonthStart),
|
||||
supabase.from('incidents').select('id').gte('reported_at', lastMonthStart).lt('reported_at', thisMonthStart),
|
||||
supabase.from('incidents').select('incident_type').gte('reported_at', thirtyDaysAgo),
|
||||
supabase.from('capa_actions').select('id').eq('status', 'overdue'),
|
||||
const [allIncidents, thisMonthIncidents, lastMonthIncidents, recentIncidents, overdueCapas] = await Promise.all([
|
||||
asAdmin(db =>
|
||||
db.select({
|
||||
id: incidents.id,
|
||||
severity: incidents.severity,
|
||||
status: incidents.status,
|
||||
incidentType: incidents.incidentType,
|
||||
medicalStatus: incidents.medicalStatus,
|
||||
siteName: sites.name,
|
||||
})
|
||||
.from(incidents)
|
||||
.leftJoin(sites, eq(incidents.siteId, sites.id))
|
||||
),
|
||||
asAdmin(db =>
|
||||
db.select({ id: incidents.id })
|
||||
.from(incidents)
|
||||
.where(gte(incidents.reportedAt, new Date(thisMonthStart)))
|
||||
),
|
||||
asAdmin(db =>
|
||||
db.select({ id: incidents.id })
|
||||
.from(incidents)
|
||||
.where(and(gte(incidents.reportedAt, new Date(lastMonthStart)), lt(incidents.reportedAt, new Date(thisMonthStart))))
|
||||
),
|
||||
asAdmin(db =>
|
||||
db.select({ incidentType: incidents.incidentType })
|
||||
.from(incidents)
|
||||
.where(gte(incidents.reportedAt, new Date(thirtyDaysAgo)))
|
||||
),
|
||||
asAdmin(db =>
|
||||
db.select({ id: capaActions.id })
|
||||
.from(capaActions)
|
||||
.where(eq(capaActions.status, 'overdue'))
|
||||
),
|
||||
])
|
||||
|
||||
const rows = allIncidents ?? []
|
||||
const totalThisMonth = thisMonthIncidents?.length ?? 0
|
||||
const totalLastMonth = lastMonthIncidents?.length ?? 0
|
||||
const rows = allIncidents
|
||||
const totalThisMonth = thisMonthIncidents.length
|
||||
const totalLastMonth = lastMonthIncidents.length
|
||||
const monthDelta = totalThisMonth - totalLastMonth
|
||||
|
||||
const ltiCount = rows.filter(r => r.medical_status === 'lti').length
|
||||
const overdueCount = overdueCapas?.length ?? 0
|
||||
const ltiCount = rows.filter(r => r.medicalStatus === 'lti').length
|
||||
const overdueCount = overdueCapas.length
|
||||
|
||||
// Severity distribution
|
||||
const severityDist: Record<number, number> = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 }
|
||||
@@ -50,14 +71,13 @@ export default async function ManagementPage() {
|
||||
const severityMax = Math.max(...Object.values(severityDist), 1)
|
||||
|
||||
// Leading vs lagging (last 30 days)
|
||||
const recent = recentIncidents ?? []
|
||||
const leadingCount = recent.filter(r => ['hazard', 'near_miss'].includes(r.incident_type)).length
|
||||
const laggingCount = recent.filter(r => r.incident_type === 'injury').length
|
||||
const leadingCount = recentIncidents.filter(r => ['hazard', 'near_miss'].includes(r.incidentType)).length
|
||||
const laggingCount = recentIncidents.filter(r => r.incidentType === 'injury').length
|
||||
|
||||
// Site comparison
|
||||
const siteMap: Record<string, number> = {}
|
||||
for (const r of rows) {
|
||||
const name = (r.sites as unknown as { name: string } | null)?.name ?? 'Unknown'
|
||||
const name = r.siteName ?? 'Unknown'
|
||||
siteMap[name] = (siteMap[name] ?? 0) + 1
|
||||
}
|
||||
const by_site = Object.entries(siteMap).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count)
|
||||
|
||||
Reference in New Issue
Block a user