Merge pull request 'feat(missing-precedents): accordion grouping by discovery source' (#312) from worktree-mp-accordion into main
This commit was merged in pull request #312.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { Trash2, Upload, Pencil, ExternalLink } from "lucide-react";
|
import { Trash2, Upload, Pencil, ExternalLink, ChevronDown } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {
|
import {
|
||||||
@@ -63,6 +63,24 @@ function SourceChip({ party }: { party: CitedByParty | null }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const COLS = 7;
|
||||||
|
|
||||||
|
function TableHeaderRow() {
|
||||||
|
return (
|
||||||
|
<TableHeader className="bg-parchment">
|
||||||
|
<TableRow className="border-rule hover:bg-transparent">
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">פסיקה</TableHead>
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">נושא</TableHead>
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">תיק</TableHead>
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">צוטט ע״י</TableHead>
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">סטטוס</TableHead>
|
||||||
|
<TableHead className="text-ink-muted text-right font-medium text-xs">נוצר</TableHead>
|
||||||
|
<TableHead className="text-navy" />
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function TableSkeleton({ cols }: { cols: number }) {
|
function TableSkeleton({ cols }: { cols: number }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -79,6 +97,38 @@ function TableSkeleton({ cols }: { cols: number }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Accordion section meta — groups rows by discovery source (chair's request).
|
||||||
|
* "צוטט ע״י דפנה" (corpus-decision reliance) is the high-value group and opens
|
||||||
|
* by default; the noisy יומון group and the misc "אחר" group start collapsed. */
|
||||||
|
type SectionKey = "chair" | "digest" | "other";
|
||||||
|
const SECTION_META: Record<
|
||||||
|
SectionKey,
|
||||||
|
{ label: string; title: string; desc: string; chip: string; defaultOpen: boolean }
|
||||||
|
> = {
|
||||||
|
chair: {
|
||||||
|
label: "צוטט ע״י דפנה",
|
||||||
|
title: "פסיקה שהוועדה נסמכת עליה",
|
||||||
|
desc: "מצוטטת בהחלטות-הקורפוס (גרף-הציטוטים)",
|
||||||
|
chip: "bg-success-bg text-success",
|
||||||
|
defaultOpen: true,
|
||||||
|
},
|
||||||
|
digest: {
|
||||||
|
label: "יומון",
|
||||||
|
title: "זוהתה ביומון יומי",
|
||||||
|
desc: "מצביע, טרם צוטט בהחלטה",
|
||||||
|
chip: "bg-teal-bg text-teal",
|
||||||
|
defaultOpen: false,
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
label: "אחר",
|
||||||
|
title: "כתב-טענות / ידני",
|
||||||
|
desc: "צוטט בערר חי או נרשם ידנית",
|
||||||
|
chip: "bg-info-bg text-info",
|
||||||
|
defaultOpen: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const SECTION_ORDER: SectionKey[] = ["chair", "digest", "other"];
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
status?: MissingPrecedentStatus | "";
|
status?: MissingPrecedentStatus | "";
|
||||||
q?: string;
|
q?: string;
|
||||||
@@ -108,6 +158,196 @@ export function MissingPrecedentsTable({ status, q, legalTopic }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Partition the current result set by discovery source so each accordion
|
||||||
|
* section renders only its own rows. A row "cited by the committee" (has a
|
||||||
|
* resolved chair from the citation-graph bridge) wins over its raw
|
||||||
|
* discovery_source — that's the group the chair cares about. */
|
||||||
|
const groups = useMemo(() => {
|
||||||
|
const g: Record<SectionKey, MissingPrecedent[]> = { chair: [], digest: [], other: [] };
|
||||||
|
for (const mp of data?.items ?? []) {
|
||||||
|
if (mp.cited_by_chairs?.length) g.chair.push(mp);
|
||||||
|
else if (mp.discovery_source === "digest") g.digest.push(mp);
|
||||||
|
else g.other.push(mp);
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const renderRow = (mp: MissingPrecedent) => (
|
||||||
|
<TableRow
|
||||||
|
key={mp.id}
|
||||||
|
className="border-rule hover:bg-rule-soft/30 cursor-pointer"
|
||||||
|
onClick={() => setOpenId(mp.id)}
|
||||||
|
>
|
||||||
|
<TableCell className="max-w-[440px]">
|
||||||
|
{/* Single line when there's no distinct case_name — the old two-line
|
||||||
|
layout repeated the citation (name fell back to a truncation of the
|
||||||
|
same citation). Show the name row only when it adds information. */}
|
||||||
|
{mp.case_name && mp.case_name.trim() ? (
|
||||||
|
<>
|
||||||
|
<div className="text-sm text-navy font-semibold truncate">
|
||||||
|
{mp.case_name}
|
||||||
|
</div>
|
||||||
|
<div className="text-[0.72rem] text-ink-muted truncate" dir="rtl">
|
||||||
|
{mp.citation}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="text-sm text-navy font-semibold truncate" dir="rtl">
|
||||||
|
{mp.citation}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<span className="text-sm text-ink">{mp.legal_topic || "—"}</span>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{mp.cited_by_decisions?.length ? (
|
||||||
|
/* committee decision(s) that cite this missing ruling
|
||||||
|
(corpus citation-graph bridge) */
|
||||||
|
<span className="inline-flex items-baseline gap-1.5">
|
||||||
|
<span className="text-sm text-navy font-semibold tabular-nums" dir="ltr">
|
||||||
|
{mp.cited_by_decisions[0]}
|
||||||
|
</span>
|
||||||
|
{mp.cited_by_decisions.length > 1 ? (
|
||||||
|
<span className="text-[0.7rem] text-ink-muted">
|
||||||
|
+{mp.cited_by_decisions.length - 1}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
) : mp.cited_in_case_number ? (
|
||||||
|
<Link
|
||||||
|
href={`/cases/${encodeURIComponent(mp.cited_in_case_number)}`}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="text-sm text-navy hover:text-gold-deep inline-flex items-center gap-1"
|
||||||
|
>
|
||||||
|
{mp.cited_in_case_number}
|
||||||
|
<ExternalLink className="w-3 h-3" />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span className="text-ink-muted text-sm">—</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-sm text-ink">
|
||||||
|
{mp.cited_by_chairs?.length ? (
|
||||||
|
/* cited by a committee DECISION in the corpus → show the chair who
|
||||||
|
relied on it (e.g. דפנה תמיר). Bridge from
|
||||||
|
precedent_internal_citations; takes priority over the generic
|
||||||
|
discovery-source chips. */
|
||||||
|
<>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="rounded-full whitespace-nowrap bg-success-bg text-success border-transparent"
|
||||||
|
>
|
||||||
|
{mp.cited_by_chairs[0]}
|
||||||
|
</Badge>
|
||||||
|
{mp.cited_by_chairs.length > 1 ? (
|
||||||
|
<div className="text-[0.7rem] text-ink-muted mt-1">
|
||||||
|
+{mp.cited_by_chairs.length - 1} יו״ר
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : mp.discovery_source === "cited_only" ? (
|
||||||
|
<>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="rounded-full whitespace-nowrap bg-plum-bg text-plum border-transparent"
|
||||||
|
>
|
||||||
|
פסיקה בקורפוס
|
||||||
|
</Badge>
|
||||||
|
{mp.cited_by_precedents?.length ? (
|
||||||
|
<div className="text-[0.7rem] text-ink-muted truncate max-w-[180px] mt-1">
|
||||||
|
מצוטט ע״י: {mp.cited_by_precedents.join(", ")}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : mp.discovery_source === "digest" ? (
|
||||||
|
<>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="rounded-full whitespace-nowrap bg-teal-bg text-teal border-transparent"
|
||||||
|
>
|
||||||
|
יומון
|
||||||
|
</Badge>
|
||||||
|
{mp.yomon_number ? (
|
||||||
|
<div className="text-[0.7rem] text-ink-muted mt-1">
|
||||||
|
מס׳ {mp.yomon_number}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<SourceChip party={mp.cited_by_party} />
|
||||||
|
{mp.cited_by_party_name ? (
|
||||||
|
<div className="text-[0.7rem] text-ink-muted truncate max-w-[160px] mt-1">
|
||||||
|
{mp.cited_by_party_name}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusBadge status={mp.status} />
|
||||||
|
{mp.linked_case_law_number ? (
|
||||||
|
<div className="text-[0.7rem] text-success mt-1">
|
||||||
|
↳ {mp.linked_case_law_name || mp.linked_case_law_number}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-[0.78rem] text-ink-muted">
|
||||||
|
{formatDate(mp.created_at)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-end">
|
||||||
|
<div className="flex items-center justify-end gap-2">
|
||||||
|
{mp.status === "open" ? (
|
||||||
|
/* gold "העלה והשלם" CTA (mockup 09 `.btn`) */
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setOpenId(mp.id);
|
||||||
|
}}
|
||||||
|
className="h-7 bg-gold text-white hover:bg-gold-deep border-transparent text-[0.78rem] font-semibold"
|
||||||
|
>
|
||||||
|
<Upload className="w-3.5 h-3.5 me-1" />
|
||||||
|
העלה והשלם
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
/* passive "done" label for non-open rows */
|
||||||
|
<span className="inline-flex items-center gap-1 rounded-md bg-rule-soft text-ink-muted text-[0.78rem] font-medium px-2.5 py-1">
|
||||||
|
{mp.status === "closed" ? "קושר" : STATUS_LABELS[mp.status]} ✓
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{mp.status !== "open" ? (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setOpenId(mp.id);
|
||||||
|
}}
|
||||||
|
title="פרטים"
|
||||||
|
>
|
||||||
|
<Pencil className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleDelete(mp);
|
||||||
|
}}
|
||||||
|
disabled={del.isPending}
|
||||||
|
className="text-danger hover:text-danger"
|
||||||
|
title="מחיקה"
|
||||||
|
>
|
||||||
|
<Trash2 className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded bg-danger-bg border border-danger/40 px-6 py-4 text-danger text-center text-sm">
|
<div className="rounded bg-danger-bg border border-danger/40 px-6 py-4 text-danger text-center text-sm">
|
||||||
@@ -116,211 +356,61 @@ export function MissingPrecedentsTable({ status, q, legalTopic }: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
if (isPending) {
|
||||||
<>
|
return (
|
||||||
<div className="rounded-lg border border-rule bg-surface shadow-sm overflow-hidden">
|
<div className="rounded-lg border border-rule bg-surface shadow-sm overflow-hidden">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader className="bg-parchment">
|
<TableHeaderRow />
|
||||||
<TableRow className="border-rule hover:bg-transparent">
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">פסיקה</TableHead>
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">נושא</TableHead>
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">תיק</TableHead>
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">צוטט ע״י</TableHead>
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">סטטוס</TableHead>
|
|
||||||
<TableHead className="text-ink-muted text-right font-medium text-xs">נוצר</TableHead>
|
|
||||||
<TableHead className="text-navy" />
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{isPending ? (
|
<TableSkeleton cols={COLS} />
|
||||||
<TableSkeleton cols={7} />
|
|
||||||
) : !data?.items.length ? (
|
|
||||||
<TableRow className="border-rule">
|
|
||||||
<TableCell colSpan={7} className="text-center text-ink-muted py-8">
|
|
||||||
אין פסיקות חסרות בקריטריונים הנוכחיים.
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
) : (
|
|
||||||
data.items.map((mp) => (
|
|
||||||
<TableRow
|
|
||||||
key={mp.id}
|
|
||||||
className="border-rule hover:bg-rule-soft/30 cursor-pointer"
|
|
||||||
onClick={() => setOpenId(mp.id)}
|
|
||||||
>
|
|
||||||
<TableCell className="max-w-[440px]">
|
|
||||||
{/* Single line when there's no distinct case_name — the old
|
|
||||||
two-line layout repeated the citation (name fell back to a
|
|
||||||
truncation of the same citation). Show the name row only
|
|
||||||
when it adds information. */}
|
|
||||||
{mp.case_name && mp.case_name.trim() ? (
|
|
||||||
<>
|
|
||||||
<div className="text-sm text-navy font-semibold truncate">
|
|
||||||
{mp.case_name}
|
|
||||||
</div>
|
|
||||||
<div className="text-[0.72rem] text-ink-muted truncate" dir="rtl">
|
|
||||||
{mp.citation}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="text-sm text-navy font-semibold truncate" dir="rtl">
|
|
||||||
{mp.citation}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<span className="text-sm text-ink">{mp.legal_topic || "—"}</span>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{mp.cited_by_decisions?.length ? (
|
|
||||||
/* committee decision(s) that cite this missing ruling
|
|
||||||
(corpus citation-graph bridge) */
|
|
||||||
<span className="inline-flex items-baseline gap-1.5">
|
|
||||||
<span className="text-sm text-navy font-semibold tabular-nums" dir="ltr">
|
|
||||||
{mp.cited_by_decisions[0]}
|
|
||||||
</span>
|
|
||||||
{mp.cited_by_decisions.length > 1 ? (
|
|
||||||
<span className="text-[0.7rem] text-ink-muted">
|
|
||||||
+{mp.cited_by_decisions.length - 1}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
) : mp.cited_in_case_number ? (
|
|
||||||
<Link
|
|
||||||
href={`/cases/${encodeURIComponent(mp.cited_in_case_number)}`}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
className="text-sm text-navy hover:text-gold-deep inline-flex items-center gap-1"
|
|
||||||
>
|
|
||||||
{mp.cited_in_case_number}
|
|
||||||
<ExternalLink className="w-3 h-3" />
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<span className="text-ink-muted text-sm">—</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-sm text-ink">
|
|
||||||
{mp.cited_by_chairs?.length ? (
|
|
||||||
/* cited by a committee DECISION in the corpus → show the
|
|
||||||
chair who relied on it (e.g. דפנה תמיר). Bridge from
|
|
||||||
precedent_internal_citations; takes priority over the
|
|
||||||
generic discovery-source chips. */
|
|
||||||
<>
|
|
||||||
<Badge
|
|
||||||
variant="outline"
|
|
||||||
className="rounded-full whitespace-nowrap bg-success-bg text-success border-transparent"
|
|
||||||
>
|
|
||||||
{mp.cited_by_chairs[0]}
|
|
||||||
</Badge>
|
|
||||||
{mp.cited_by_chairs.length > 1 ? (
|
|
||||||
<div className="text-[0.7rem] text-ink-muted mt-1">
|
|
||||||
+{mp.cited_by_chairs.length - 1} יו״ר
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : mp.discovery_source === "cited_only" ? (
|
|
||||||
<>
|
|
||||||
<Badge
|
|
||||||
variant="outline"
|
|
||||||
className="rounded-full whitespace-nowrap bg-plum-bg text-plum border-transparent"
|
|
||||||
>
|
|
||||||
פסיקה בקורפוס
|
|
||||||
</Badge>
|
|
||||||
{mp.cited_by_precedents?.length ? (
|
|
||||||
<div className="text-[0.7rem] text-ink-muted truncate max-w-[180px] mt-1">
|
|
||||||
מצוטט ע״י: {mp.cited_by_precedents.join(", ")}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : mp.discovery_source === "digest" ? (
|
|
||||||
<>
|
|
||||||
<Badge
|
|
||||||
variant="outline"
|
|
||||||
className="rounded-full whitespace-nowrap bg-teal-bg text-teal border-transparent"
|
|
||||||
>
|
|
||||||
יומון
|
|
||||||
</Badge>
|
|
||||||
{mp.yomon_number ? (
|
|
||||||
<div className="text-[0.7rem] text-ink-muted mt-1">
|
|
||||||
מס׳ {mp.yomon_number}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<SourceChip party={mp.cited_by_party} />
|
|
||||||
{mp.cited_by_party_name ? (
|
|
||||||
<div className="text-[0.7rem] text-ink-muted truncate max-w-[160px] mt-1">
|
|
||||||
{mp.cited_by_party_name}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<StatusBadge status={mp.status} />
|
|
||||||
{mp.linked_case_law_number ? (
|
|
||||||
<div className="text-[0.7rem] text-success mt-1">
|
|
||||||
↳ {mp.linked_case_law_name || mp.linked_case_law_number}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-[0.78rem] text-ink-muted">
|
|
||||||
{formatDate(mp.created_at)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-end">
|
|
||||||
<div className="flex items-center justify-end gap-2">
|
|
||||||
{mp.status === "open" ? (
|
|
||||||
/* gold "העלה והשלם" CTA (mockup 09 `.btn`) */
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setOpenId(mp.id);
|
|
||||||
}}
|
|
||||||
className="h-7 bg-gold text-white hover:bg-gold-deep border-transparent text-[0.78rem] font-semibold"
|
|
||||||
>
|
|
||||||
<Upload className="w-3.5 h-3.5 me-1" />
|
|
||||||
העלה והשלם
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
/* passive "done" label for non-open rows */
|
|
||||||
<span className="inline-flex items-center gap-1 rounded-md bg-rule-soft text-ink-muted text-[0.78rem] font-medium px-2.5 py-1">
|
|
||||||
{mp.status === "closed" ? "קושר" : STATUS_LABELS[mp.status]} ✓
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{mp.status !== "open" ? (
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setOpenId(mp.id);
|
|
||||||
}}
|
|
||||||
title="פרטים"
|
|
||||||
>
|
|
||||||
<Pencil className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleDelete(mp);
|
|
||||||
}}
|
|
||||||
disabled={del.isPending}
|
|
||||||
className="text-danger hover:text-danger"
|
|
||||||
title="מחיקה"
|
|
||||||
>
|
|
||||||
<Trash2 className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data?.items.length) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-lg border border-rule bg-surface shadow-sm px-6 py-10 text-center text-ink-muted text-sm">
|
||||||
|
אין פסיקות חסרות בקריטריונים הנוכחיים.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="space-y-3.5">
|
||||||
|
{SECTION_ORDER.map((key) => {
|
||||||
|
const items = groups[key];
|
||||||
|
if (!items.length) return null;
|
||||||
|
const meta = SECTION_META[key];
|
||||||
|
return (
|
||||||
|
<details
|
||||||
|
key={key}
|
||||||
|
open={meta.defaultOpen}
|
||||||
|
className="group rounded-lg border border-rule bg-surface shadow-sm overflow-hidden"
|
||||||
|
>
|
||||||
|
<summary className="flex items-center gap-3 px-4 py-3.5 bg-parchment cursor-pointer select-none list-none [&::-webkit-details-marker]:hidden">
|
||||||
|
<ChevronDown className="w-4 h-4 text-ink-muted transition-transform -rotate-90 group-open:rotate-0 shrink-0" />
|
||||||
|
<span className={`rounded-full px-2.5 py-0.5 text-[0.72rem] font-semibold whitespace-nowrap ${meta.chip}`}>
|
||||||
|
{meta.label}
|
||||||
|
</span>
|
||||||
|
<span className="font-bold text-navy text-sm">{meta.title}</span>
|
||||||
|
<span className="hidden sm:inline text-ink-muted text-[0.78rem]">
|
||||||
|
— {meta.desc}
|
||||||
|
</span>
|
||||||
|
<span className="ms-auto tabular-nums text-[0.8rem] text-ink-soft bg-surface border border-rule rounded-full px-2.5 py-0.5 font-semibold">
|
||||||
|
{items.length}
|
||||||
|
</span>
|
||||||
|
</summary>
|
||||||
|
<Table>
|
||||||
|
<TableHeaderRow />
|
||||||
|
<TableBody>{items.map(renderRow)}</TableBody>
|
||||||
|
</Table>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
<MissingPrecedentDetailDrawer
|
<MissingPrecedentDetailDrawer
|
||||||
id={openId}
|
id={openId}
|
||||||
|
|||||||
Reference in New Issue
Block a user