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>
92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
"use client";
|
||
|
||
import type { Case, CaseStatus } from "@/lib/api/cases";
|
||
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.
|
||
*/
|
||
|
||
type GroupKey = "intake" | "prep" | "thinking" | "writing" | "done";
|
||
|
||
const GROUP_OF: Record<CaseStatus, GroupKey> = {
|
||
new: "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", drafted: "writing",
|
||
exported: "done", reviewed: "done", final: "done",
|
||
};
|
||
|
||
const GROUP_META: Record<GroupKey, { label: string; color: string }> = {
|
||
intake: { label: "חדש / בעיבוד", color: "var(--color-ink-muted)" },
|
||
prep: { label: "הכנה", color: "var(--color-info)" },
|
||
thinking: { label: "ניתוח וכיוון", color: "var(--color-gold)" },
|
||
writing: { label: "בכתיבה", color: "var(--color-warn)" },
|
||
done: { label: "מוכן", color: "var(--color-success)" },
|
||
};
|
||
|
||
export function StatusDonut({ cases }: { cases?: Case[] }) {
|
||
const counts: Record<GroupKey, number> = {
|
||
intake: 0, prep: 0, thinking: 0, writing: 0, done: 0,
|
||
};
|
||
(cases ?? []).forEach((c) => {
|
||
const g = GROUP_OF[c.status];
|
||
if (g) counts[g] += 1;
|
||
});
|
||
const total = Object.values(counts).reduce((a, b) => a + b, 0);
|
||
|
||
const segments: { key: GroupKey; start: number; end: number }[] = [];
|
||
let pct = 0;
|
||
(Object.keys(counts) as GroupKey[]).forEach((k) => {
|
||
if (counts[k] === 0) return;
|
||
const start = total === 0 ? 0 : (pct / total) * 360;
|
||
pct += counts[k];
|
||
const end = total === 0 ? 360 : (pct / total) * 360;
|
||
segments.push({ key: k, start, end });
|
||
});
|
||
|
||
const background =
|
||
total === 0
|
||
? "conic-gradient(var(--color-rule-soft) 0deg 360deg)"
|
||
: `conic-gradient(${segments
|
||
.map((s) => `${GROUP_META[s.key].color} ${s.start}deg ${s.end}deg`)
|
||
.join(", ")})`;
|
||
|
||
return (
|
||
<div className="flex items-center gap-6">
|
||
<div
|
||
className="relative w-[140px] h-[140px] rounded-full shadow-sm"
|
||
style={{ background }}
|
||
aria-label="פיזור תיקים לפי סטטוס"
|
||
>
|
||
<div className="absolute inset-[18px] bg-surface rounded-full flex flex-col items-center justify-center">
|
||
<span className="font-display text-2xl font-black text-navy leading-none">
|
||
{total}
|
||
</span>
|
||
<span className="text-[0.7rem] text-ink-muted mt-1">תיקים</span>
|
||
</div>
|
||
</div>
|
||
|
||
<ul className="flex flex-col gap-1.5 text-sm">
|
||
{(Object.keys(GROUP_META) as GroupKey[]).map((k) => (
|
||
<li key={k} className="flex items-center gap-2">
|
||
<span
|
||
className="inline-block w-2.5 h-2.5 rounded-full"
|
||
style={{ background: GROUP_META[k].color }}
|
||
/>
|
||
<span className="text-ink-soft">{GROUP_META[k].label}</span>
|
||
<span className="text-ink-muted tabular-nums me-auto ms-1">
|
||
{counts[k]}
|
||
</span>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/* Exported for the legend tests / docs if ever needed */
|
||
export { STATUS_LABELS };
|