"use client"; import { useMemo, useState } from "react"; import Link from "next/link"; import { flexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable, type ColumnDef, type SortingState, } from "@tanstack/react-table"; import { toast } from "sonner"; import { AppShell } from "@/components/app-shell"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Skeleton } from "@/components/ui/skeleton"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { useCases, useRestoreCase, type Case } from "@/lib/api/cases"; import { subtypeOf } from "@/components/cases/appeal-type-bars"; import { APPEAL_SUBTYPE_LABELS, type AppealSubtype } from "@/lib/practice-area"; import { formatDate, getIsraelYear } from "@/lib/format-date"; // type chip styling per mockup 05 (.t-lic / .t-bet / .t-comp) const TYPE_CHIP: Record = { building_permit: "bg-info-bg text-info", betterment_levy: "bg-gold-wash text-gold-deep border border-rule", compensation_197: "bg-rule-soft text-ink-soft", }; // outcome chip styling per mockup 05 (.r-acc / .r-rej / .r-part) const OUTCOME_CHIP: Record = { full_acceptance: { label: "התקבל", cls: "bg-success-bg text-success" }, partial_acceptance: { label: "חלקי", cls: "bg-warn-bg text-warn" }, rejection: { label: "נדחה", cls: "bg-danger-bg text-danger" }, }; function RestoreButton({ caseNumber }: { caseNumber: string }) { const restore = useRestoreCase(caseNumber); return ( ); } const columns: ColumnDef[] = [ { accessorKey: "case_number", header: "מספר ערר", cell: ({ row }) => ( {row.original.case_number} ), }, { accessorKey: "title", header: "כותרת", cell: ({ row }) => (
{row.original.title}
), }, { accessorKey: "appeal_subtype", header: "סוג", cell: ({ row }) => { const s = subtypeOf(row.original); if (!s || s === "unknown") return ; return ( {APPEAL_SUBTYPE_LABELS[s as AppealSubtype]} ); }, }, { accessorKey: "expected_outcome", header: "תוצאה", cell: ({ row }) => { const o = row.original.expected_outcome; const chip = o ? OUTCOME_CHIP[o] : undefined; if (!chip) return ; return ( {chip.label} ); }, }, { accessorKey: "archived_at", header: "תאריך ארכוב", cell: ({ row }) => ( {formatDate(row.original.archived_at)} ), }, { id: "actions", header: "", cell: ({ row }) => , }, ]; export default function ArchivePage() { const { data, isPending, error } = useCases(true, "archived"); const [sorting, setSorting] = useState([ { id: "archived_at", desc: true }, ]); const [globalFilter, setGlobalFilter] = useState(""); const [typeFilter, setTypeFilter] = useState("all"); const [yearFilter, setYearFilter] = useState("all"); const rows = useMemo(() => data ?? [], [data]); // years present in the archive (by archive date) — for the year filter (mockup 05) const years = useMemo(() => { const set = new Set(); for (const c of rows) { if (!c.archived_at) continue; const y = getIsraelYear(c.archived_at); if (y !== null) set.add(String(y)); } return [...set].sort((a, b) => Number(b) - Number(a)); }, [rows]); const table = useReactTable({ data: rows, columns, state: { sorting, globalFilter }, onSortingChange: setSorting, onGlobalFilterChange: setGlobalFilter, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), globalFilterFn: (row, _colId, filterValue: string) => { if (!filterValue) return true; const needle = filterValue.toLowerCase(); return ( row.original.case_number.toLowerCase().includes(needle) || row.original.title.toLowerCase().includes(needle) ); }, }); // domain filter applied client-side (subtypeOf collapses בל"מ variants) const filteredRows = useMemo(() => { let all = table.getFilteredRowModel().rows; if (typeFilter !== "all") all = all.filter((r) => subtypeOf(r.original) === typeFilter); if (yearFilter !== "all") { all = all.filter((r) => { const iso = r.original.archived_at; return iso != null && String(getIsraelYear(iso)) === yearFilter; }); } return all; }, [table, typeFilter, yearFilter, globalFilter, sorting, rows]); const total = rows.length; const shown = filteredRows.length; return (
ארכיון תיקי ערר

ארכיון

כל ההחלטות שהושלמו — לחיפוש, סינון ועיון. {total} תיקים סגורים. שחזור מחזיר את התיק לרשימה הראשית ופותח מחדש את הפרויקט המקביל ב-Paperclip.

{/* filter bar — search + domain select + count aligned to end (mockup 05 .filters) */}
setGlobalFilter(e.target.value)} placeholder="חיפוש לפי מספר ערר, כותרת או צד…" className="flex-1 min-w-[220px] bg-surface" dir="rtl" /> {years.length > 0 ? ( ) : null} מציג {shown} מתוך {total}
{/* clean bordered table — parchment header, gold-wash hover (mockup 05 .card table) */} {table.getHeaderGroups().map((hg) => ( {hg.headers.map((header) => ( {flexRender( header.column.columnDef.header, header.getContext(), )} {{ asc: " ▲", desc: " ▼" }[ header.column.getIsSorted() as string ] ?? ""} ))} ))} {isPending ? ( Array.from({ length: 3 }).map((_, i) => ( {columns.map((_c, j) => ( ))} )) ) : error ? ( שגיאה בטעינת ארכיון: {error.message} ) : filteredRows.length === 0 ? (
{globalFilter || typeFilter !== "all" || yearFilter !== "all" ? "אין תיקים תואמים לחיפוש" : "אין תיקים בארכיון"}
) : ( filteredRows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} )) )}
); }