"use client"; import { useEffect, useState } from "react"; import { Upload, Save, Loader2, CheckCircle2 } from "lucide-react"; import { toast } from "sonner"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, } from "@/components/ui/sheet"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { useMissingPrecedent, useUpdateMissingPrecedent, useUploadMissingPrecedent, STATUS_LABELS, type MissingPrecedentPatch, } from "@/lib/api/missing-precedents"; import { PRACTICE_AREAS, PRECEDENT_LEVELS, DISTRICTS, } from "@/components/precedents/practice-area"; type Props = { id: string | null; onOpenChange: (open: boolean) => void; }; const ACCEPT = ".pdf,.docx,.doc,.rtf,.txt,.md"; function isCommitteeCitation(citation: string): boolean { const norm = citation.trim(); return /^(ערר[\s(]|בל"מ[\s(]|ARAR )/.test(norm); } export function MissingPrecedentDetailDrawer({ id, onOpenChange }: Props) { const open = id !== null; const { data: mp, isPending } = useMissingPrecedent(id); const update = useUpdateMissingPrecedent(); const upload = useUploadMissingPrecedent(); // The only chair-editable field on the missing-precedent is `notes` — // free-text. Everything else (citation, who-cited-whom, status) is set // when the row was detected, and updates automatically when the file // is uploaded. The metadata of the *uploaded* precedent (case_name, // chair, district, …) is auto-extracted by the LLM and lives on the // case_law row, not here. const [notes, setNotes] = useState(""); // Upload form fields. const [file, setFile] = useState(null); const [decisionDate, setDecisionDate] = useState(""); const [court, setCourt] = useState(""); const [practiceArea, setPracticeArea] = useState(""); const [appealSubtype, setAppealSubtype] = useState(""); const [precedentLevel, setPrecedentLevel] = useState(""); const [chairName, setChairName] = useState(""); const [district, setDistrict] = useState(""); const [committeeCaseNumber, setCommitteeCaseNumber] = useState(""); const [summary, setSummary] = useState(""); // Sync form from record when it loads or id changes. const [syncedId, setSyncedId] = useState(null); if (mp && mp.id !== syncedId) { setSyncedId(mp.id); setNotes(mp.notes ?? ""); } // Reset on close. The cascading-render warning is the intended side // effect here — wiping the form when the drawer closes. useEffect(() => { if (open) return; // eslint-disable-next-line react-hooks/set-state-in-effect setFile(null); setSyncedId(null); setDecisionDate(""); setCourt(""); setPracticeArea(""); setAppealSubtype(""); setPrecedentLevel(""); setChairName(""); setDistrict(""); setCommitteeCaseNumber(""); setSummary(""); }, [open]); const handleSaveNotes = async () => { if (!mp) return; const patch: MissingPrecedentPatch = { notes }; try { await update.mutateAsync({ id: mp.id, patch }); toast.success("הערות נשמרו"); } catch (e) { toast.error("שמירה נכשלה"); console.error(e); } }; const isCommittee = mp ? isCommitteeCitation(mp.citation) : false; const handleUpload = async (e: React.FormEvent) => { e.preventDefault(); if (!mp || !file) { toast.error("בחר קובץ"); return; } try { await upload.mutateAsync({ id: mp.id, file, case_number: isCommittee ? committeeCaseNumber || undefined : undefined, chair_name: isCommittee ? chairName || undefined : undefined, district: isCommittee ? district || undefined : undefined, court: court || undefined, decision_date: decisionDate || undefined, practice_area: practiceArea || undefined, appeal_subtype: appealSubtype || undefined, precedent_level: precedentLevel || undefined, source_type: isCommittee ? "appeals_committee" : "court_ruling", summary: summary || undefined, }); toast.success( "הקובץ הועלה. חילוץ המטא־דאטה (שם, ערכאה, תאריך, יו״ר, מחוז…) מתבצע ברקע ויסתיים בתוך כדקה.", ); onOpenChange(false); } catch (e: unknown) { const msg = e instanceof Error ? e.message : typeof e === "string" ? e : "כשל העלאה"; toast.error(msg); console.error(e); } }; return ( פסיקה חסרה {mp ? ( {STATUS_LABELS[mp.status]} ) : null} פרטים מלאים והעלאת הפסיקה לקורפוס. {isPending || !mp ? (
) : (
{/* ── Citation block (read-only) ── */}
מראה מקום
{mp.citation}
{mp.claim_quote ? ( <>
ציטוט מכתב הטענות
{mp.claim_quote}
) : null}
{/* ── Linked record (if closed) ── */} {mp.linked_case_law_id ? (
מקושר ל
{mp.linked_case_law_name || "—"}
{mp.linked_case_law_number}
) : null} {/* ── Notes (only chair-editable field; everything else is auto-detected or auto-extracted from the file). ── */}

שדה חופשי — לדוגמה: מי מצטט (הוועדה / העורר / המשיב) ובאיזה הקשר. שאר השדות (שם, ערכאה, יו״ר, מחוז, תאריך, תת־סוג, תקציר) יחולצו אוטומטית מהקובץ בעת ההעלאה.