Three user-reported bugs on /cases/[caseNumber]: 1. Documents tab showed "9 מסמכים" in the count but rendered nothing — DocumentsPanel was reading filename/category/status/size_bytes/uploaded_at, but the real FastAPI payload (case_get → db.list_documents) returns title/doc_type/extraction_status/page_count/created_at. Rewrote the panel against the actual document row shape, added a CaseDocument type alias in lib/api/cases.ts, mapped doc_type to Hebrew labels (כתב ערר / כתב תשובה / ...) and extraction_status likewise. 2. The "פעולות" tab showed a debug-flavoured paragraph "עריכת פרטי התיק נשמרת מיד דרך PUT /api/cases/1033-25" — that was internal wording, not user copy. Removed. 3. Overview tab showed the raw enum value "full_acceptance" in the expected-outcome line. Mapped through the existing expectedOutcomes label array so it now reads "קבלה מלאה". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
116 lines
3.8 KiB
TypeScript
116 lines
3.8 KiB
TypeScript
import { Badge } from "@/components/ui/badge";
|
||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||
import type { CaseDetail } from "@/lib/api/cases";
|
||
|
||
/*
|
||
* Document list for the case detail "מסמכים" tab. Uses the real document
|
||
* row shape returned by the FastAPI case_get endpoint — see db.list_documents
|
||
* and the `documents` schema in legal_mcp/services/db.py:
|
||
* id · case_id · doc_type · title · file_path · extraction_status ·
|
||
* page_count · created_at · practice_area · appeal_subtype
|
||
*/
|
||
|
||
const DOC_TYPE_LABELS: Record<string, string> = {
|
||
appeal: "כתב ערר",
|
||
response: "כתב תשובה",
|
||
protocol: "פרוטוקול",
|
||
decision: "החלטת ועדה מקומית",
|
||
plan: "תכנית",
|
||
reference: "חומר רקע",
|
||
auto: "—",
|
||
};
|
||
|
||
function doctypeLabel(t: string): string {
|
||
return DOC_TYPE_LABELS[t] ?? t;
|
||
}
|
||
|
||
function doctypeTone(t: string): string {
|
||
switch (t) {
|
||
case "appeal": return "bg-info-bg text-info border-info/40";
|
||
case "response": return "bg-gold-wash text-gold-deep border-gold/40";
|
||
case "decision": return "bg-success-bg text-success border-success/40";
|
||
case "protocol": return "bg-warn-bg text-warn border-warn/40";
|
||
default: return "bg-rule-soft text-ink-muted border-rule";
|
||
}
|
||
}
|
||
|
||
const STATUS_LABELS: Record<string, string> = {
|
||
pending: "בהמתנה",
|
||
processing: "בעיבוד",
|
||
completed: "הושלם",
|
||
proofread: "הוגה",
|
||
failed: "נכשל",
|
||
error: "שגיאה",
|
||
};
|
||
|
||
function formatDate(iso: string) {
|
||
if (!iso) return "—";
|
||
try {
|
||
return new Date(iso).toLocaleDateString("he-IL");
|
||
} catch {
|
||
return iso;
|
||
}
|
||
}
|
||
|
||
function filenameFromPath(path: string): string {
|
||
const parts = path.split("/");
|
||
return parts[parts.length - 1] || path;
|
||
}
|
||
|
||
export function DocumentsPanel({ data }: { data?: CaseDetail }) {
|
||
const docs = data?.documents ?? [];
|
||
|
||
if (docs.length === 0) {
|
||
return (
|
||
<div className="text-center py-12 text-ink-muted">
|
||
<div className="text-gold text-2xl mb-2" aria-hidden="true">❦</div>
|
||
<p className="text-sm">אין מסמכים בתיק זה</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<ScrollArea className="max-h-[520px]">
|
||
<ul className="divide-y divide-rule">
|
||
{docs.map((doc) => {
|
||
const displayName = doc.title || filenameFromPath(doc.file_path);
|
||
const statusDone =
|
||
doc.extraction_status === "completed" ||
|
||
doc.extraction_status === "proofread";
|
||
return (
|
||
<li
|
||
key={doc.id}
|
||
className="py-3 flex items-start justify-between gap-4 hover:bg-gold-wash/30 transition-colors px-2 -mx-2 rounded"
|
||
>
|
||
<div className="flex-1 min-w-0 space-y-0.5">
|
||
<div className="text-ink font-medium truncate" title={displayName}>
|
||
{displayName}
|
||
</div>
|
||
<div className="text-[0.72rem] text-ink-muted flex items-center gap-3 flex-wrap">
|
||
{doc.page_count != null && (
|
||
<span className="tabular-nums">{doc.page_count} עמ׳</span>
|
||
)}
|
||
{doc.created_at && <span>{formatDate(doc.created_at)}</span>}
|
||
{!statusDone && doc.extraction_status && (
|
||
<span className="text-warn">
|
||
{STATUS_LABELS[doc.extraction_status] ?? doc.extraction_status}
|
||
</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
{doc.doc_type && (
|
||
<Badge
|
||
variant="outline"
|
||
className={`rounded-full px-2 py-0.5 text-[0.7rem] shrink-0 ${doctypeTone(doc.doc_type)}`}
|
||
>
|
||
{doctypeLabel(doc.doc_type)}
|
||
</Badge>
|
||
)}
|
||
</li>
|
||
);
|
||
})}
|
||
</ul>
|
||
</ScrollArea>
|
||
);
|
||
}
|