diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index dddf5ce..24ed570 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -908,16 +908,71 @@ "priority": "high", "subtasks": [], "updatedAt": "2026-04-11T19:20:56.040Z" + }, + { + "id": 92, + "title": "הסרת אפליקציית Flask הישנה מ-Coolify", + "description": "ארכיון והסרה של אפליקציית Flask הישנה מ-Coolify, וכיוון DNS כך ש-legal-ai.nautilus.marcusgroup.org יצביע על אפליקציית Next.js", + "details": "## פסאודו-קוד:\n```\n1. גיבוי הגדרות Flask מ-Coolify לפני מחיקה\n2. ב-Coolify dashboard:\n - מצא את הקונטיינר legal-ai-flask (או שם דומה)\n - עצור את הקונטיינר\n - צור snapshot או ארכיון של ההגדרות\n - מחק את הקונטיינר והסרוויס\n3. ב-DNS (Cloudflare/Coolify proxy):\n - שנה את legal-ai.nautilus.marcusgroup.org\n - הפנה ל-IP/service של legal-ai-next (Next.js app)\n4. ב-Next.js app (Coolify):\n - הוסף domain alias: legal-ai.nautilus.marcusgroup.org\n - עדכן SSL certificate\n```\n\n## קבצים מושפעים:\n- Coolify dashboard settings\n- DNS records (Cloudflare או ספק אחר)\n- Coolify proxy/Traefik configuration\n\n## הערות:\n- **אין שינויים בקוד** - רק הגדרות תשתית\n- ודא שה-Next.js app עובד עם שני הדומיינים במקביל לפני הסרת Flask\n- שמור לוגים מ-Flask לפני מחיקה למקרה של rollback", + "testStrategy": "## בדיקות:\n1. **לפני הסרה**: ודא ש-legal-ai-next.nautilus.marcusgroup.org עובד תקין\n2. **אחרי שינוי DNS**: \n - `curl -I https://legal-ai.nautilus.marcusgroup.org` - צריך להחזיר 200\n - בדוק SSL certificate תקין\n3. **בדיקת UI**: \n - פתח את legal-ai.nautilus.marcusgroup.org בדפדפן\n - ודא שזה אותו UI כמו legal-ai-next\n4. **בדיקת API**: \n - `curl https://legal-ai.nautilus.marcusgroup.org/api/cases`\n - ודא שמחזיר נתונים", + "priority": "high", + "dependencies": [], + "status": "pending", + "subtasks": [] + }, + { + "id": 93, + "title": "עדכון סטטוסים ב-WorkflowTimeline וב-status-badge", + "description": "עדכון רשימת הסטטוסים בממשק לפי ה-pipeline החדש: new → proofread → documents_ready → analyst_verified → research_complete → outcome_set → direction_approved → drafted → qa_passed → exported, כולל qa_failed ו-blocked", + "details": "## קבצים לעדכון:\n1. `web-ui/src/lib/api/cases.ts` - עדכון type CaseStatus\n2. `web-ui/src/components/cases/status-badge.tsx` - תוויות ועיצוב\n3. `web-ui/src/components/cases/workflow-timeline.tsx` - שלבי pipeline\n\n## פסאודו-קוד:\n\n### 1. cases.ts - עדכון הטיפוס:\n```typescript\nexport type CaseStatus =\n | \"new\"\n | \"proofread\"\n | \"documents_ready\"\n | \"analyst_verified\"\n | \"research_complete\"\n | \"outcome_set\"\n | \"direction_approved\"\n | \"drafted\"\n | \"qa_passed\"\n | \"exported\"\n | \"qa_failed\"\n | \"blocked\";\n```\n\n### 2. status-badge.tsx - תוויות עבריות וצבעים:\n```typescript\nconst STATUS_LABELS: Record = {\n new: \"חדש\",\n proofread: \"הוגה\",\n documents_ready: \"מסמכים מוכנים\",\n analyst_verified: \"אומת ע״י אנליסט\",\n research_complete: \"מחקר הושלם\",\n outcome_set: \"תוצאה נקבעה\",\n direction_approved: \"כיוון אושר\",\n drafted: \"טיוטה\",\n qa_passed: \"עבר QA\",\n exported: \"יוצא\",\n qa_failed: \"נכשל QA\",\n blocked: \"חסום\",\n};\n\nconst STATUS_TONE: Record = {\n new: \"bg-rule-soft text-ink-muted border-rule\",\n proofread: \"bg-info-bg text-info border-info/30\",\n documents_ready: \"bg-info-bg text-info border-info/40\",\n analyst_verified: \"bg-info-bg text-info border-info/50\",\n research_complete: \"bg-gold-wash text-gold-deep border-gold/40\",\n outcome_set: \"bg-gold-wash text-gold-deep border-gold/50\",\n direction_approved: \"bg-gold-wash text-gold-deep border-gold/60\",\n drafted: \"bg-warn-bg text-warn border-warn/40\",\n qa_passed: \"bg-success-bg text-success border-success/40\",\n exported: \"bg-success-bg text-success border-success/60\",\n qa_failed: \"bg-danger-bg text-danger border-danger/40\",\n blocked: \"bg-danger-bg text-danger border-danger/50\",\n};\n```\n\n### 3. workflow-timeline.tsx - קבוצות שלבים חדשות:\n```typescript\nconst PHASES: Phase[] = [\n { key: \"intake\", label: \"קליטה ועיבוד\", statuses: [\"new\", \"proofread\", \"documents_ready\"] },\n { key: \"analysis\", label: \"ניתוח\", statuses: [\"analyst_verified\", \"research_complete\"] },\n { key: \"direction\", label: \"קביעת כיוון\", statuses: [\"outcome_set\", \"direction_approved\"] },\n { key: \"writing\", label: \"כתיבה וביקורת\", statuses: [\"drafted\", \"qa_passed\"] },\n { key: \"done\", label: \"סגירה\", statuses: [\"exported\"] },\n];\n\n// טיפול בסטטוסי שגיאה (qa_failed, blocked) - הצגה מיוחדת\nif (status === \"qa_failed\" || status === \"blocked\") {\n // הצג באדום עם אייקון אזהרה\n}\n```", + "testStrategy": "## בדיקות:\n1. **Unit Tests** (אם קיימים):\n - ודא שכל הסטטוסים מופו נכון\n - בדוק שאין סטטוס חסר ב-STATUS_LABELS ו-STATUS_TONE\n\n2. **Visual Testing**:\n - צור/ערוך תיק ידנית ב-DB לכל סטטוס\n - ודא שהתווית מוצגת בעברית נכונה\n - ודא שהצבע מתאים (כחול לעיבוד, זהב לניתוח, ירוק להצלחה, אדום לשגיאה)\n\n3. **WorkflowTimeline**:\n - ודא שהשלב הנוכחי מודגש בצהוב\n - ודא ששלבים שהושלמו מסומנים בירוק\n - ודא שסטטוסי שגיאה (qa_failed, blocked) מוצגים עם אינדיקציה ויזואלית מיוחדת", + "priority": "high", + "dependencies": [], + "status": "pending", + "subtasks": [] + }, + { + "id": 94, + "title": "דף/קומפוננטה להצגת כל הסטטוסים עם הסברים", + "description": "יצירת דף /statuses או מודל עזרה שמסביר את כל הסטטוסים האפשריים - מה כל סטטוס אומר, איזה agent קובע אותו, ומה קורה אחר כך", + "details": "## אפשרויות מימוש:\n\n### אפשרות A: Popover tooltip בתוך WorkflowTimeline (מומלץ)\n```typescript\n// web-ui/src/components/cases/workflow-timeline.tsx\n// הוסף אייקון (?) ליד הכותרת שפותח popover\n\nconst STATUS_INFO: Record = {\n new: {\n description: \"תיק נוצר, ממתין להעלאת מסמכים\",\n agent: \"משתמש\",\n nextStep: \"העלאת מסמכים → proofread\"\n },\n proofread: {\n description: \"מסמכים הועלו, עוברים הגהה אוטומטית\",\n agent: \"Proofread Agent\",\n nextStep: \"הגהה הושלמה → documents_ready\"\n },\n documents_ready: {\n description: \"מסמכים מוכנים לניתוח\",\n agent: \"Document Processor\",\n nextStep: \"בדיקת אנליסט → analyst_verified\"\n },\n analyst_verified: {\n description: \"אנליסט אימת את חילוץ הטענות\",\n agent: \"Analyst Agent\",\n nextStep: \"מחקר → research_complete\"\n },\n research_complete: {\n description: \"מחקר משפטי הושלם, פסיקה זוהתה\",\n agent: \"Research Agent\",\n nextStep: \"קביעת תוצאה → outcome_set\"\n },\n outcome_set: {\n description: \"דפנה קבעה את התוצאה (דחייה/קבלה)\",\n agent: \"משתמש (דפנה)\",\n nextStep: \"אישור כיוון → direction_approved\"\n },\n direction_approved: {\n description: \"כיוון ההחלטה אושר, מוכן לכתיבה\",\n agent: \"משתמש\",\n nextStep: \"כתיבה → drafted\"\n },\n drafted: {\n description: \"טיוטת החלטה נכתבה\",\n agent: \"Writing Agent\",\n nextStep: \"בדיקת QA → qa_passed\"\n },\n qa_passed: {\n description: \"טיוטה עברה בדיקת איכות\",\n agent: \"QA Agent\",\n nextStep: \"ייצוא → exported\"\n },\n exported: {\n description: \"ההחלטה יוצאה כ-DOCX\",\n agent: \"Export Service\",\n nextStep: \"הושלם\"\n },\n qa_failed: {\n description: \"טיוטה נכשלה בבדיקת QA\",\n agent: \"QA Agent\",\n nextStep: \"חזרה לכתיבה → drafted\"\n },\n blocked: {\n description: \"תיק חסום - דורש התערבות ידנית\",\n agent: \"מערכת\",\n nextStep: \"טיפול ידני\"\n },\n};\n```\n\n### אפשרות B: דף /statuses נפרד\n```typescript\n// web-ui/src/app/statuses/page.tsx\n// דף עצמאי עם טבלה של כל הסטטוסים\n```\n\n## המלצה: אפשרות A - פשוטה יותר ומשתלבת ב-UX הקיים", + "testStrategy": "## בדיקות:\n1. **UI Testing**:\n - לחיצה על אייקון העזרה פותחת popover/tooltip\n - כל סטטוס מציג: תיאור, agent, שלב הבא\n - סגירת ה-popover עובדת (לחיצה מחוץ/Escape)\n\n2. **Accessibility**:\n - ה-popover נגיש למקלדת (Tab, Enter, Escape)\n - aria-label מתאים\n - RTL מוצג נכון\n\n3. **Content Review**:\n - כל ההסברים בעברית תקנית\n - הזרימה בין סטטוסים מובנת", + "priority": "medium", + "dependencies": [ + 93 + ], + "status": "pending", + "subtasks": [] + }, + { + "id": 95, + "title": "עריכה ידנית של סטטוס בדף התיק", + "description": "הוספת dropdown או מודל בדף התיק לשינוי סטטוס ידני, לטיפול במקרים שבהם ה-pipeline נתקע או צריך reset", + "details": "## מיקום: בתוך הכרטיס של WorkflowTimeline (בצד ימין של דף התיק)\n\n## פסאודו-קוד:\n\n### 1. קומפוננטת StatusEditor:\n```typescript\n// web-ui/src/components/cases/status-editor.tsx\n\nimport { Select } from \"@/components/ui/select\";\nimport { Button } from \"@/components/ui/button\";\nimport { useUpdateCase } from \"@/lib/api/cases\";\nimport { toast } from \"sonner\";\n\nexport function StatusEditor({ caseNumber, currentStatus }: Props) {\n const [selectedStatus, setSelectedStatus] = useState(currentStatus);\n const updateCase = useUpdateCase(caseNumber);\n\n const handleSave = async () => {\n if (selectedStatus === currentStatus) return;\n \n try {\n await updateCase.mutateAsync({ status: selectedStatus });\n toast.success(\"סטטוס עודכן בהצלחה\");\n } catch (error) {\n toast.error(\"שגיאה בעדכון הסטטוס\");\n }\n };\n\n return (\n
\n \n \n
\n );\n}\n```\n\n### 2. שילוב בדף התיק:\n```typescript\n// web-ui/src/app/cases/[caseNumber]/page.tsx\n// בתוך הכרטיס של WorkflowTimeline\n\n\n \n

