feat(case-ui): banner-A status rail + V2 segmented tabs (X17 #2)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 3s
Lint — undefined names / undefined-names (pull_request) Successful in 10s

Implements the approved X17 case-detail redesign foundation (mockups 18c "A" +
18e "V2"):

- New StatusRail component — the integrated status strip (current-phase chip,
  expected-outcome semantic tag, hearing/updated/sync meta inline, agents
  Popover, manual-changer Popover) over the 5-phase pipeline stepper. Lives
  INSIDE the parchment band (CaseHeader), so status is now visible on EVERY tab
  (supersedes the overview-only StatusHero / reverses the prior INV-IA1
  overview-only decision, deliberately).
- CaseHeader absorbs the rail and drops its separate hearing/updated/sync dl
  (those moved into the rail — no duplication).
- Tabs restyled to the V2 "segmented" look (each tab a pill, active = raised
  white card) with per-tab icons.
- Overview tab body is now just documents + agent-activity preview (status left
  the body).
- StatusHero deleted — its content moved wholesale into StatusRail, so no
  parallel status surface remains (G2).

Reuses the shared StatusChanger / StatusGuide / AgentStatusWidget verbatim
(G2). Design-gate: mockups 18c + 18e approved in Claude Design X17.
tsc --noEmit + eslint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-30 18:46:04 +00:00
parent b79c7bf161
commit 3f253269f6
4 changed files with 225 additions and 192 deletions

View File

@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
import Link from "next/link";
import { Badge } from "@/components/ui/badge";
import { StatusBadge } from "@/components/cases/status-badge";
import { SyncIndicator } from "@/components/cases/sync-indicator";
import { StatusRail } from "@/components/cases/status-rail";
import { CaseArchiveAction } from "@/components/cases/case-archive-action";
import { CreateRepoButton } from "@/components/cases/create-repo-button";
import {
@@ -10,7 +10,6 @@ import {
APPEAL_SUBTYPE_LABELS,
isBlamSubtype,
} from "@/lib/practice-area";
import { formatDate } from "@/lib/format-date";
import type { CaseDetail } from "@/lib/api/cases";
function partiesLine(data?: CaseDetail): string | null {
@@ -29,10 +28,12 @@ function partiesLine(data?: CaseDetail): string | null {
* the tab strip inside the band, anchored to its bottom edge.
*/
export function CaseHeader({
caseNumber,
data,
actions,
tabs,
}: {
caseNumber: string;
data?: CaseDetail;
actions?: ReactNode;
tabs?: ReactNode;
@@ -123,25 +124,13 @@ export function CaseHeader({
</div>
</div>
{/* metadata strip — hearing date / updated / sync */}
<dl className="grid grid-cols-2 gap-x-6 gap-y-1 text-sm shrink-0">
<dt className="text-ink-muted text-[0.72rem] uppercase tracking-wider">
תאריך דיון
</dt>
<dd className="text-ink-soft tabular-nums">{formatDate(data?.hearing_date)}</dd>
<dt className="text-ink-muted text-[0.72rem] uppercase tracking-wider">
עודכן
</dt>
<dd className="text-ink-soft tabular-nums">{formatDate(data?.updated_at)}</dd>
<dt className="text-ink-muted text-[0.72rem] uppercase tracking-wider">
סנכרון
</dt>
<dd><SyncIndicator caseNumber={data?.case_number} /></dd>
</dl>
</div>
{/* tab strip anchored to band bottom (mockup .tabs) */}
{tabs ? <div className="mt-5">{tabs}</div> : null}
{/* ★ integrated status rail — visible on every tab (banner A, X17) */}
<StatusRail caseNumber={caseNumber} data={data} />
{/* tab strip anchored to band bottom */}
{tabs ? <div className="mt-4">{tabs}</div> : null}
</div>
);
}