feat: split alcohol and urine test into separate fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 19:08:27 +08:00
co-authored by Claude Sonnet 4.6
parent e687510d0b
commit e30d583947
5 changed files with 60 additions and 19 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ export default async function HseIncidentDetailPage({ params }: Props) {
.from('investigations') .from('investigations')
.select(` .select(`
id, method, five_why_steps, fishbone_categories, id, method, five_why_steps, fishbone_categories,
findings_text, root_cause_summary, alcohol_test_result, findings_text, root_cause_summary, alcohol_test_result, urine_test_result,
witness_statement_refs, completed_at, witness_statement_refs, completed_at,
investigator:users!investigator_id (name, email) investigator:users!investigator_id (name, email)
`) `)
@@ -45,6 +45,7 @@ export async function POST(
five_why_steps: method === 'five_why' ? (body.five_why_steps ?? []) : null, five_why_steps: method === 'five_why' ? (body.five_why_steps ?? []) : null,
fishbone_categories: method === 'fishbone' ? (body.fishbone_categories ?? []) : null, fishbone_categories: method === 'fishbone' ? (body.fishbone_categories ?? []) : null,
alcohol_test_result: body.alcohol_test_result ?? null, alcohol_test_result: body.alcohol_test_result ?? null,
urine_test_result: body.urine_test_result ?? null,
witness_statement_refs: Array.isArray(body.witness_statement_refs) ? body.witness_statement_refs : [], witness_statement_refs: Array.isArray(body.witness_statement_refs) ? body.witness_statement_refs : [],
}) })
.select('id') .select('id')
@@ -93,6 +94,7 @@ export async function PATCH(
five_why_steps: fields.five_why_steps ?? null, five_why_steps: fields.five_why_steps ?? null,
fishbone_categories: fields.fishbone_categories ?? null, fishbone_categories: fields.fishbone_categories ?? null,
alcohol_test_result: fields.alcohol_test_result ?? null, alcohol_test_result: fields.alcohol_test_result ?? null,
urine_test_result: fields.urine_test_result ?? null,
witness_statement_refs: Array.isArray(fields.witness_statement_refs) ? fields.witness_statement_refs : [], witness_statement_refs: Array.isArray(fields.witness_statement_refs) ? fields.witness_statement_refs : [],
} }
if (complete) updateData.completed_at = new Date().toISOString() if (complete) updateData.completed_at = new Date().toISOString()
+31 -13
View File
@@ -38,6 +38,7 @@ export function InvestigationForm({ incidentId, existingInvestigationId }: Props
const [findingsText, setFindingsText] = useState('') const [findingsText, setFindingsText] = useState('')
const [rootCause, setRootCause] = useState('') const [rootCause, setRootCause] = useState('')
const [alcoholTest, setAlcoholTest] = useState('') const [alcoholTest, setAlcoholTest] = useState('')
const [urineTest, setUrineTest] = useState('')
const [witnessRefs, setWitnessRefs] = useState<string[]>(['']) const [witnessRefs, setWitnessRefs] = useState<string[]>([''])
const [complete, setComplete] = useState(false) const [complete, setComplete] = useState(false)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
@@ -95,6 +96,7 @@ export function InvestigationForm({ incidentId, existingInvestigationId }: Props
findings_text: findingsText || null, findings_text: findingsText || null,
root_cause_summary: rootCause || null, root_cause_summary: rootCause || null,
alcohol_test_result: alcoholTest || null, alcohol_test_result: alcoholTest || null,
urine_test_result: urineTest || null,
witness_statement_refs: witnessRefs.map(w => w.trim()).filter(Boolean), witness_statement_refs: witnessRefs.map(w => w.trim()).filter(Boolean),
five_why_steps: method === 'five_why' ? fiveWhy.filter(s => s.answer) : null, five_why_steps: method === 'five_why' ? fiveWhy.filter(s => s.answer) : null,
fishbone_categories: method === 'fishbone' fishbone_categories: method === 'fishbone'
@@ -211,19 +213,35 @@ export function InvestigationForm({ incidentId, existingInvestigationId }: Props
</div> </div>
)} )}
<div> <div className="grid grid-cols-2 gap-3">
<label className="block text-sm font-medium text-gray-700 mb-1">Alcohol / Urine Test Result</label> <div>
<select <label className="block text-sm font-medium text-gray-700 mb-1">Alcohol Test Result</label>
value={alcoholTest} <select
onChange={e => setAlcoholTest(e.target.value)} value={alcoholTest}
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm" onChange={e => setAlcoholTest(e.target.value)}
> className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"
<option value="">Not applicable / not conducted</option> >
<option value="negative">Negative</option> <option value="">Not conducted</option>
<option value="positive">Positive</option> <option value="negative">Negative</option>
<option value="refused">Refused</option> <option value="positive">Positive</option>
<option value="pending">Result pending</option> <option value="refused">Refused</option>
</select> <option value="pending">Result pending</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Urine Test Result</label>
<select
value={urineTest}
onChange={e => setUrineTest(e.target.value)}
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"
>
<option value="">Not conducted</option>
<option value="negative">Negative</option>
<option value="positive">Positive</option>
<option value="refused">Refused</option>
<option value="pending">Result pending</option>
</select>
</div>
</div> </div>
<div> <div>
+23 -5
View File
@@ -8,6 +8,7 @@ interface Investigation {
findings_text: string | null findings_text: string | null
root_cause_summary: string | null root_cause_summary: string | null
alcohol_test_result: string | null alcohol_test_result: string | null
urine_test_result: string | null
witness_statement_refs: string[] witness_statement_refs: string[]
completed_at: string | null completed_at: string | null
investigator: { name: string | null; email: string } | null investigator: { name: string | null; email: string } | null
@@ -23,6 +24,13 @@ const METHOD_LABELS = {
other: 'Other Method', other: 'Other Method',
} }
const TEST_RESULT_LABELS: Record<string, string> = {
negative: 'Negative',
positive: 'Positive',
refused: 'Refused',
pending: 'Result pending',
}
export function InvestigationPanel({ investigation: inv }: Props) { export function InvestigationPanel({ investigation: inv }: Props) {
const investigatorName = inv.investigator?.name ?? inv.investigator?.email ?? 'Unknown' const investigatorName = inv.investigator?.name ?? inv.investigator?.email ?? 'Unknown'
@@ -105,11 +113,21 @@ export function InvestigationPanel({ investigation: inv }: Props) {
</div> </div>
)} )}
{/* Alcohol test */} {/* Drug tests */}
{inv.alcohol_test_result && ( {(inv.alcohol_test_result || inv.urine_test_result) && (
<div> <div className="grid grid-cols-2 gap-4">
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1">Alcohol Test Result</h3> {inv.alcohol_test_result && (
<p className="text-sm text-gray-900">{inv.alcohol_test_result}</p> <div>
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1">Alcohol Test</h3>
<p className="text-sm text-gray-900">{TEST_RESULT_LABELS[inv.alcohol_test_result] ?? inv.alcohol_test_result}</p>
</div>
)}
{inv.urine_test_result && (
<div>
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1">Urine Test</h3>
<p className="text-sm text-gray-900">{TEST_RESULT_LABELS[inv.urine_test_result] ?? inv.urine_test_result}</p>
</div>
)}
</div> </div>
)} )}
@@ -0,0 +1,3 @@
ALTER TABLE investigations
ADD COLUMN IF NOT EXISTS urine_test_result text
CHECK (urine_test_result IN ('negative','positive','refused','pending'));