שלב בתהליך

\n \n {data && }\n
\n
\n```\n\n### 3. עדכון ה-API (אם נדרש):\nה-`useUpdateCase` כבר תומך ב-status field לפי `caseUpdateSchema`.", + "testStrategy": "## בדיקות:\n1. **Functionality**:\n - בחירת סטטוס חדש מה-dropdown\n - לחיצה על \"עדכן\" שולחת PUT request ל-API\n - הסטטוס מתעדכן ב-UI אחרי הצלחה\n - toast הודעה מוצגת\n\n2. **Edge Cases**:\n - לחיצה על \"עדכן\" כשהסטטוס לא השתנה - כפתור disabled\n - טיפול בשגיאת API - הודעת שגיאה\n - כפתור disabled בזמן loading\n\n3. **Integration**:\n - ה-WorkflowTimeline מתעדכן מיד אחרי שינוי סטטוס\n - ה-StatusBadge בכותרת מתעדכן\n - הנתונים מסונכרנים עם ה-DB", + "priority": "medium", + "dependencies": [ + 93 + ], + "status": "pending", + "subtasks": [] + }, + { + "id": 96, + "title": "מיזוג כפתורי פעולות לכרטיס הסקירה הראשי", + "description": "העברת הכפתורים 'פתח בעורך ההחלטה' ו'עריכת פרטי תיק' מהלשונית 'פעולות' לכרטיס הכותרת העליון, והסרת הלשונית המיותרת", + "details": "## קבצים לעדכון:\n- `web-ui/src/app/cases/[caseNumber]/page.tsx`\n- `web-ui/src/components/cases/case-header.tsx`\n\n## פסאודו-קוד:\n\n### 1. עדכון CaseHeader להוספת כפתורי פעולה:\n```typescript\n// web-ui/src/components/cases/case-header.tsx\n\nimport Link from \"next/link\";\nimport { Button } from \"@/components/ui/button\";\nimport { CaseEditDialog } from \"@/components/cases/case-edit-dialog\";\n\nexport function CaseHeader({ data }: { data?: CaseDetail }) {\n return (\n \n \n {/* ... breadcrumb קיים ... */}\n \n
\n
\n {/* ... כותרת וסטטוס קיימים ... */}\n
\n\n {/* כפתורי פעולה - חדש */}\n
\n \n {data && }\n
\n
\n\n {/* ... תאריכים קיימים ... */}\n
\n
\n );\n}\n```\n\n### 2. הסרת לשונית \"פעולות\" מדף התיק:\n```typescript\n// web-ui/src/app/cases/[caseNumber]/page.tsx\n\n// הסר את TabsTrigger value=\"actions\"\n\n סקירה\n מסמכים (...)\n {/* הוסר: פעולות */}\n\n\n// הסר את TabsContent value=\"actions\"\n// הקוד הבא נמחק:\n// \n//
\n// \n// {data && }\n//
\n//
\n```\n\n### 3. עדכון CaseHeader props:\n```typescript\n// צריך להעביר caseNumber ל-CaseHeader אם עדיין לא קיים\n\n```", + "testStrategy": "## בדיקות:\n1. **Visual**:\n - כפתורי הפעולה מופיעים בכרטיס העליון\n - הכפתורים מיושרים ימינה (RTL)\n - responsive - נגלשים נכון במסכים קטנים\n\n2. **Functionality**:\n - \"פתח בעורך ההחלטה\" מנווט ל-/cases/{caseNumber}/compose\n - \"עריכת פרטי תיק\" פותח את ה-CaseEditDialog\n - ה-dialog עובד כרגיל\n\n3. **Removal**:\n - לשונית \"פעולות\" לא מופיעה יותר ב-Tabs\n - אין שגיאות קונסול\n - ניווט ל-#actions לא עובד (ולא אמור)\n\n4. **Regression**:\n - לשוניות \"סקירה\" ו\"מסמכים\" עובדות כרגיל\n - שאר הדף לא נפגע", + "priority": "low", + "dependencies": [], + "status": "pending", + "subtasks": [] } ], "metadata": { - "version": "1.0.0", - "lastModified": "2026-04-11T19:20:56.040Z", - "taskCount": 60, - "completedCount": 57, - "tags": [ - "master" - ] + "created": "2026-04-13T14:20:54.888Z", + "updated": "2026-04-13T14:20:54.888Z", + "description": "Tasks for master context" } } } \ No newline at end of file diff --git a/web-ui/src/app/cases/[caseNumber]/page.tsx b/web-ui/src/app/cases/[caseNumber]/page.tsx index 4622667..1c1a287 100644 --- a/web-ui/src/app/cases/[caseNumber]/page.tsx +++ b/web-ui/src/app/cases/[caseNumber]/page.tsx @@ -10,6 +10,8 @@ import { Skeleton } from "@/components/ui/skeleton"; import { CaseHeader } from "@/components/cases/case-header"; import { CaseEditDialog } from "@/components/cases/case-edit-dialog"; import { WorkflowTimeline } from "@/components/cases/workflow-timeline"; +import { StatusGuide } from "@/components/cases/status-guide"; +import { StatusChanger } from "@/components/cases/status-changer"; import { DocumentsPanel } from "@/components/cases/documents-panel"; import { UploadSheet } from "@/components/documents/upload-sheet"; import { expectedOutcomes } from "@/lib/schemas/case"; @@ -76,7 +78,6 @@ export default function CaseDetailPage({ )} - פעולות @@ -101,14 +102,7 @@ export default function CaseDetailPage({ - - - - - - - -
+
+ + + + @@ -125,6 +123,8 @@ export default function CaseDetailPage({

שלב בתהליך

+ +
diff --git a/web-ui/src/components/cases/status-badge.tsx b/web-ui/src/components/cases/status-badge.tsx index 7bb8721..b8942b0 100644 --- a/web-ui/src/components/cases/status-badge.tsx +++ b/web-ui/src/components/cases/status-badge.tsx @@ -1,5 +1,11 @@ import { Badge } from "@/components/ui/badge"; +import { + FilePlus2, Upload, Loader2, FileCheck, Target, + Lightbulb, Compass, PenLine, SearchCheck, FileText, + FileOutput, CheckCircle2, Award, +} from "lucide-react"; import type { CaseStatus } from "@/lib/api/cases"; +import type { LucideIcon } from "lucide-react"; const STATUS_LABELS: Record = { new: "חדש", @@ -17,6 +23,38 @@ const STATUS_LABELS: Record = { final: "סופי", }; +const STATUS_ICONS: Record = { + new: FilePlus2, + uploading: Upload, + processing: Loader2, + documents_ready: FileCheck, + outcome_set: Target, + brainstorming: Lightbulb, + direction_approved: Compass, + drafting: PenLine, + qa_review: SearchCheck, + drafted: FileText, + exported: FileOutput, + reviewed: CheckCircle2, + final: Award, +}; + +const STATUS_DESCRIPTIONS: Record = { + new: "התיק נוצר וממתין להעלאת מסמכים", + uploading: "מסמכים בתהליך העלאה לשרת", + processing: "המערכת מעבדת ומנתחת את המסמכים", + documents_ready: "כל המסמכים עובדו ומוכנים לעבודה", + outcome_set: "נקבעה תוצאה צפויה לערר", + brainstorming: "ניתוח כיוונים אפשריים להחלטה", + direction_approved: "כיוון ההחלטה אושר — ניתן להתחיל כתיבה", + drafting: "טיוטת ההחלטה בתהליך כתיבה", + qa_review: "הטיוטה בבדיקת איכות אוטומטית", + drafted: "טיוטה ראשונה מוכנה לעיון", + exported: "ההחלטה יוצאה לקובץ DOCX", + reviewed: "ההחלטה נבדקה ע\"י היו\"ר", + final: "החלטה סופית — מוכנה להגשה", +}; + /* Status color groups: * intake → new, uploading, processing (muted parchment) * prep → documents_ready, outcome_set (info blue) @@ -40,14 +78,16 @@ const STATUS_TONE: Record = { }; export function StatusBadge({ status }: { status: CaseStatus }) { + const Icon = STATUS_ICONS[status]; return ( + {Icon && } {STATUS_LABELS[status] ?? status} ); } -export { STATUS_LABELS }; +export { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS, STATUS_TONE }; diff --git a/web-ui/src/components/cases/status-changer.tsx b/web-ui/src/components/cases/status-changer.tsx new file mode 100644 index 0000000..bd636b5 --- /dev/null +++ b/web-ui/src/components/cases/status-changer.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { useState } from "react"; +import { toast } from "sonner"; +import { + Select, SelectContent, SelectItem, SelectTrigger, SelectValue, +} 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"; + +/* + * Dropdown for manually overriding the case status — skip a step + * or revert to an earlier stage. Calls PUT /api/cases/:caseNumber + * with { status: newValue }. + */ + +const ALL_STATUSES: CaseStatus[] = [ + "new", "uploading", "processing", + "documents_ready", "outcome_set", + "brainstorming", "direction_approved", + "drafting", "qa_review", "drafted", + "exported", "reviewed", "final", +]; + +export function StatusChanger({ + caseNumber, + currentStatus, +}: { + caseNumber: string; + currentStatus?: CaseStatus; +}) { + const [selected, setSelected] = useState(currentStatus ?? ""); + const mutate = useUpdateCase(caseNumber); + + const handleSave = async () => { + if (!selected || selected === currentStatus) return; + try { + await mutate.mutateAsync({ status: selected }); + toast.success(`הסטטוס עודכן ל${STATUS_LABELS[selected]}`); + } catch (e) { + toast.error(e instanceof Error ? e.message : "שגיאה בעדכון הסטטוס"); + } + }; + + return ( +
+ +
+ + +
+
+ ); +} diff --git a/web-ui/src/components/cases/status-guide.tsx b/web-ui/src/components/cases/status-guide.tsx new file mode 100644 index 0000000..f8e42b8 --- /dev/null +++ b/web-ui/src/components/cases/status-guide.tsx @@ -0,0 +1,72 @@ +"use client"; + +import { useState } from "react"; +import { ChevronDown, ChevronUp } from "lucide-react"; +import type { CaseStatus } from "@/lib/api/cases"; +import { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS, STATUS_TONE } from "@/components/cases/status-badge"; + +/* + * Collapsible guide showing all 13 statuses grouped by phase, + * each with its icon, Hebrew label, color badge, and description. + * 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", "outcome_set"] }, + { label: "ניתוח וכיוון", statuses: ["brainstorming", "direction_approved"] }, + { label: "כתיבת טיוטה", statuses: ["drafting", "qa_review", "drafted"] }, + { label: "סגירה", statuses: ["exported", "reviewed", "final"] }, +]; + +export function StatusGuide() { + const [open, setOpen] = useState(false); + + return ( +
+ + + {open && ( +
+ {PHASE_GROUPS.map((group) => ( +
+

+ {group.label} +

+
    + {group.statuses.map((s) => { + const Icon = STATUS_ICONS[s]; + return ( +
  • + + + {STATUS_LABELS[s]} + + + {STATUS_DESCRIPTIONS[s]} + +
  • + ); + })} +
+
+ ))} +
+ )} +
+ ); +} diff --git a/web-ui/src/components/cases/workflow-timeline.tsx b/web-ui/src/components/cases/workflow-timeline.tsx index ffeaf73..52bf75b 100644 --- a/web-ui/src/components/cases/workflow-timeline.tsx +++ b/web-ui/src/components/cases/workflow-timeline.tsx @@ -1,7 +1,11 @@ "use client"; import type { CaseStatus } from "@/lib/api/cases"; -import { STATUS_LABELS } from "@/components/cases/status-badge"; +import { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS } from "@/components/cases/status-badge"; +import { + FolderInput, ClipboardList, Brain, PenLine, CheckCircle2, +} from "lucide-react"; +import type { LucideIcon } from "lucide-react"; /* * Vertical RTL workflow timeline showing the 13-status case pipeline. @@ -13,15 +17,16 @@ import { STATUS_LABELS } from "@/components/cases/status-badge"; type Phase = { key: string; label: string; + icon: LucideIcon; statuses: CaseStatus[]; }; const PHASES: Phase[] = [ - { key: "intake", label: "קליטה ועיבוד", statuses: ["new", "uploading", "processing"] }, - { key: "prep", label: "הכנת תיק", statuses: ["documents_ready", "outcome_set"] }, - { key: "thinking", label: "ניתוח וכיוון", statuses: ["brainstorming", "direction_approved"] }, - { key: "writing", label: "כתיבת טיוטה", statuses: ["drafting", "qa_review", "drafted"] }, - { key: "done", label: "סגירה", statuses: ["exported", "reviewed", "final"] }, + { key: "intake", label: "קליטה ועיבוד", icon: FolderInput, statuses: ["new", "uploading", "processing"] }, + { key: "prep", label: "הכנת תיק", icon: ClipboardList, statuses: ["documents_ready", "outcome_set"] }, + { key: "thinking", label: "ניתוח וכיוון", icon: Brain, statuses: ["brainstorming", "direction_approved"] }, + { key: "writing", label: "כתיבת טיוטה", icon: PenLine, statuses: ["drafting", "qa_review", "drafted"] }, + { key: "done", label: "סגירה", icon: CheckCircle2, statuses: ["exported", "reviewed", "final"] }, ]; function phaseIndexOf(status?: CaseStatus): number { @@ -55,19 +60,36 @@ export function WorkflowTimeline({ status }: { status?: CaseStatus }) { : state === "current" ? "text-navy font-semibold" : "text-ink-muted"; + const iconTone = + state === "done" ? "text-success" + : state === "current" ? "text-gold-deep" + : "text-ink-muted/50"; + + const PhaseIcon = phase.icon; + const StatusIcon = status ? STATUS_ICONS[status] : null; + return (
  • -
    - {phase.label} +
    + + + {phase.label} + {state === "current" && status && ( - + + {StatusIcon && } {STATUS_LABELS[status]} )} + {state === "current" && status && STATUS_DESCRIPTIONS[status] && ( + + {STATUS_DESCRIPTIONS[status]} + + )}
  • );