diff --git a/src/features/prozess/components/dokument-liste.tsx b/src/features/prozess/components/dokument-liste.tsx new file mode 100644 index 0000000..64becf8 --- /dev/null +++ b/src/features/prozess/components/dokument-liste.tsx @@ -0,0 +1,192 @@ +import { FileText, Plus, Trash2, X } from "lucide-react"; +import { useCallback, useEffect, useState } from "react"; +import { + type Dokument, + deleteDokument, + getDokumente, + saveDokument, +} from "@/shared/hooks/dokument-store"; + +interface DokumentListeProps { + sprechstundeId: number; +} + +export function DokumentListe({ sprechstundeId }: DokumentListeProps) { + const [dokumente, setDokumente] = useState([]); + const [viewDokument, setViewDokument] = useState(null); + + const refresh = useCallback(async () => { + const docs = await getDokumente(sprechstundeId); + setDokumente(docs); + }, [sprechstundeId]); + + useEffect(() => { + refresh(); + }, [refresh]); + + const handleFiles = async (files: FileList | null) => { + if (!files) return; + for (const file of files) { + await saveDokument(sprechstundeId, file); + } + await refresh(); + }; + + const handleDelete = async (id: number) => { + if (!window.confirm("Dokument wirklich löschen?")) return; + await deleteDokument(id); + await refresh(); + }; + + const handleView = (dok: Dokument) => { + if (dok.mimeType === "application/pdf") { + const url = URL.createObjectURL(dok.blob); + window.open(url, "_blank"); + setTimeout(() => URL.revokeObjectURL(url), 60_000); + } else { + setViewDokument(dok); + } + }; + + return ( +
+

Dokumente

+ + {dokumente.length > 0 && ( +
+ {dokumente.map((dok) => ( + handleView(dok)} + onDelete={() => handleDelete(dok.id)} + /> + ))} +
+ )} + + + + {viewDokument && ( + setViewDokument(null)} + /> + )} +
+ ); +} + +function DokumentThumbnail({ + dokument, + onView, + onDelete, +}: { + dokument: Dokument; + onView: () => void; + onDelete: () => void; +}) { + const [url, setUrl] = useState(null); + const isImage = dokument.mimeType.startsWith("image/"); + + useEffect(() => { + if (isImage) { + const objectUrl = URL.createObjectURL(dokument.blob); + setUrl(objectUrl); + return () => URL.revokeObjectURL(objectUrl); + } + }, [dokument.blob, isImage]); + + return ( +
+ + +
+ ); +} + +function ImageModal({ + dokument, + onClose, +}: { + dokument: Dokument; + onClose: () => void; +}) { + const [url, setUrl] = useState(null); + + useEffect(() => { + const objectUrl = URL.createObjectURL(dokument.blob); + setUrl(objectUrl); + return () => URL.revokeObjectURL(objectUrl); + }, [dokument.blob]); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose(); + }; + document.addEventListener("keydown", handleKeyDown); + return () => document.removeEventListener("keydown", handleKeyDown); + }, [onClose]); + + return ( +
e.key === "Escape" && onClose()} + > + + {url && ( + {dokument.name} e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + /> + )} +
+ ); +}