import { useState } from "react"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Plus, Trash2, Loader2, Settings2, ArrowRight } from "lucide-react"; import { approvalsService, type ApprovalWorkflow, type ApprovalStage } from "@/services/approvals.service"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useToast } from "@/hooks/use-toast"; type WorkflowStage = Omit & { order: number }; export default function ApprovalWorkflowConfig() { const { toast } = useToast(); const qc = useQueryClient(); const { data: workflowsData, isLoading } = useQuery({ queryKey: ["approvals", "list"], queryFn: () => approvalsService.list(), }); const workflows: ApprovalWorkflow[] = workflowsData?.results ?? workflowsData?.items ?? []; type WorkflowWriteInput = Partial & { steps?: Partial[]; bypass_enabled?: boolean; }; const createWorkflow = useMutation({ mutationFn: (data: WorkflowWriteInput) => approvalsService.create(data), onSuccess: () => qc.invalidateQueries({ queryKey: ["approvals"] }), onError: () => toast({ title: "Error", description: "Failed to create workflow", variant: "destructive" }), }); const updateWorkflow = useMutation({ mutationFn: ({ id, data }: { id: number; data: WorkflowWriteInput }) => approvalsService.update(id, data), onSuccess: () => qc.invalidateQueries({ queryKey: ["approvals"] }), onError: () => toast({ title: "Error", description: "Failed to update workflow", variant: "destructive" }), }); const deleteWorkflow = useMutation({ mutationFn: (id: number) => approvalsService.delete(id), onSuccess: () => qc.invalidateQueries({ queryKey: ["approvals"] }), onError: () => toast({ title: "Error", description: "Failed to delete workflow", variant: "destructive" }), }); const [showCreate, setShowCreate] = useState(false); const [wfName, setWfName] = useState(""); const [stages, setStages] = useState([{ order: 1, approver_id: 0, approver_name: "", max_days: 3, auto_escalate: false }]); const [bypassEnabled, setBypassEnabled] = useState(false); const resetForm = () => { setWfName(""); setStages([{ order: 1, approver_id: 0, approver_name: "", max_days: 3, auto_escalate: false }]); setBypassEnabled(false); }; const addStage = () => { setStages(prev => [...prev, { order: prev.length + 1, approver_id: 0, approver_name: "", max_days: 3, auto_escalate: false }]); }; const removeStage = (idx: number) => { setStages(prev => prev.filter((_, i) => i !== idx).map((s, i) => ({ ...s, order: i + 1 }))); }; const updateStage = (idx: number, field: keyof WorkflowStage, value: string | number | boolean) => { setStages(prev => prev.map((s, i) => i === idx ? { ...s, [field]: value } : s)); }; const handleCreate = () => { const valid = stages.filter(s => s.approver_id > 0); if (valid.length === 0) { toast({ title: "Validation", description: "Add at least one stage with an approver ID", variant: "destructive" }); return; } createWorkflow.mutate( { name: wfName, status: "draft", allow_bypass: bypassEnabled, bypass_enabled: bypassEnabled, steps: valid.map(s => ({ order: s.order, approver_id: s.approver_id, approver_name: s.approver_name, max_days: s.max_days, auto_escalate: s.auto_escalate, notification_email: s.notification_email, })), }, { onSuccess: () => { toast({ title: "Workflow Created" }); setShowCreate(false); resetForm(); } }, ); }; const handleDelete = (id: number) => { if (!window.confirm("Delete this approval workflow?")) return; deleteWorkflow.mutate(id, { onSuccess: () => toast({ title: "Workflow Deleted" }), }); }; const handleToggleStatus = (wf: ApprovalWorkflow) => { const newStatus = wf.status === "active" ? "draft" : "active"; updateWorkflow.mutate( { id: wf.id, data: { status: newStatus } }, { onSuccess: () => toast({ title: `Workflow ${newStatus === "active" ? "Activated" : "Deactivated"}` }) }, ); }; if (isLoading) return
; return (

Approval Workflows

Configure multi-stage approval workflows with escalation rules.

{ setShowCreate(open); if (!open) resetForm(); }}> Create Approval Workflow
setWfName(e.target.value)} />
{stages.map((stage, idx) => (
Stage {stage.order} {stages.length > 1 && ( )}
updateStage(idx, "approver_name", e.target.value)} placeholder="Name" />
updateStage(idx, "approver_id", Number(e.target.value))} placeholder="ID" />
updateStage(idx, "max_days", Number(e.target.value))} />
updateStage(idx, "notification_email", e.target.value)} placeholder="email@..." />
updateStage(idx, "auto_escalate", v)} />
))}
{workflows.map(wf => (
{wf.name} {wf.entity_name}
{wf.status} handleToggleStatus(wf)} />
{wf.steps.map((step, i) => (
{step.order} {step.approver_name}
{i < wf.steps.length - 1 && }
))}

Created: {new Date(wf.created_at).toLocaleDateString()}

))} {workflows.length === 0 && (

No approval workflows configured.

)}
); }