'use client'; /** * Patient Context Card * * Toont patiënt context na selectie: notities, vitals, diagnoses. * E3.S5: Volledige implementatie met auto-open na patient selectie. */ import { useEffect, useState } from 'react'; import { useSwiftStore } from '@/stores/swift-store'; import { BlockContainer } from './block-container'; import { BLOCK_CONFIGS } from '@/lib/swift/types'; import type { PatientDetail, Report, VitalSign, Condition, RiskAssessment } from '@/lib/types/overdracht'; import { Loader2, FileText, Activity, Stethoscope, AlertTriangle, Calendar } from 'lucide-react'; import { format } from 'date-fns'; import { nl } from 'date-fns/locale/nl'; import { cn } from '@/lib/utils'; export function PatientContextCard() { const { activePatient, closeBlock } = useSwiftStore(); const [data, setData] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!activePatient?.id) { return; } const fetchContext = async () => { setIsLoading(true); setError(null); try { const response = await fetch(`/api/overdracht/${activePatient.id}`); if (!response.ok) { throw new Error('Kon patiënt context niet laden'); } const result = await response.json(); setData(result); } catch (err) { console.error('Failed to fetch patient context:', err); setError(err instanceof Error ? err.message : 'Onbekende fout'); } finally { setIsLoading(false); } }; fetchContext(); }, [activePatient?.id]); if (!activePatient) { return null; } const patientName = `${activePatient.name_given?.join(' ') || ''} ${activePatient.name_family || ''}`.trim(); return ( {isLoading ? (
Context laden...
) : error ? (

{error}

) : data ? (
{/* Notities (Reports) */} {data.reports && data.reports.length > 0 && (

Recente notities

({data.reports.length})
{data.reports.slice(0, 5).map((report) => ( ))} {data.reports.length > 5 && (

+ {data.reports.length - 5} meer notities

)}
)} {/* Vitals */} {data.vitals && data.vitals.length > 0 && (

Vitale functies (vandaag)

({data.vitals.length})
{data.vitals.slice(0, 6).map((vital) => ( ))}
)} {/* Diagnoses */} {data.conditions && data.conditions.length > 0 && (

Actieve diagnoses

({data.conditions.length})
{data.conditions.map((condition) => ( ))}
)} {/* Risico's */} {data.risks && data.risks.length > 0 && (

Risico's

({data.risks.length})
{data.risks.map((risk) => ( ))}
)} {/* Empty state */} {(!data.reports || data.reports.length === 0) && (!data.vitals || data.vitals.length === 0) && (!data.conditions || data.conditions.length === 0) && (!data.risks || data.risks.length === 0) && (

Geen context beschikbaar voor deze patiënt

)}
) : null}
); } function ReportItem({ report }: { report: Report }) { const date = report.created_at ? new Date(report.created_at) : null; const formattedDate = date ? format(date, 'd MMM HH:mm', { locale: nl }) : 'Onbekend'; return (
{report.type} {report.include_in_handover && ( Overdracht )}
{formattedDate}

{report.content}

); } function VitalItem({ vital }: { vital: VitalSign }) { const isAbnormal = vital.interpretation_code === 'H' || vital.interpretation_code === 'L'; const date = vital.effective_datetime ? new Date(vital.effective_datetime) : null; const formattedTime = date ? format(date, 'HH:mm', { locale: nl }) : ''; return (
{vital.code_display}
{vital.value_quantity_value} {vital.value_quantity_unit && {vital.value_quantity_unit}}
{formattedTime &&
{formattedTime}
}
); } function ConditionItem({ condition }: { condition: Condition }) { const date = condition.onset_datetime ? new Date(condition.onset_datetime) : null; const formattedDate = date ? format(date, 'd MMM yyyy', { locale: nl }) : null; return (

{condition.code_display}

{formattedDate && (

Sinds {formattedDate}

)}
); } function RiskBadge({ risk }: { risk: RiskAssessment }) { const RISK_TYPE_LABELS: Record = { suiciderisico: 'Suicide', agressie: 'Agressie', terugval: 'Terugval', automutilatie: 'Automutilatie', verwaarlozing: 'Verwaarlozing', weglopen: 'Weglopen', }; const RISK_LEVEL_STYLES: Record = { zeer_hoog: { bg: 'bg-red-900/30', text: 'text-red-300', dot: 'bg-red-500' }, hoog: { bg: 'bg-red-900/20', text: 'text-red-400', dot: 'bg-red-500' }, gemiddeld: { bg: 'bg-amber-900/20', text: 'text-amber-300', dot: 'bg-amber-500' }, laag: { bg: 'bg-green-900/20', text: 'text-green-300', dot: 'bg-green-500' }, }; const styles = RISK_LEVEL_STYLES[risk.risk_level] || RISK_LEVEL_STYLES.laag; const label = RISK_TYPE_LABELS[risk.risk_type] || risk.risk_type; const levelLabel = risk.risk_level === 'zeer_hoog' ? 'Zeer hoog' : risk.risk_level.charAt(0).toUpperCase() + risk.risk_level.slice(1); return ( {label}: {levelLabel} ); }