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:
@@ -9,8 +9,30 @@ import { AppealTypeBars, subtypeOf } from "@/components/cases/appeal-type-bars";
|
||||
import { CasesTable } from "@/components/cases/cases-table";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useCases, type Case } from "@/lib/api/cases";
|
||||
import { usePendingApprovals } from "@/lib/api/chair";
|
||||
import { useCases, type Case, type CaseStatus } from "@/lib/api/cases";
|
||||
import {
|
||||
usePendingApprovals,
|
||||
type ApprovalSeverity,
|
||||
} from "@/lib/api/chair";
|
||||
|
||||
// severity dot per the approved 04-home mockup gate-list (.dot.high/.med/.ok)
|
||||
const SEVERITY_DOT: Record<ApprovalSeverity, string> = {
|
||||
high: "bg-danger",
|
||||
medium: "bg-warn",
|
||||
low: "bg-info",
|
||||
ok: "bg-success",
|
||||
};
|
||||
|
||||
// "תיקים לפי סטטוס" horizontal status bars (mockup 04: .bar / .track / .fill).
|
||||
// Driven by the same live cases the KPI row uses — five status groups onto the
|
||||
// gold/info/success/danger/muted palette.
|
||||
type StatusBarRow = { label: string; fill: string; match: CaseStatus[] };
|
||||
const STATUS_BARS: StatusBarRow[] = [
|
||||
{ label: "בהכנה", fill: "bg-info", match: ["new", "uploading", "processing", "documents_ready", "analyst_verified", "research_complete", "outcome_set"] },
|
||||
{ label: "ניתוח וכיוון", fill: "bg-gold", match: ["brainstorming", "direction_approved", "analysis_enriched", "ready_for_writing"] },
|
||||
{ label: "בכתיבה", fill: "bg-warn", match: ["drafting", "qa_review", "drafted"] },
|
||||
{ label: "הושלם", fill: "bg-success", match: ["exported", "reviewed", "final"] },
|
||||
];
|
||||
|
||||
export default function HomePage() {
|
||||
const { data, isPending, error } = useCases(true);
|
||||
@@ -30,9 +52,19 @@ export default function HomePage() {
|
||||
return { permits, levies };
|
||||
}, [data]);
|
||||
|
||||
const statusBars = useMemo(() => {
|
||||
const cases = data ?? [];
|
||||
const counts = STATUS_BARS.map((b) => ({
|
||||
...b,
|
||||
n: cases.filter((c) => b.match.includes(c.status)).length,
|
||||
}));
|
||||
const max = Math.max(1, ...counts.map((c) => c.n));
|
||||
return { counts, max };
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<AppShell>
|
||||
<section className="space-y-8">
|
||||
<section className="space-y-7">
|
||||
<header className="flex items-end justify-between gap-6 flex-wrap">
|
||||
<div className="space-y-1.5">
|
||||
<div className="text-[0.75rem] uppercase tracking-[0.12em] text-gold-deep">
|
||||
@@ -40,21 +72,53 @@ export default function HomePage() {
|
||||
</div>
|
||||
<h1 className="text-navy">עוזר משפטי</h1>
|
||||
<p className="text-ink-muted text-base max-w-2xl leading-relaxed">
|
||||
לוח בקרה לניהול תיקי ערר, ניתוח סגנון, וכתיבת החלטות לפי ארכיטקטורת
|
||||
12 הבלוקים.
|
||||
מבט-על על הוועדה — תיקים, אישורים ופעילות אחרונה במקום אחד.
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild className="bg-navy hover:bg-navy-soft text-parchment">
|
||||
<Link href="/cases/new">+ תיק חדש</Link>
|
||||
</Button>
|
||||
<div className="flex gap-2.5">
|
||||
<Button asChild className="bg-gold text-white hover:bg-gold-deep border-transparent">
|
||||
<Link href="/cases/new">+ תיק חדש</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline" className="border-rule text-navy">
|
||||
<Link href="/precedents">חיפוש בקורפוס</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="h-[2px] bg-gradient-to-l from-transparent via-gold to-transparent" />
|
||||
|
||||
{/* KPI row — mockup 04 .kpis (4-up, gold-washed "ממתינים לאישור") */}
|
||||
<KPICards cases={data} loading={isPending} />
|
||||
|
||||
<div className="grid gap-6 lg:grid-cols-[1fr_320px]">
|
||||
{/* two-column body — main flow + narrow gold gate rail (mockup 04 .cols) */}
|
||||
<div className="grid gap-6 lg:grid-cols-[1fr_360px]">
|
||||
<div className="space-y-6 min-w-0">
|
||||
{/* תיקים לפי סטטוס — horizontal bars (mockup 04) */}
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
<h2 className="text-navy text-lg mb-4">תיקים לפי סטטוס</h2>
|
||||
<ul className="space-y-3">
|
||||
{statusBars.counts.map((b) => (
|
||||
<li key={b.label} className="flex items-center gap-3">
|
||||
<span className="w-20 shrink-0 text-[0.82rem] text-ink-soft">
|
||||
{b.label}
|
||||
</span>
|
||||
<span className="flex-1 h-3.5 rounded-full bg-rule-soft overflow-hidden">
|
||||
<span
|
||||
className={`block h-full rounded-full ${b.fill} transition-[width] duration-500`}
|
||||
style={{ width: `${(b.n / statusBars.max) * 100}%` }}
|
||||
/>
|
||||
</span>
|
||||
<span className="w-9 shrink-0 text-end text-[0.82rem] font-semibold text-navy tabular-nums">
|
||||
{isPending ? "—" : b.n}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* live case tables kept in full (richer than the mockup's single feed) */}
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
<div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
|
||||
@@ -103,38 +167,39 @@ export default function HomePage() {
|
||||
</div>
|
||||
|
||||
<aside className="space-y-6 lg:sticky lg:top-6 lg:self-start">
|
||||
{approvals && approvals.total_pending > 0 ? (
|
||||
<Card className="bg-gold-wash border-gold/40 shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
<div className="flex items-center justify-between gap-3 mb-3">
|
||||
<h2 className="text-navy text-lg mb-0">מה ממתין להכרעתך</h2>
|
||||
<span className="text-2xl font-semibold text-gold-deep leading-none tabular-nums">
|
||||
{approvals.total_pending}
|
||||
</span>
|
||||
</div>
|
||||
<ul className="space-y-1.5 mb-4">
|
||||
{approvals.categories
|
||||
.filter((c) => c.count > 0)
|
||||
.map((c) => (
|
||||
<li
|
||||
key={c.key}
|
||||
className="flex items-center justify-between gap-2 text-[0.85rem] text-ink-soft"
|
||||
>
|
||||
<span>{c.label}</span>
|
||||
<span className="text-navy font-semibold tabular-nums">{c.count}</span>
|
||||
</li>
|
||||
))}
|
||||
{/* מה ממתין להכרעתך — gold gate card with dot+label+count rows (mockup 04 .gatecard) */}
|
||||
<Card className="bg-gold-wash border-gold/50 shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
<h2 className="text-navy text-lg mb-3">מה ממתין להכרעתך</h2>
|
||||
{approvals && approvals.categories.length > 0 ? (
|
||||
<ul className="mb-1">
|
||||
{approvals.categories.map((c) => (
|
||||
<li
|
||||
key={c.key}
|
||||
className="flex items-center gap-2.5 py-2.5 text-[0.88rem] text-ink-soft border-b border-rule-soft last:border-b-0"
|
||||
>
|
||||
<span
|
||||
className={`h-2.5 w-2.5 shrink-0 rounded-full ${SEVERITY_DOT[c.severity]}`}
|
||||
aria-hidden
|
||||
/>
|
||||
<span className="grow min-w-0">{c.label}</span>
|
||||
<span className="font-bold text-navy tabular-nums">{c.count}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button
|
||||
asChild
|
||||
size="sm"
|
||||
className="bg-gold text-white hover:bg-gold-deep border-transparent w-full"
|
||||
>
|
||||
<Link href="/approvals">למרכז האישורים ←</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : null}
|
||||
) : (
|
||||
<p className="text-[0.85rem] text-ink-muted mb-2">
|
||||
אין פריטים הממתינים להכרעתך.
|
||||
</p>
|
||||
)}
|
||||
<Link
|
||||
href="/approvals"
|
||||
className="inline-block mt-3 text-[0.85rem] font-semibold text-gold-deep hover:text-navy"
|
||||
>
|
||||
למרכז האישורים ←
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
|
||||
Reference in New Issue
Block a user