Merge pull request 'refactor(cases): צמצום תפריט-סטטוס 17→10 + מקור-אמת יחיד (UI-B1/G2)' (#287) from worktree-status-trim into main
This commit was merged in pull request #287.
This commit is contained in:
@@ -21,17 +21,10 @@ import { DOC_TYPE_LABELS, type DocType } from "@/lib/doc-types";
|
||||
// ── Case-status → Hebrew label + tone (mockup 03 status chip) ────────────────
|
||||
const STATUS_CHIP: Record<string, { label: string; cls: string }> = {
|
||||
new: { label: "חדש", cls: "bg-rule-soft text-ink-muted border-rule" },
|
||||
uploading: { label: "בהעלאה", cls: "bg-info-bg text-info border-info/30" },
|
||||
processing: { label: "בעיבוד", cls: "bg-info-bg text-info border-info/30" },
|
||||
documents_ready: { label: "מסמכים מוכנים", cls: "bg-info-bg text-info border-info/30" },
|
||||
analyst_verified: { label: "אומת ע״י אנליסט", cls: "bg-info-bg text-info border-info/30" },
|
||||
research_complete: { label: "מחקר הושלם", cls: "bg-info-bg text-info border-info/30" },
|
||||
outcome_set: { label: "תוצאה נקבעה", cls: "bg-info-bg text-info border-info/30" },
|
||||
brainstorming: { label: "סיעור-מוחות", cls: "bg-info-bg text-info border-info/30" },
|
||||
direction_approved: { label: "כיוון אושר", cls: "bg-info-bg text-info border-info/30" },
|
||||
analysis_enriched: { label: "ניתוח הועשר", cls: "bg-info-bg text-info border-info/30" },
|
||||
ready_for_writing: { label: "מוכן לכתיבה", cls: "bg-gold-wash text-gold-deep border-gold/40" },
|
||||
drafting: { label: "בעריכה", cls: "bg-info-bg text-info border-info/30" },
|
||||
qa_review: { label: "בדיקת-איכות", cls: "bg-gold-wash text-gold-deep border-gold/40" },
|
||||
drafted: { label: "טיוטה", cls: "bg-gold-wash text-gold-deep border-gold/40" },
|
||||
exported: { label: "יוצא", cls: "bg-success-bg text-success border-success/40" },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import type { Case } from "@/lib/api/cases";
|
||||
import { phaseOf } from "@/lib/api/case-status";
|
||||
|
||||
type Bucket = {
|
||||
label: string;
|
||||
@@ -17,15 +18,14 @@ const TONE_STYLES: Record<Bucket["tone"], string> = {
|
||||
|
||||
function bucketize(cases: Case[] | undefined): Bucket[] {
|
||||
const c = cases ?? [];
|
||||
const inProgress = c.filter((x) =>
|
||||
["processing", "documents_ready", "analyst_verified", "research_complete", "outcome_set", "brainstorming", "direction_approved", "analysis_enriched", "ready_for_writing"].includes(x.status),
|
||||
).length;
|
||||
const drafting = c.filter((x) =>
|
||||
["drafting", "qa_review", "drafted"].includes(x.status),
|
||||
).length;
|
||||
const done = c.filter((x) =>
|
||||
["exported", "reviewed", "final"].includes(x.status),
|
||||
).length;
|
||||
/* Buckets derive from the SSoT phases: "בהכנה" = everything from processing
|
||||
* through direction-approval (intake-after-new + prep + thinking). */
|
||||
const inProgress = c.filter((x) => {
|
||||
const p = phaseOf(x.status);
|
||||
return x.status === "processing" || p === "prep" || p === "thinking";
|
||||
}).length;
|
||||
const drafting = c.filter((x) => phaseOf(x.status) === "writing").length;
|
||||
const done = c.filter((x) => phaseOf(x.status) === "done").length;
|
||||
|
||||
return [
|
||||
{ label: "סה״כ תיקי ערר", caption: "בכל הסטטוסים", value: c.length, tone: "navy" },
|
||||
|
||||
@@ -1,105 +1,48 @@
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
FilePlus2, Upload, Loader2, FileCheck, Target,
|
||||
Lightbulb, Compass, PenLine, SearchCheck, FileText,
|
||||
FileOutput, CheckCircle2, Award, ShieldCheck, BookOpen,
|
||||
Microscope, PlayCircle, Hammer, AlertTriangle,
|
||||
FilePlus2, Loader2, FileCheck, Target,
|
||||
Compass, SearchCheck, FileText,
|
||||
FileOutput, CheckCircle2, Award,
|
||||
} from "lucide-react";
|
||||
import type { CaseStatus } from "@/lib/api/cases";
|
||||
import {
|
||||
STATUS_LABELS, STATUS_DESCRIPTIONS, statusLabel, type CaseStatus,
|
||||
} from "@/lib/api/case-status";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
const STATUS_LABELS: Record<CaseStatus, string> = {
|
||||
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: "סופי",
|
||||
};
|
||||
/* Labels + descriptions come from the SSoT (@/lib/api/case-status).
|
||||
* Icons + color tones are view-layer concerns and live here, keyed off the
|
||||
* same 10 core statuses. */
|
||||
|
||||
const STATUS_ICONS: Record<CaseStatus, LucideIcon> = {
|
||||
new: FilePlus2,
|
||||
in_progress: Hammer,
|
||||
uploading: Upload,
|
||||
processing: Loader2,
|
||||
documents_ready: FileCheck,
|
||||
analyst_verified: ShieldCheck,
|
||||
research_complete: BookOpen,
|
||||
outcome_set: Target,
|
||||
brainstorming: Lightbulb,
|
||||
direction_approved: Compass,
|
||||
analysis_enriched: Microscope,
|
||||
ready_for_writing: PlayCircle,
|
||||
drafting: PenLine,
|
||||
qa_review: SearchCheck,
|
||||
qa_failed: AlertTriangle,
|
||||
drafted: FileText,
|
||||
exported: FileOutput,
|
||||
reviewed: CheckCircle2,
|
||||
final: Award,
|
||||
};
|
||||
|
||||
const STATUS_DESCRIPTIONS: Record<CaseStatus, string> = {
|
||||
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: "ההחלטה יוצאה לקובץ DOCX",
|
||||
reviewed: "ההחלטה נבדקה ע\"י היו\"ר",
|
||||
final: "החלטה סופית — מוכנה להגשה",
|
||||
};
|
||||
|
||||
/* Status color groups:
|
||||
* intake → new, uploading, processing (muted parchment)
|
||||
* prep → documents_ready, outcome_set (info blue)
|
||||
* thinking→ brainstorming, direction_approved (gold)
|
||||
* writing → drafting, qa_review, drafted (warn amber)
|
||||
* done → exported, reviewed, final (success green) */
|
||||
* intake → new, processing (muted parchment / info)
|
||||
* prep → documents_ready (info blue)
|
||||
* thinking→ outcome_set, direction_approved (gold)
|
||||
* writing → qa_review, drafted (warn amber)
|
||||
* done → exported, reviewed, final (success green) */
|
||||
const STATUS_TONE: Record<CaseStatus, string> = {
|
||||
new: "bg-rule-soft text-ink-muted border-rule",
|
||||
in_progress: "bg-warn-bg text-warn border-warn/40",
|
||||
uploading: "bg-rule-soft text-ink-muted border-rule",
|
||||
processing: "bg-info-bg text-info border-info/30",
|
||||
documents_ready: "bg-info-bg text-info border-info/40",
|
||||
analyst_verified: "bg-info-bg text-info border-info/40",
|
||||
research_complete:"bg-info-bg text-info border-info/40",
|
||||
outcome_set: "bg-info-bg text-info border-info/40",
|
||||
brainstorming: "bg-gold-wash text-gold-deep border-gold/40",
|
||||
new: "bg-rule-soft text-ink-muted border-rule",
|
||||
processing: "bg-info-bg text-info border-info/30",
|
||||
documents_ready: "bg-info-bg text-info border-info/40",
|
||||
outcome_set: "bg-gold-wash text-gold-deep border-gold/40",
|
||||
direction_approved:"bg-gold-wash text-gold-deep border-gold/50",
|
||||
analysis_enriched:"bg-gold-wash text-gold-deep border-gold/50",
|
||||
ready_for_writing:"bg-gold-wash text-gold-deep border-gold/50",
|
||||
drafting: "bg-warn-bg text-warn border-warn/40",
|
||||
qa_review: "bg-warn-bg text-warn border-warn/40",
|
||||
qa_failed: "bg-danger-bg text-danger border-danger/40",
|
||||
drafted: "bg-warn-bg text-warn border-warn/50",
|
||||
exported: "bg-success-bg text-success border-success/40",
|
||||
reviewed: "bg-success-bg text-success border-success/50",
|
||||
final: "bg-success-bg text-success border-success/60 font-semibold",
|
||||
qa_review: "bg-warn-bg text-warn border-warn/40",
|
||||
drafted: "bg-warn-bg text-warn border-warn/50",
|
||||
exported: "bg-success-bg text-success border-success/40",
|
||||
reviewed: "bg-success-bg text-success border-success/50",
|
||||
final: "bg-success-bg text-success border-success/60 font-semibold",
|
||||
};
|
||||
|
||||
export function StatusBadge({ status }: { status: CaseStatus }) {
|
||||
@@ -110,7 +53,7 @@ export function StatusBadge({ status }: { status: CaseStatus }) {
|
||||
className={`rounded-full px-2.5 py-0.5 text-[0.72rem] font-medium inline-flex items-center gap-1 ${STATUS_TONE[status] ?? ""}`}
|
||||
>
|
||||
{Icon && <Icon className="w-3 h-3 shrink-0" />}
|
||||
{STATUS_LABELS[status] ?? status}
|
||||
{statusLabel(status)}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,21 +7,16 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { STATUS_LABELS, STATUS_ICONS } from "@/components/cases/status-badge";
|
||||
import { useUpdateCase, type CaseStatus } from "@/lib/api/cases";
|
||||
import { useUpdateCase } from "@/lib/api/cases";
|
||||
import { CASE_STATUSES, type CaseStatus } from "@/lib/api/case-status";
|
||||
|
||||
/*
|
||||
* Dropdown for manually overriding the case status — skip a step
|
||||
* or revert to an earlier stage. Calls PUT /api/cases/:caseNumber
|
||||
* with { status: newValue }.
|
||||
* with { status: newValue }. The option list is the SSoT lifecycle.
|
||||
*/
|
||||
|
||||
const ALL_STATUSES: CaseStatus[] = [
|
||||
"new", "uploading", "processing",
|
||||
"documents_ready", "analyst_verified", "research_complete", "outcome_set",
|
||||
"brainstorming", "direction_approved", "analysis_enriched", "ready_for_writing",
|
||||
"drafting", "qa_review", "drafted",
|
||||
"exported", "reviewed", "final",
|
||||
];
|
||||
const ALL_STATUSES: readonly CaseStatus[] = CASE_STATUSES;
|
||||
|
||||
export function StatusChanger({
|
||||
caseNumber,
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import type { Case, CaseStatus } from "@/lib/api/cases";
|
||||
import type { Case } from "@/lib/api/cases";
|
||||
import { phaseOf, type PhaseKey } from "@/lib/api/case-status";
|
||||
import { STATUS_LABELS } from "@/components/cases/status-badge";
|
||||
|
||||
/*
|
||||
* Conic-gradient donut — ported from legal-ai/web/static/index.html renderHero().
|
||||
* Kept deliberately dependency-free (no D3/recharts) — a single background-image.
|
||||
* Five status groups map onto the navy/gold/info/warn/success palette.
|
||||
* Five status groups (= the SSoT phases) map onto navy/gold/info/warn/success.
|
||||
*/
|
||||
|
||||
type GroupKey = "intake" | "prep" | "thinking" | "writing" | "done";
|
||||
|
||||
const GROUP_OF: Record<CaseStatus, GroupKey> = {
|
||||
new: "intake", in_progress: "intake", uploading: "intake", processing: "intake",
|
||||
documents_ready: "prep", analyst_verified: "prep", research_complete: "prep", outcome_set: "prep",
|
||||
brainstorming: "thinking", direction_approved: "thinking", analysis_enriched: "thinking", ready_for_writing: "thinking",
|
||||
drafting: "writing", qa_review: "writing", qa_failed: "writing", drafted: "writing",
|
||||
exported: "done", reviewed: "done", final: "done",
|
||||
};
|
||||
type GroupKey = PhaseKey;
|
||||
|
||||
const GROUP_META: Record<GroupKey, { label: string; color: string }> = {
|
||||
intake: { label: "חדש / בעיבוד", color: "var(--color-ink-muted)" },
|
||||
@@ -32,7 +25,7 @@ export function StatusDonut({ cases }: { cases?: Case[] }) {
|
||||
intake: 0, prep: 0, thinking: 0, writing: 0, done: 0,
|
||||
};
|
||||
(cases ?? []).forEach((c) => {
|
||||
const g = GROUP_OF[c.status];
|
||||
const g = phaseOf(c.status);
|
||||
if (g) counts[g] += 1;
|
||||
});
|
||||
const total = Object.values(counts).reduce((a, b) => a + b, 0);
|
||||
|
||||
@@ -2,28 +2,16 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
import type { CaseStatus } from "@/lib/api/cases";
|
||||
import { PHASES as PHASE_GROUPS } from "@/lib/api/case-status";
|
||||
import { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS, STATUS_TONE } from "@/components/cases/status-badge";
|
||||
|
||||
/*
|
||||
* Collapsible guide showing all 13 statuses grouped by phase,
|
||||
* Collapsible guide showing the core statuses grouped by phase,
|
||||
* each with its icon, Hebrew label, color badge, and description.
|
||||
* Phases come from the SSoT (@/lib/api/case-status).
|
||||
* Intended to sit below the WorkflowTimeline in the case sidebar.
|
||||
*/
|
||||
|
||||
type PhaseGroup = {
|
||||
label: string;
|
||||
statuses: CaseStatus[];
|
||||
};
|
||||
|
||||
const PHASE_GROUPS: PhaseGroup[] = [
|
||||
{ label: "קליטה ועיבוד", statuses: ["new", "uploading", "processing"] },
|
||||
{ label: "הכנת תיק", statuses: ["documents_ready", "analyst_verified", "research_complete", "outcome_set"] },
|
||||
{ label: "ניתוח וכיוון", statuses: ["brainstorming", "direction_approved", "analysis_enriched", "ready_for_writing"] },
|
||||
{ label: "כתיבת טיוטה", statuses: ["drafting", "qa_review", "drafted"] },
|
||||
{ label: "סגירה", statuses: ["exported", "reviewed", "final"] },
|
||||
];
|
||||
|
||||
export function StatusGuide() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { CaseStatus } from "@/lib/api/cases";
|
||||
import { PHASES, type CaseStatus, type PhaseKey } from "@/lib/api/case-status";
|
||||
import { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS } from "@/components/cases/status-badge";
|
||||
import {
|
||||
FolderInput, ClipboardList, Brain, PenLine, CheckCircle2,
|
||||
@@ -8,27 +8,19 @@ import {
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
/*
|
||||
* Vertical RTL workflow timeline showing the 13-status case pipeline.
|
||||
* Groups the raw statuses into the 5 visual phases used across the app
|
||||
* (intake → prep → thinking → writing → done) so the user sees
|
||||
* "where am I in the process" rather than 13 micro-steps.
|
||||
* Vertical RTL workflow timeline. Phases + their statuses come from the SSoT
|
||||
* (@/lib/api/case-status); only the per-phase icon is a view-layer concern and
|
||||
* stays here. The user sees "where am I in the process" rather than micro-steps.
|
||||
*/
|
||||
|
||||
type Phase = {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: LucideIcon;
|
||||
statuses: CaseStatus[];
|
||||
const PHASE_ICONS: Record<PhaseKey, LucideIcon> = {
|
||||
intake: FolderInput,
|
||||
prep: ClipboardList,
|
||||
thinking: Brain,
|
||||
writing: PenLine,
|
||||
done: CheckCircle2,
|
||||
};
|
||||
|
||||
const PHASES: Phase[] = [
|
||||
{ key: "intake", label: "קליטה ועיבוד", icon: FolderInput, statuses: ["new", "uploading", "processing"] },
|
||||
{ key: "prep", label: "הכנת תיק", icon: ClipboardList, statuses: ["documents_ready", "analyst_verified", "research_complete", "outcome_set"] },
|
||||
{ key: "thinking", label: "ניתוח וכיוון", icon: Brain, statuses: ["brainstorming", "direction_approved", "analysis_enriched", "ready_for_writing"] },
|
||||
{ key: "writing", label: "כתיבת טיוטה", icon: PenLine, statuses: ["drafting", "qa_review", "drafted"] },
|
||||
{ key: "done", label: "סגירה", icon: CheckCircle2, statuses: ["exported", "reviewed", "final"] },
|
||||
];
|
||||
|
||||
function phaseIndexOf(status?: CaseStatus): number {
|
||||
if (!status) return -1;
|
||||
return PHASES.findIndex((p) => p.statuses.includes(status));
|
||||
@@ -61,7 +53,7 @@ export function WorkflowTimeline({ status }: { status?: CaseStatus }) {
|
||||
: state === "current" ? "text-gold-deep"
|
||||
: "text-ink-muted/50";
|
||||
|
||||
const PhaseIcon = phase.icon;
|
||||
const PhaseIcon = PHASE_ICONS[phase.key];
|
||||
const isLast = i === PHASES.length - 1;
|
||||
|
||||
return (
|
||||
|
||||
103
web-ui/src/lib/api/case-status.ts
Normal file
103
web-ui/src/lib/api/case-status.ts
Normal 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: "החלטה סופית — מוכנה להגשה",
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user