Add status icons, descriptions, status guide, manual status changer, and merge action buttons into overview tab
- StatusBadge: added icons (lucide-react) and Hebrew descriptions for all 13 statuses - WorkflowTimeline: added phase icons and current-status description display - StatusGuide: new collapsible component showing all statuses grouped by phase with explanations - StatusChanger: new dropdown for manual status override on the case detail sidebar - Case detail page: merged action buttons into overview tab, removed separate actions tab Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
web-ui/src/components/cases/status-changer.tsx
Normal file
84
web-ui/src/components/cases/status-changer.tsx
Normal file
@@ -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<CaseStatus | "">(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 (
|
||||
<div className="mt-4 border-t border-rule pt-3 space-y-2">
|
||||
<label className="text-[0.72rem] text-ink-muted block">שינוי סטטוס ידני</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select
|
||||
value={selected || "__current__"}
|
||||
onValueChange={(v) => setSelected(v === "__current__" ? "" : v as CaseStatus)}
|
||||
dir="rtl"
|
||||
>
|
||||
<SelectTrigger className="text-[0.75rem] h-8">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{ALL_STATUSES.map((s) => {
|
||||
const Icon = STATUS_ICONS[s];
|
||||
return (
|
||||
<SelectItem key={s} value={s} className="text-[0.75rem]">
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<Icon className="w-3 h-3 shrink-0" />
|
||||
{STATUS_LABELS[s]}
|
||||
</span>
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-8 text-[0.72rem] px-3 shrink-0"
|
||||
disabled={!selected || selected === currentStatus || mutate.isPending}
|
||||
onClick={handleSave}
|
||||
>
|
||||
{mutate.isPending ? "שומר…" : "עדכן"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user