All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m26s
Added analyst_verified, research_complete, analysis_enriched, and ready_for_writing statuses across all UI components: status-badge, workflow-timeline, status-donut, status-changer, status-guide, and kpi-cards. Also changed qa_review label from "QA" to "בדיקת איכות". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
3.8 KiB
TypeScript
100 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import type { CaseStatus } from "@/lib/api/cases";
|
|
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.
|
|
* 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.
|
|
*/
|
|
|
|
type Phase = {
|
|
key: string;
|
|
label: string;
|
|
icon: LucideIcon;
|
|
statuses: CaseStatus[];
|
|
};
|
|
|
|
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));
|
|
}
|
|
|
|
export function WorkflowTimeline({ status }: { status?: CaseStatus }) {
|
|
const currentIdx = phaseIndexOf(status);
|
|
|
|
return (
|
|
<ol className="relative space-y-4">
|
|
<div
|
|
className="absolute top-2 bottom-2 right-[11px] w-px bg-rule"
|
|
aria-hidden
|
|
/>
|
|
{PHASES.map((phase, i) => {
|
|
const state =
|
|
currentIdx === -1 ? "pending"
|
|
: i < currentIdx ? "done"
|
|
: i === currentIdx ? "current"
|
|
: "pending";
|
|
|
|
const dotTone =
|
|
state === "done" ? "bg-success border-success"
|
|
: state === "current" ? "bg-gold border-gold shadow-[0_0_0_4px_color-mix(in_oklab,var(--color-gold)_20%,transparent)]"
|
|
: "bg-surface border-rule";
|
|
|
|
const labelTone =
|
|
state === "done" ? "text-ink-soft"
|
|
: 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 (
|
|
<li key={phase.key} className="relative flex items-start gap-3 ps-7">
|
|
<span
|
|
className={`absolute right-[5px] top-1 inline-block w-3 h-3 rounded-full border-2 ${dotTone}`}
|
|
aria-hidden
|
|
/>
|
|
<div className="flex flex-col gap-0.5">
|
|
<span className={`text-sm flex items-center gap-1.5 ${labelTone}`}>
|
|
<PhaseIcon className={`w-3.5 h-3.5 shrink-0 ${iconTone}`} />
|
|
{phase.label}
|
|
</span>
|
|
{state === "current" && status && (
|
|
<span className="text-[0.72rem] text-gold-deep flex items-center gap-1">
|
|
{StatusIcon && <StatusIcon className="w-3 h-3 shrink-0" />}
|
|
{STATUS_LABELS[status]}
|
|
</span>
|
|
)}
|
|
{state === "current" && status && STATUS_DESCRIPTIONS[status] && (
|
|
<span className="text-[0.65rem] text-ink-muted leading-snug mt-0.5">
|
|
{STATUS_DESCRIPTIONS[status]}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</li>
|
|
);
|
|
})}
|
|
</ol>
|
|
);
|
|
}
|