Merge pull request 'refactor(cases): צמצום תפריט-סטטוס 17→10 + מקור-אמת יחיד (UI-B1/G2)' (#287) from worktree-status-trim into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m29s
G12 Leak-Guard / leak-guard (push) Successful in 4s
Lint — undefined names / undefined-names (push) Successful in 10s

This commit was merged in pull request #287.
This commit is contained in:
2026-06-17 10:15:41 +00:00
16 changed files with 316 additions and 190 deletions

View File

@@ -0,0 +1,103 @@
/**
* Single source of truth for the case-status lifecycle (UI-B1 / G2).
*
* The 17-status manual menu was trimmed to the **10 core statuses** that the
* pipeline actually sets or that gate real logic. Decorative mid-stage markers
* (uploading, analyst_verified, research_complete, brainstorming,
* analysis_enriched, ready_for_writing, drafting) plus the legacy/dead
* `in_progress` and `qa_failed` were removed — no pipeline code ever set them.
*
* Every status consumer (badge, changer, timeline, guide, donut, KPI cards,
* compose chip) imports the list / labels / phases from here instead of
* re-declaring its own array. Keep this file in sync with the backend
* STATUS_ORDER in `mcp-server/src/legal_mcp/tools/cases.py`.
*/
/** Ordered lifecycle — also the order shown in the manual status dropdown. */
export const CASE_STATUSES = [
"new",
"processing",
"documents_ready",
"outcome_set",
"direction_approved",
"qa_review",
"drafted",
"exported",
"reviewed",
"final",
] as const;
export type CaseStatus = (typeof CASE_STATUSES)[number];
export type PhaseKey = "intake" | "prep" | "thinking" | "writing" | "done";
/** The 5 visual phases the lifecycle collapses into across the app. */
export const PHASES: { key: PhaseKey; label: string; statuses: CaseStatus[] }[] = [
{ key: "intake", label: "קליטה ועיבוד", statuses: ["new", "processing"] },
{ key: "prep", label: "הכנת תיק", statuses: ["documents_ready"] },
{ key: "thinking", label: "ניתוח וכיוון", statuses: ["outcome_set", "direction_approved"] },
{ key: "writing", label: "כתיבת טיוטה", statuses: ["qa_review", "drafted"] },
{ key: "done", label: "סגירה", statuses: ["exported", "reviewed", "final"] },
];
/** Which phase a status belongs to (undefined for unknown/legacy values). */
export function phaseOf(status?: CaseStatus | string): PhaseKey | undefined {
if (!status) return undefined;
return PHASES.find((p) => (p.statuses as string[]).includes(status))?.key;
}
export const STATUS_LABELS: Record<CaseStatus, string> = {
new: "חדש",
processing: "בעיבוד",
documents_ready: "מסמכים מוכנים",
outcome_set: "תוצאה נקבעה",
direction_approved: "כיוון אושר",
qa_review: "בדיקת איכות",
drafted: "טיוטה",
exported: "יוצא",
reviewed: "נבדק",
final: "סופי",
};
/**
* Hebrew labels for the removed/legacy statuses — display-only fallback so a
* row that hasn't been migrated yet (or arrives from an old client) never
* renders a raw English slug as a label. These are NOT selectable statuses.
*/
const LEGACY_STATUS_LABELS: Record<string, string> = {
in_progress: "בעבודה",
uploading: "מעלה",
analyst_verified: "ניתוח אומת",
research_complete: "מחקר הושלם",
brainstorming: "סיעור מוחות",
analysis_enriched: "ניתוח הועמק",
ready_for_writing: "מוכן לכתיבה",
drafting: "בכתיבה",
qa_failed: "בדיקת איכות נכשלה",
};
/**
* Always-Hebrew label for any status string. Use this everywhere a status is
* rendered as a label so an unknown/legacy value never leaks an English slug.
*/
export function statusLabel(status?: string): string {
if (!status) return "";
return (
STATUS_LABELS[status as CaseStatus] ??
LEGACY_STATUS_LABELS[status] ??
"לא ידוע"
);
}
export const STATUS_DESCRIPTIONS: Record<CaseStatus, string> = {
new: "התיק נוצר וממתין להעלאת מסמכים",
processing: "המערכת מעבדת ומנתחת את המסמכים",
documents_ready: "כל המסמכים עובדו ומוכנים לעבודה",
outcome_set: "נקבעה תוצאה צפויה לערר",
direction_approved: "כיוון ההחלטה אושר — בהעמקת ניתוח וכתיבה",
qa_review: "הטיוטה בבדיקת איכות אוטומטית",
drafted: "טיוטה מוכנה לעיון",
exported: "ההחלטה יוצאה לקובץ DOCX",
reviewed: 'ההחלטה נבדקה ע"י היו"ר',
final: "החלטה סופית — מוכנה להגשה",
};

View File

@@ -13,26 +13,11 @@ import { apiRequest } from "./client";
import type { CaseCreateInput, CaseUpdateInput } from "@/lib/schemas/case";
import type { PracticeArea, AppealSubtype } from "@/lib/practice-area";
export type CaseStatus =
| "new"
| "in_progress"
| "uploading"
| "processing"
| "documents_ready"
| "analyst_verified"
| "research_complete"
| "outcome_set"
| "brainstorming"
| "direction_approved"
| "analysis_enriched"
| "ready_for_writing"
| "drafting"
| "qa_review"
| "qa_failed"
| "drafted"
| "exported"
| "reviewed"
| "final";
/* CaseStatus + the status list/labels/phases are defined once in ./case-status
* (single source of truth, UI-B1). Re-exported here so existing
* `import { CaseStatus } from "@/lib/api/cases"` sites keep working. */
export type { CaseStatus } from "./case-status";
import type { CaseStatus } from "./case-status";
export type Case = {
case_number: string;