"use client"; import { useMemo, useState } from "react"; import { useCaseFiles, useCaseFileText, caseFileUrl, type CaseFileFolder, } from "@/lib/api/case-files"; import { Markdown } from "@/components/ui/markdown"; import { Badge } from "@/components/ui/badge"; import { formatDateTime } from "@/lib/format-date"; import { Folder, FileText, File as FileIcon, Download, ChevronDown, Loader2, FolderOpen, } from "lucide-react"; /* ── Helpers ─────────────────────────────────────────────────── */ const FOLDER_LABELS: Record = { research: "מחקר וטיוטות", originals: "מסמכי מקור", extracted: "טקסט מחולץ (OCR)", proofread: "לאחר הגהה", drafts: "טיוטות DOCX", backup: "גיבויים", }; // Extensions the inline viewer can render (everything else → download only). const TEXT_EXT = new Set(["md", "txt", "json", "csv", "log", "markdown"]); function fileExt(filename: string): string { return filename.includes(".") ? filename.split(".").pop()!.toLowerCase() : ""; } function folderLabel(f: CaseFileFolder): string { return FOLDER_LABELS[f.name] ?? f.name; } function fmtSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / 1024 / 1024).toFixed(1)} MB`; } const EXT_TONE: Record = { md: "bg-teal-100 text-teal-700", markdown: "bg-teal-100 text-teal-700", txt: "bg-blue-100 text-blue-700", json: "bg-blue-100 text-blue-700", pdf: "bg-red-100 text-red-700", docx: "bg-indigo-100 text-indigo-700", doc: "bg-indigo-100 text-indigo-700", }; function extTone(ext: string): string { return EXT_TONE[ext] ?? "bg-gray-100 text-gray-600"; } type Selected = { folderKey: string; filename: string }; /* ── Component ───────────────────────────────────────────────── */ export function CaseFilesBrowser({ caseNumber }: { caseNumber: string }) { const { data, isLoading, error } = useCaseFiles(caseNumber); const folders = useMemo(() => data?.folders ?? [], [data?.folders]); const totalFiles = folders.reduce((n, f) => n + f.files.length, 0); // Default selection derived (not via an effect): a text file in research, // else any text file. The chair's explicit pick overrides it. const defaultSelected = useMemo(() => { const pick = ( pred: (f: CaseFileFolder, name: string) => boolean, ): Selected | null => { for (const f of folders) for (const file of f.files) if (pred(f, file.filename)) return { folderKey: f.key, filename: file.filename }; return null; }; return ( pick((f, name) => f.name === "research" && TEXT_EXT.has(fileExt(name))) ?? pick((_f, name) => TEXT_EXT.has(fileExt(name))) ); }, [folders]); const [userSelected, setUserSelected] = useState(null); const selected = userSelected ?? defaultSelected; // A folder is open if explicitly toggled; otherwise the folder of the current // selection (or the first non-empty folder) is open by default. const defaultOpenKey = selected?.folderKey ?? folders.find((f) => f.files.length)?.key ?? null; const [openOverrides, setOpenOverrides] = useState>( new Map(), ); const isOpen = (key: string) => openOverrides.has(key) ? openOverrides.get(key)! : key === defaultOpenKey; const selExt = selected ? fileExt(selected.filename) : ""; const selIsText = TEXT_EXT.has(selExt); const { data: fileText, isLoading: textLoading, error: textError, } = useCaseFileText( caseNumber, selIsText ? selected?.folderKey : undefined, selIsText ? selected?.filename : undefined, ); const toggleFolder = (key: string) => { const next = !isOpen(key); setOpenOverrides((prev) => new Map(prev).set(key, next)); }; if (isLoading) { return (
טוען קבצים...
); } if (error) { return (
שגיאה בטעינת קבצי-התיק
); } return (
{/* header */}

קבצי-התיק

כל תתי-התיקיות · {totalFiles} קבצים
{/* file tree */}
{folders.map((f) => { const open = isOpen(f.key); return (
{open && f.files.length > 0 && (
{f.files.map((file) => { const ext = fileExt(file.filename); const isSel = selected?.folderKey === f.key && selected?.filename === file.filename; const viewable = TEXT_EXT.has(ext); return (
viewable ? setUserSelected({ folderKey: f.key, filename: file.filename, }) : undefined } > {viewable ? ( ) : ( )}
{file.filename}
{fmtSize(file.size)} ·{" "} {formatDateTime(file.modified_at * 1000)}
e.stopPropagation()} className="w-7 h-7 rounded-md border border-rule bg-surface flex items-center justify-center text-ink-muted hover:text-navy shrink-0" title="הורדה" >
); })}
)}
); })} {folders.length === 0 && (
אין קבצים בתיק.
)}
{/* viewer */}
{!selected ? (
בחר קובץ טקסט מהרשימה לצפייה
) : ( <>
{selected.filename}
הורדה
{!selIsText ? (
קובץ מסוג {selExt || "?"} — לא ניתן לצפייה מוטבעת. הורד כדי לפתוח.
) : textLoading ? (
טוען תוכן...
) : textError ? (
שגיאה בטעינת תוכן הקובץ
) : selExt === "md" || selExt === "markdown" ? ( ) : (
                    {fileText}
                  
)}
)}
); }