import { useState, useEffect, useCallback, useRef } from 'react' import { Search, ChevronLeft, ChevronRight, Save, CheckCircle, XCircle, } from 'lucide-react' import api from '@/services/api' import type { Case, CaseListResponse } from '@/types' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, } from '@/components/ui/sheet' import { Skeleton } from '@/components/ui/skeleton' import { Alert, AlertDescription } from '@/components/ui/alert' const FALLGRUPPEN_LABELS: Record = { onko: 'Onkologie', kardio: 'Kardiologie', intensiv: 'Intensivmedizin', galle: 'Gallenblase', sd: 'Schilddrüse', } const FALLGRUPPEN_OPTIONS = [ { value: '__all__', label: 'Alle Fallgruppen' }, { value: 'onko', label: 'Onkologie' }, { value: 'kardio', label: 'Kardiologie' }, { value: 'intensiv', label: 'Intensivmedizin' }, { value: 'galle', label: 'Gallenblase' }, { value: 'sd', label: 'Schilddrüse' }, ] const ICD_OPTIONS = [ { value: '__all__', label: 'Alle' }, { value: 'true', label: 'Mit ICD' }, { value: 'false', label: 'Ohne ICD' }, ] interface CasesPageProps { /** When true, fetches from pending-icd endpoint instead */ pendingIcdOnly?: boolean } export function CasesPage({ pendingIcdOnly = false }: CasesPageProps) { const currentYear = new Date().getFullYear() const [search, setSearch] = useState('') const [debouncedSearch, setDebouncedSearch] = useState('') const [jahr, setJahr] = useState('__all__') const [fallgruppe, setFallgruppe] = useState('__all__') const [hasIcd, setHasIcd] = useState('__all__') const [page, setPage] = useState(1) const [perPage] = useState(50) const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [selectedCase, setSelectedCase] = useState(null) const [sheetOpen, setSheetOpen] = useState(false) // Debounce search const debounceRef = useRef | null>(null) const handleSearchChange = useCallback((val: string) => { setSearch(val) if (debounceRef.current) clearTimeout(debounceRef.current) debounceRef.current = setTimeout(() => { setDebouncedSearch(val) setPage(1) }, 300) }, []) useEffect(() => { return () => { if (debounceRef.current) clearTimeout(debounceRef.current) } }, []) // Fetch cases useEffect(() => { setLoading(true) if (pendingIcdOnly) { api.get('/cases/pending-icd', { params: { page, per_page: perPage }, }) .then((res) => setData(res.data)) .catch(() => setData(null)) .finally(() => setLoading(false)) } else { const params: Record = { page, per_page: perPage } if (debouncedSearch) params.search = debouncedSearch if (jahr !== '__all__') params.jahr = Number(jahr) if (fallgruppe !== '__all__') params.fallgruppe = fallgruppe if (hasIcd !== '__all__') params.has_icd = hasIcd api.get('/cases/', { params }) .then((res) => setData(res.data)) .catch(() => setData(null)) .finally(() => setLoading(false)) } }, [page, perPage, debouncedSearch, jahr, fallgruppe, hasIcd, pendingIcdOnly]) const totalPages = data ? Math.ceil(data.total / perPage) : 0 const years = Array.from({ length: 5 }, (_, i) => currentYear - i) const openDetail = (c: Case) => { setSelectedCase(c) setSheetOpen(true) } const handleIcdSaved = (updated: Case) => { setSelectedCase(updated) // Refresh list setData((prev) => prev ? { ...prev, items: prev.items.map((c) => (c.id === updated.id ? updated : c)), } : prev, ) } return (

{pendingIcdOnly ? 'ICD-Eingabe' : 'Fälle'}

{/* Filter bar */} {!pendingIcdOnly && (
handleSearchChange(e.target.value)} className="pl-9" />
)} {/* Table */} {loading ? (
{Array.from({ length: 8 }).map((_, i) => ( ))}
) : data && data.items.length > 0 ? ( <> Fall-ID Datum Nachname Vorname KVNR Fallgruppe ICD Gutachten Status {data.items.map((c) => ( openDetail(c)} > {c.fall_id || '-'} {formatDate(c.datum)} {c.nachname} {c.vorname || '-'} {c.kvnr || '-'} {FALLGRUPPEN_LABELS[c.fallgruppe] || c.fallgruppe} {c.icd ? ( {c.icd} ) : ( - )} {c.gutachten ? ( ) : ( )} ))}
{/* Pagination */}

{data.total} Fälle insgesamt

Seite {page} von {totalPages || 1}
) : (

Keine Fälle gefunden.

)} {/* Detail Sheet */} {selectedCase && ( )}
) } function StatusBadges({ c }: { c: Case }) { return (
{c.unterlagen && Unterlagen} {c.gutachten && Gutachten} {c.abgerechnet && Abgerechnet} {c.ablehnung && Abgelehnt} {c.abbruch && Abbruch}
) } function CaseDetail({ caseData, onIcdSaved, }: { caseData: Case onIcdSaved: (updated: Case) => void }) { const [icdValue, setIcdValue] = useState(caseData.icd || '') const [saving, setSaving] = useState(false) const [error, setError] = useState('') const [success, setSuccess] = useState(false) // Reset on case change useEffect(() => { setIcdValue(caseData.icd || '') setError('') setSuccess(false) }, [caseData.id, caseData.icd]) const saveIcd = async () => { if (!icdValue.trim()) return setSaving(true) setError('') setSuccess(false) try { const res = await api.put(`/cases/${caseData.id}/icd`, { icd: icdValue.trim() }) onIcdSaved(res.data) setSuccess(true) } catch { setError('Fehler beim Speichern des ICD-Codes.') } finally { setSaving(false) } } return ( <> Fall {caseData.fall_id || `#${caseData.id}`} {FALLGRUPPEN_LABELS[caseData.fallgruppe] || caseData.fallgruppe} — KW {caseData.kw}/{caseData.jahr}
{/* Status badges */}
{/* Patient info */}
{/* Case details */}
{/* ICD edit */}
{ setIcdValue(e.target.value); setSuccess(false) }} placeholder="z.B. C50.9" className="flex-1" />
{error && ( {error} )} {success && (

ICD-Code gespeichert.

)}
{/* Description fields */} {caseData.kurzbeschreibung && (

{caseData.kurzbeschreibung}

)} {caseData.fragestellung && (

{caseData.fragestellung}

)} {caseData.kommentar && (

{caseData.kommentar}

)}

Importiert: {formatDateTime(caseData.imported_at)}

Aktualisiert: {formatDateTime(caseData.updated_at)}

{caseData.import_source &&

Quelle: {caseData.import_source}

}
) } function DetailField({ label, value }: { label: string; value: string | null | undefined }) { return (
{label}

{value || '-'}

) } function formatDate(dateStr: string): string { try { return new Date(dateStr).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', }) } catch { return dateStr } } function formatDateTime(dateStr: string): string { try { return new Date(dateStr).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } catch { return dateStr } }