feat(ui): IA redesign → production · יישום נאמן של 16 הדפים הנותרים למוקאפים
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s
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:
@@ -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">
|
||||
פסיקה חיצונית — פסקי דין של ערכאות עליונות והחלטות של ועדות ערר אחרות.
|
||||
כל קובץ עובר חילוץ הלכות אוטומטי, וההלכות ממתינות לאישור היו"ר לפני
|
||||
שהן זמינות לסוכני הכתיבה (legal-writer וכו').
|
||||
</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">
|
||||
קורפוס הפסיקה והלכות המערכת — חיפוש סמנטי, תור-אישור והשלמת
|
||||
פסיקה חסרה. כל קובץ עובר חילוץ הלכות אוטומטי, וההלכות ממתינות
|
||||
לאישור היו"ר לפני שהן זמינות לסוכני הכתיבה.
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user