feat: JKKP 6/7 PDF generation via pdf-lib, download from incident detail

Also excludes node_modules.nosync from vitest test discovery to fix pre-existing bleed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
This commit is contained in:
2026-07-11 15:24:18 +08:00
co-authored by Claude Opus 4.8
parent 75fa2605bf
commit 54332d0297
7 changed files with 293 additions and 0 deletions
@@ -18,6 +18,7 @@ export default async function HseIncidentDetailPage({ params }: Props) {
.select(`
id, reference_no, incident_type, description, severity, status,
injury_involved, asset_involved, medical_status, lost_days,
is_fatality, is_serious_bodily_injury, is_dangerous_occurrence, is_occupational_disease,
reported_at, closed_at,
sites (id, name),
zones (id, name),
@@ -69,6 +70,30 @@ export default async function HseIncidentDetailPage({ params }: Props) {
</Link>
</div>
)}
{Boolean(
(incident as { is_fatality?: boolean }).is_fatality ||
(incident as { is_serious_bodily_injury?: boolean }).is_serious_bodily_injury ||
(incident as { is_dangerous_occurrence?: boolean }).is_dangerous_occurrence ||
((incident as { lost_days?: number | null }).lost_days ?? 0) >= 4
) && (
<div className="mt-4 flex gap-3">
<a
href={`/api/incidents/${id}/jkkp-pdf?form=jkkp6`}
target="_blank"
className="inline-block bg-gray-800 text-white rounded-lg px-4 py-2 text-sm font-semibold hover:bg-gray-900"
>
Download JKKP 6 (PDF)
</a>
<a
href={`/api/incidents/${id}/jkkp-pdf?form=jkkp7`}
target="_blank"
className="inline-block bg-gray-600 text-white rounded-lg px-4 py-2 text-sm font-semibold hover:bg-gray-700"
>
Download JKKP 7 (PDF)
</a>
</div>
)}
</main>
)
}