feat(ui): IA redesign → production · יישום נאמן של 16 הדפים הנותרים למוקאפים
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s

תיקון הגישה: יישום מלא ונאמן של עיצוב-המוקאפים המאושרים (Claude Design) על כל
הדפים — שינוי-הרכב אמיתי פר-מוקאפ, לא ליטוש-טוקנים. כל hook/query/mutation/טאב/
טופס/נתון נשמר (אומת: tsc נקי + בדיקת-נוכחות hooks קריטיים; 0 פונקציונליות נמחקה).

דפים (← מוקאפ):
- בית — לוח: KPI + "תיקים לפי סטטוס" (bars) + כרטיס-אישורים + CTA כפול.
- ארכיון — filter-bar שטוח + טבלה נקייה + צ'יפי-סוג/תוצאה.
- הערות יו״ר — פריסה דו-טורית + טופס-הוספה חי + כרטיסי-הערה.
- ספריית-פסיקה — tabs קו-תחתון + כרטיסי-תוצאה halacha/קטע + AuthorityBadge.
- דף-תקדים — באנר-meta parchment + דו-טורי + provenance pills.
- פסיקה-חסרה — pill פתוחים + צ'יפי-סטטוס + CTA העלאה.
- יומונים — אזור-העלאה מקווקו + כרטיסי-digest + "ממתין" כתווית פסיבית.
- גרף — פאנל-צד שכבות/אנליטיקה + canvas parchment.
- אימון-סגנון — פורטרט: banner + KPI + אנטומיה + ביטויי-חתימה.
- מתודולוגיה — עורך-צ'קליסט + "חל על:" + canon chip.
- מיומנויות/סקריפטים — טבלאות אמיתיות + צ'יפי-סטטוס.
- הגדרות — sidenav דו-טורי + env-rows עם "ממתין ל-redeploy".
- דף-תיק — באנר-תיק parchment + tabs + timeline + "פתח עורך החלטה".
- תפעול — SectionHeaders + טבלת-שירותים + כרטיסי-שער gold-wash.
- compose — באנר-תיק + SOT pill + פריסה דו-טורית + "השלמה והעברה".

תיקונים שלי אחרי הסוכנים: documents-panel (הוצאת רכיב Shell מ-render — React
Compiler), scripts useMemo deps. /approvals כבר נבנה מחדש נאמנה (commit קודם).

בדיקות: npx tsc --noEmit ✓ · eslint ✓ (לבד מ-learning-panel:109 קיים-מראש).
שימור-פונקציונליות אומת. CI Docker build = שער סופי לפני deploy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 23:00:25 +00:00
parent c53ef9a7c4
commit f3b075d282
32 changed files with 2925 additions and 1799 deletions

View File

@@ -15,6 +15,7 @@ import {
useDeleteMissingPrecedent,
CITED_BY_PARTY_LABELS,
STATUS_LABELS,
type CitedByParty,
type MissingPrecedent,
type MissingPrecedentStatus,
} from "@/lib/api/missing-precedents";
@@ -29,20 +30,39 @@ function formatDate(iso: string | null) {
}
}
/** Status chip — mockup 09 tones (open=warn, uploaded=info, closed=success,
* irrelevant=muted). Pill-shaped, whitespace-nowrap. */
function StatusBadge({ status }: { status: MissingPrecedentStatus }) {
const variants: Record<MissingPrecedentStatus, string> = {
open: "bg-gold-wash text-gold-deep border-gold/40",
uploaded: "bg-rule-soft text-ink-muted border-rule",
closed: "bg-emerald-50 text-emerald-800 border-emerald-300/60",
irrelevant: "bg-rule-soft text-ink-muted border-rule line-through",
open: "bg-warn-bg text-warn border-transparent",
uploaded: "bg-info-bg text-info border-transparent",
closed: "bg-success-bg text-success border-transparent",
irrelevant: "bg-rule-soft text-ink-muted border-transparent",
};
return (
<Badge variant="outline" className={variants[status]}>
<Badge variant="outline" className={`rounded-full whitespace-nowrap ${variants[status]}`}>
{STATUS_LABELS[status]}
</Badge>
);
}
/** Citing-party chip — colored by side (mockup 09 source chips). */
function SourceChip({ party }: { party: CitedByParty | null }) {
if (!party) return <span className="text-ink-muted text-sm"></span>;
const variants: Record<CitedByParty, string> = {
appellant: "bg-info-bg text-info border-transparent",
respondent: "bg-gold-wash text-gold-deep border-rule",
committee: "bg-success-bg text-success border-transparent",
permit_applicant: "bg-info-bg text-info border-transparent",
unknown: "bg-rule-soft text-ink-muted border-transparent",
};
return (
<Badge variant="outline" className={`rounded-full whitespace-nowrap ${variants[party]}`}>
{CITED_BY_PARTY_LABELS[party]}
</Badge>
);
}
function TableSkeleton({ cols }: { cols: number }) {
return (
<>
@@ -100,14 +120,14 @@ export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props
<>
<div className="rounded-lg border border-rule bg-surface shadow-sm overflow-hidden">
<Table>
<TableHeader className="bg-rule-soft/60">
<TableRow className="border-rule">
<TableHead className="text-navy text-right">פסיקה</TableHead>
<TableHead className="text-navy text-right">נושא</TableHead>
<TableHead className="text-navy text-right">תיק</TableHead>
<TableHead className="text-navy text-right">צד מצטט</TableHead>
<TableHead className="text-navy text-right">סטטוס</TableHead>
<TableHead className="text-navy text-right">נוצר</TableHead>
<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>
@@ -128,7 +148,7 @@ export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props
onClick={() => setOpenId(mp.id)}
>
<TableCell className="max-w-[440px]">
<div className="text-sm text-navy font-medium truncate">
<div className="text-sm text-navy font-semibold truncate">
{mp.case_name || mp.citation.split(" ").slice(0, 6).join(" ")}
</div>
<div className="text-[0.72rem] text-ink-muted truncate" dir="rtl">
@@ -153,11 +173,9 @@ export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props
)}
</TableCell>
<TableCell className="text-sm text-ink">
{mp.cited_by_party
? CITED_BY_PARTY_LABELS[mp.cited_by_party]
: "—"}
<SourceChip party={mp.cited_by_party} />
{mp.cited_by_party_name ? (
<div className="text-[0.7rem] text-ink-muted truncate max-w-[160px]">
<div className="text-[0.7rem] text-ink-muted truncate max-w-[160px] mt-1">
{mp.cited_by_party_name}
</div>
) : null}
@@ -165,7 +183,7 @@ export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props
<TableCell>
<StatusBadge status={mp.status} />
{mp.linked_case_law_number ? (
<div className="text-[0.7rem] text-emerald-700 mt-1">
<div className="text-[0.7rem] text-success mt-1">
{mp.linked_case_law_name || mp.linked_case_law_number}
</div>
) : null}
@@ -174,22 +192,39 @@ export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props
{formatDate(mp.created_at)}
</TableCell>
<TableCell className="text-end">
<div className="flex items-center justify-end gap-1">
<Button
variant="ghost"
size="sm"
onClick={(e) => {
e.stopPropagation();
setOpenId(mp.id);
}}
title={mp.status === "open" ? "העלאה" : "פרטים"}
>
{mp.status === "open" ? (
<Upload className="w-4 h-4" />
) : (
<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>
</Button>
) : null}
<Button
variant="ghost"
size="sm"