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

@@ -45,10 +45,10 @@ export default function CaseDetailPage({
? EXPECTED_OUTCOME_LABELS[data.expected_outcome] ?? data.expected_outcome
: null;
return (
<AppShell>
<section className="space-y-6">
{error ? (
if (error) {
return (
<AppShell>
<section className="space-y-6">
<Card className="bg-danger-bg border-danger/40">
<CardContent className="px-6 py-6 text-center space-y-3">
<p className="text-danger font-semibold">שגיאה בטעינת התיק</p>
@@ -58,130 +58,168 @@ export default function CaseDetailPage({
</Button>
</CardContent>
</Card>
</section>
</AppShell>
);
}
const tabsList = (
<TabsList
variant="line"
className="gap-6 h-auto p-0 rounded-none -mb-px"
>
{[
["overview", "סקירה"],
["arguments", "טיעונים"],
["decision", "ההחלטה"],
["drafts", "טיוטות והערות"],
["agents", "סוכנים"],
].map(([value, label]) => (
<TabsTrigger
key={value}
value={value}
className="flex-none rounded-none px-0 pb-3.5 pt-0 text-[0.92rem] font-medium text-ink-muted data-active:text-navy data-active:font-semibold data-active:after:bg-gold data-active:after:bottom-0"
>
{label}
</TabsTrigger>
))}
</TabsList>
);
const bandActions = (
<>
{data && <CaseEditDialog data={data} />}
<UploadSheet caseNumber={caseNumber} />
</>
);
return (
<AppShell>
<Tabs defaultValue="overview" dir="rtl">
{/* parchment band — header (title/chips/parties/actions) + tab strip */}
{isPending ? (
<div className="-mx-10 -mt-10 mb-2 bg-parchment border-b border-rule px-10 pt-6 pb-4 space-y-3">
<Skeleton className="h-4 w-40" />
<Skeleton className="h-8 w-64" />
<Skeleton className="h-6 w-96" />
</div>
) : (
<>
{isPending ? (
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5 space-y-3">
<Skeleton className="h-4 w-40" />
<Skeleton className="h-8 w-64" />
<Skeleton className="h-6 w-96" />
<CaseHeader data={data} actions={bandActions} tabs={tabsList} />
)}
{/* two-column wrap — main tab content (1fr) + rail (340px) */}
<div className="grid gap-6 lg:grid-cols-[1fr_340px] items-start mt-6">
<div className="min-w-0">
<TabsContent value="overview" className="mt-0 space-y-5">
<Card className="bg-surface border-rule shadow-sm overflow-hidden p-0">
<div className="px-5 py-3.5 border-b border-rule-soft bg-parchment text-[0.92rem] font-semibold text-navy">
סקירת התיק
</div>
<CardContent className="px-5 py-4 space-y-4">
<div>
<h3 className="text-navy text-[0.95rem] font-semibold mb-1.5">תוצאה צפויה</h3>
<p className="text-ink-soft text-sm leading-relaxed">
{expectedOutcomeLabel ?? "לא נקבעה תוצאה צפויה."}
</p>
</div>
<div className="pt-2 border-t border-rule-soft">
<dl className="grid grid-cols-2 gap-y-2 gap-x-6 text-sm">
<dt className="text-ink-muted">בעיבוד</dt>
<dd className="text-ink tabular-nums">
{data?.processing_count ?? 0}
</dd>
</dl>
</div>
{canStartWorkflow && (
<div className="pt-2 border-t border-rule-soft">
<Button
className="bg-gold-deep hover:bg-gold-deep/90 text-parchment"
disabled={startWorkflow.isPending}
onClick={() =>
startWorkflow.mutate(undefined, {
onSuccess: (res) =>
toast.success(
`תהליך הופעל — ${res.issue_identifier}`,
),
onError: (err) =>
toast.error(`שגיאה: ${err.message}`),
})
}
>
{startWorkflow.isPending ? (
<Loader2 className="w-4 h-4 animate-spin me-1.5" />
) : (
<Play className="w-4 h-4 me-1.5" />
)}
התחל תהליך
</Button>
</div>
)}
</CardContent>
</Card>
) : (
<CaseHeader data={data} />
)}
<div className="grid gap-6 lg:grid-cols-[1fr_280px]">
<DocumentsPanel data={data} />
{/* gold CTA — open the decision editor (mockup .cta) */}
<Button
asChild
className="w-full bg-gold text-white hover:bg-gold-deep border-transparent py-6 text-base font-semibold"
>
<Link href={`/cases/${caseNumber}/compose`}>
פתח עורך החלטה
</Link>
</Button>
</TabsContent>
<TabsContent value="arguments" className="mt-0">
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5">
<Tabs defaultValue="overview" dir="rtl">
<div className="flex items-center justify-between gap-3 mb-1 flex-wrap">
<TabsList className="bg-rule-soft/60">
<TabsTrigger value="overview">סקירה</TabsTrigger>
<TabsTrigger value="arguments">
טיעונים
</TabsTrigger>
<TabsTrigger value="decision">
ההחלטה
</TabsTrigger>
<TabsTrigger value="drafts">
טיוטות והערות
</TabsTrigger>
<TabsTrigger value="agents">
סוכנים
</TabsTrigger>
</TabsList>
<div className="flex items-center gap-2 flex-wrap">
<Button asChild className="bg-navy hover:bg-navy-soft text-parchment">
<Link href={`/cases/${caseNumber}/compose`}>
פתח בעורך ההחלטה
</Link>
</Button>
{data && <CaseEditDialog data={data} />}
<UploadSheet caseNumber={caseNumber} />
</div>
</div>
<TabsContent value="overview" className="mt-5 space-y-4">
<div>
<h3 className="text-navy text-base mb-2">תוצאה צפויה</h3>
<p className="text-ink-soft text-sm leading-relaxed">
{expectedOutcomeLabel ?? "לא נקבעה תוצאה צפויה."}
</p>
</div>
<div>
<h3 className="text-navy text-base mb-2">סיכום מהיר</h3>
<dl className="grid grid-cols-2 gap-y-2 gap-x-6 text-sm">
<dt className="text-ink-muted">בעיבוד</dt>
<dd className="text-ink tabular-nums">
{data?.processing_count ?? 0}
</dd>
</dl>
</div>
{canStartWorkflow && (
<div className="pt-2 border-t border-rule">
<Button
className="bg-gold-deep hover:bg-gold-deep/90 text-parchment"
disabled={startWorkflow.isPending}
onClick={() =>
startWorkflow.mutate(undefined, {
onSuccess: (res) =>
toast.success(
`תהליך הופעל — ${res.issue_identifier}`,
),
onError: (err) =>
toast.error(`שגיאה: ${err.message}`),
})
}
>
{startWorkflow.isPending ? (
<Loader2 className="w-4 h-4 animate-spin me-1.5" />
) : (
<Play className="w-4 h-4 me-1.5" />
)}
התחל תהליך
</Button>
</div>
)}
<DocumentsPanel data={data} />
</TabsContent>
<TabsContent value="arguments" className="mt-5">
<LegalArgumentsPanel caseNumber={caseNumber} />
</TabsContent>
<TabsContent value="decision" className="mt-5">
<DecisionBlocksPanel caseNumber={caseNumber} />
</TabsContent>
<TabsContent value="drafts" className="mt-5">
<DraftsPanel
caseNumber={caseNumber}
status={data?.status}
/>
</TabsContent>
<TabsContent value="agents" className="mt-5">
<AgentActivityFeed caseNumber={caseNumber} />
</TabsContent>
</Tabs>
<LegalArgumentsPanel caseNumber={caseNumber} />
</CardContent>
</Card>
</TabsContent>
<Card className="bg-surface border-rule shadow-sm h-fit">
<CardContent className="px-6 py-5 space-y-5">
<AgentStatusWidget caseNumber={caseNumber} />
<h2 className="text-navy text-base mb-4">שלב בתהליך</h2>
<WorkflowTimeline status={data?.status} />
<StatusChanger caseNumber={caseNumber} currentStatus={data?.status} />
<StatusGuide />
<TabsContent value="decision" className="mt-0">
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5">
<DecisionBlocksPanel caseNumber={caseNumber} />
</CardContent>
</Card>
</div>
</>
)}
</section>
</TabsContent>
<TabsContent value="drafts" className="mt-0">
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5">
<DraftsPanel caseNumber={caseNumber} status={data?.status} />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="agents" className="mt-0">
<Card className="bg-surface border-rule shadow-sm">
<CardContent className="px-6 py-5">
<AgentActivityFeed caseNumber={caseNumber} />
</CardContent>
</Card>
</TabsContent>
</div>
{/* rail — status timeline + status controls (mockup .rail) */}
<div className="space-y-5">
<Card className="bg-surface border-rule shadow-sm overflow-hidden p-0 h-fit">
<div className="px-5 py-3.5 border-b border-rule-soft bg-parchment text-[0.92rem] font-semibold text-navy">
סטטוס התיק
</div>
<CardContent className="px-5 py-4 space-y-4">
<AgentStatusWidget caseNumber={caseNumber} />
<WorkflowTimeline status={data?.status} />
<StatusChanger caseNumber={caseNumber} currentStatus={data?.status} />
<StatusGuide />
</CardContent>
</Card>
</div>
</div>
</Tabs>
</AppShell>
);
}