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

@@ -1,15 +1,14 @@
"use client";
import Link from "next/link";
import { AppShell } from "@/components/app-shell";
import { Card, CardContent } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { AppShell } from "@/components/app-shell";
import { LibraryListPanel } from "@/components/precedents/library-list-panel";
import { LibrarySearchPanel } from "@/components/precedents/library-search-panel";
import { HalachaReviewPanel } from "@/components/precedents/halacha-review-panel";
import { LibraryStatsPanel } from "@/components/precedents/library-stats-panel";
import { useHalachotPending } from "@/lib/api/precedent-library";
import { useMissingPrecedents } from "@/lib/api/missing-precedents";
/**
* Precedent Library admin page.
@@ -25,72 +24,133 @@ import { useHalachotPending } from "@/lib/api/precedent-library";
* per-case precedent attacher (chair-attached quotes scoped to a case).
*/
function PendingBadge() {
const { data } = useHalachotPending();
const n = data?.count ?? 0;
/** Colored count pill riding on a tab trigger (mockup 07: warn for review
* queue, info for incoming). Returns null when the queue is empty. */
function CountPill({ n, tone }: { n: number; tone: "warn" | "info" }) {
if (!n) return null;
const cls =
tone === "warn"
? "bg-warn text-white"
: "bg-info text-white";
return (
<Badge
variant="outline"
className="ms-1 bg-gold-wash text-gold-deep border-gold/40 text-[0.65rem]"
<span
className={`ms-1.5 inline-flex items-center justify-center rounded-full px-1.5 min-w-[1.15rem] h-[1.15rem] text-[0.68rem] font-semibold tabular-nums ${cls}`}
>
{n}
</Badge>
</span>
);
}
function PendingPill() {
const { data } = useHalachotPending();
return <CountPill n={data?.count ?? 0} tone="warn" />;
}
function IncomingPill() {
// "פסיקה נכנסת" = open missing-precedents waiting for the chair to upload.
const { data } = useMissingPrecedents({ status: "open", limit: 1 });
return <CountPill n={data?.by_status?.open ?? 0} tone="info" />;
}
export default function PrecedentsPage() {
return (
<AppShell>
<section className="space-y-6">
<header>
<nav className="text-[0.78rem] text-ink-muted mb-1">
<Link href="/" className="hover:text-gold-deep">בית</Link>
<span aria-hidden> · </span>
<span className="text-navy">ספריית פסיקה</span>
</nav>
<h1 className="text-navy mb-0">ספריית הפסיקה הסמכותית</h1>
<p className="text-ink-muted text-sm mt-1 max-w-3xl">
פסיקה חיצונית פסקי דין של ערכאות עליונות והחלטות של ועדות ערר אחרות.
כל קובץ עובר חילוץ הלכות אוטומטי, וההלכות ממתינות לאישור היו&quot;ר לפני
שהן זמינות לסוכני הכתיבה (legal-writer וכו&apos;).
</p>
</header>
<Tabs defaultValue="library" dir="rtl">
<section className="space-y-6">
<header className="space-y-3">
<nav className="text-[0.78rem] text-ink-muted">
<Link href="/" className="hover:text-gold-deep">בית</Link>
<span aria-hidden> · </span>
<span className="text-navy">ספריית פסיקה</span>
</nav>
<div className="space-y-1">
<h1 className="text-navy mb-0">ספריית הפסיקה הסמכותית</h1>
<p className="text-ink-muted text-sm mt-1 max-w-3xl leading-relaxed">
קורפוס הפסיקה והלכות המערכת חיפוש סמנטי, תור-אישור והשלמת
פסיקה חסרה. כל קובץ עובר חילוץ הלכות אוטומטי, וההלכות ממתינות
לאישור היו&quot;ר לפני שהן זמינות לסוכני הכתיבה.
</p>
</div>
<div className="h-[2px] bg-gradient-to-l from-transparent via-gold to-transparent" />
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5">
<Tabs defaultValue="library" dir="rtl">
<TabsList className="bg-rule-soft/60">
<TabsTrigger value="library">ספרייה</TabsTrigger>
<TabsTrigger value="search">חיפוש סמנטי</TabsTrigger>
<TabsTrigger value="review">
ממתין לאישור
<PendingBadge />
{/* tabs as a dedicated row under the header — underline-style
triggers with colored count pills (mockup 07). */}
<TabsList className="flex w-full justify-start gap-1 rounded-none border-0 border-b border-rule bg-transparent p-0 h-auto">
{[
{ value: "library", label: "ספרייה", pill: null },
{ value: "search", label: "חיפוש בקורפוס", pill: null },
{ value: "review", label: "תור הלכות", pill: <PendingPill /> },
{
value: "incoming",
label: "פסיקה נכנסת",
pill: <IncomingPill />,
},
{ value: "stats", label: "סטטיסטיקה", pill: null },
].map((t) => (
<TabsTrigger
key={t.value}
value={t.value}
className="rounded-none border-0 border-b-2 border-transparent bg-transparent px-4 py-2.5 -mb-px text-sm font-medium text-ink-muted shadow-none data-[state=active]:border-gold data-[state=active]:bg-transparent data-[state=active]:font-semibold data-[state=active]:text-navy data-[state=active]:shadow-none"
>
{t.label}
{t.pill}
</TabsTrigger>
<TabsTrigger value="stats">סטטיסטיקה</TabsTrigger>
</TabsList>
))}
</TabsList>
</header>
<TabsContent value="library" className="mt-5">
<LibraryListPanel />
</TabsContent>
<TabsContent value="library" className="mt-0">
<LibraryListPanel />
</TabsContent>
<TabsContent value="search" className="mt-5">
<LibrarySearchPanel />
</TabsContent>
<TabsContent value="search" className="mt-0">
<LibrarySearchPanel />
</TabsContent>
<TabsContent value="review" className="mt-5">
<HalachaReviewPanel />
</TabsContent>
<TabsContent value="review" className="mt-0">
<HalachaReviewPanel />
</TabsContent>
<TabsContent value="stats" className="mt-5">
<LibraryStatsPanel />
</TabsContent>
</Tabs>
</CardContent>
</Card>
</section>
{/* "פסיקה נכנסת" — the incoming/missing-precedent queue. Kept as a
tab per the mockup; full management lives on /missing-precedents. */}
<TabsContent value="incoming" className="mt-0">
<IncomingTab />
</TabsContent>
<TabsContent value="stats" className="mt-0">
<LibraryStatsPanel />
</TabsContent>
</section>
</Tabs>
</AppShell>
);
}
/** Lightweight in-tab pointer to the dedicated missing-precedents page,
* preserving the mockup's "פסיקה נכנסת" tab without duplicating the table. */
function IncomingTab() {
const { data } = useMissingPrecedents({ status: "open", limit: 1 });
const open = data?.by_status?.open ?? 0;
return (
<div className="rounded-lg border border-rule bg-surface shadow-sm p-6 space-y-3">
<div className="flex items-baseline gap-3 flex-wrap">
<h2 className="text-navy text-lg font-semibold m-0">פסיקה נכנסת</h2>
{open ? (
<span className="inline-flex items-baseline gap-1.5 rounded-lg border border-rule bg-warn-bg px-3 py-1">
<span className="text-base font-bold text-warn tabular-nums">{open}</span>
<span className="text-[0.8rem] text-ink-soft">פתוחים</span>
</span>
) : null}
</div>
<p className="text-ink-soft text-sm leading-relaxed max-w-2xl">
פסיקה שצוטטה בכתבי-הטענות אך אינה קיימת בקורפוס. השלמתה מאפשרת
אימות-הלכה ועיגון-מקור (INV-AH).
</p>
<Link
href="/missing-precedents"
className="inline-flex items-center rounded-md bg-gold px-4 py-2 text-sm font-semibold text-white hover:bg-gold-deep"
>
לניהול פסיקה חסרה
</Link>
</div>
);
}