Skip to content
Sign in
CollaborationApproval routingMenu

Approval routingPro

Who must approve an agent's action, in order, with each step's status and your decision right on your step.

ProThe agent wants to void a charge: an automatic check passed, now it is your step.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/approval-routing

Usage

tsx
import { ApprovalRouting } from "@/components/ui/chatcn/pro/approval-routing"

<ApprovalRouting
  requester={ledger}
  action="void the second charge of $84.20 on order 4471"
  rule="Voids over $50 need billing ops, then finance."
  steps={[
    { id: "ops", label: "Billing ops", approvers: [tomasz, me], mode: "any", status: "waiting" },
    { id: "finance", approvers: [noor], status: "pending" },
  ]}
  currentUserId={me.id}
  onApprove={(stepId) => api.approve(stepId)}
  onDecline={(stepId, note) => api.decline(stepId, note)}
  onRemind={(stepId) => api.remind(stepId)}
/>

The route is a rail of steps. Passed segments are solid ink and the rest are dashed; each step's node is its own shape (a check, a cross, an amber diamond for the step waiting now, a hollow ring for later, a dash for not needed). A step can be one person, any one of a group, or all of a group. When the waiting step includes the viewer, Approve and Decline sit right on it, and Decline asks why because the agent reads the note. Other people's waiting steps offer Remind. Decisions apply the moment they resolve, so the route moves on (and a decline marks the rest as not needed) before new steps arrive; new steps always win.

Examples

States

ProWaiting on someone else, approved end to end, declined and a decision that failed to save.

Props

PropTypeNotes
requesterCollabMemberWho wants to act, usually an agent
action, detail, ruleReactNodeWhat, extra context, and the policy
steps{ id, approvers, mode?, label?, status, decidedBy?, at?, note? }[]status: approved, declined, waiting, pending, skipped
currentUserIdstringSteps the viewer can decide get the buttons
onApprove, onDecline(stepId, note?) => unknown | Promise<unknown>Reject to show the error
onRemind(stepId) => voidShows Remind on other people's steps
labels, localeEvery string, for translation

Labels

labels covers the ask line, the route line, any one of and all of, every status word with and without a name, the buttons, the decline prompt, the progress count, the closing lines and the error.

Keyboard

KeyAction
TabApprove, Decline, Remind
Enter in the noteDecline with the note
Shift EnterNew line in the note

Accessibility

  • The route is an ordered list; the waiting step has aria-current="step".
  • Every status is said in words beside its node; the nodes are decorative.
  • A failed decision is an alert; the closing line is a status.

Motion

The closing line rises 4 px and fades in over 200 ms. Buttons press at 0.97. Reduced motion keeps the fade.