A purchase request going round its approvers one at a time: a chip carries it from person to person, a ring fills round each avatar as they review and turns green as they approve; Finance sometimes sends it back in amber to be updated, Legal is only asked above $10k, and the purchase order goes out at the end. Pauses, and stacks on phones.
When to use
- A request going round its approvers one at a time, approved or sent back, with its order number.
- Procurement, expense and approval products; a live view of requests in review.
When not to use
- Requests one person approves: a button and a status are enough.
- Working through the queue itself: a table of requests with their stage.
Usage
Approval workflow with your own data: every prop has the sample as its default, so pass only what you have.
import { useEffect, useRef } from "react"
import { ApprovalWorkflow, type WorkflowHandle } from "@/components/dashral/blocks/approval-workflow"
const workflow = useRef<WorkflowHandle>(null)
useEffect(() => requests.on("submitted", (r) => workflow.current?.send(r)), [])
<ApprovalWorkflow ref={workflow} mode="live" approvers={approvers} onDone={(request) => api.requests.close(request)} />API reference
ApprovalWorkflow
The section: a heading, the workflow in a dotted panel with a Live badge and Pause, and a row of figures. Every part comes from props, with a sample workflow by default.
| Prop | Type | Default |
|---|---|---|
eyebrow | React.ReactNode | "Approvals" |
title | React.ReactNode | sample |
description | React.ReactNode | sample |
approvers | Person[]Who approves, in order; the last is only asked above | sample |
threshold | number | 10_000 |
requests | Request[]The sample requests the demo plays, and the first purchase order number. | sample |
firstOrder | number | 2041 |
stats | { value: string; label: string }[]The figures under the diagram; none hides the row. | sample |
mode | WorkflowProps["mode"]With your own requests instead of the sample ones (see Workflow's mode="live"). | — |
onDone | WorkflowProps["onDone"] | — |
ref | React.Ref<WorkflowHandle> | — |
Workflow
A request going round for approval, one at a time: a chip carries it from the requester to each approver in turn; each reviews it (a ring fills round their avatar) and approves, green; Finance sometimes asks for changes, amber, and it goes back to the requester to be updated before coming round again; the last approver is only asked above a threshold, faded otherwise; then the purchase order goes out. In a row when there's room, stacked on a narrow container. One requestAnimationFrame loop writes everything directly. The sample requests in a loop by default; with mode="live", the ones you send (see WorkflowHandle). It stops off screen, in a hidden tab, when paused and (live) once the last request is approved; with reduced motion it shows a request approved.
| Prop | Type | Default |
|---|---|---|
requests | Request[]The sample requests, played in a loop ("demo"). | sample |
approvers | Person[]Required. Who approves, in order. The last is only asked above | — |
threshold | numberRequired. | — |
firstOrder | numberRequired. The first purchase order number; it goes up with every approved request. | — |
speed | numberHow fast it runs: 1 is the usual pace, 2 twice as fast, 0 holds it still. | 1 |
paused | booleanBrings it to rest where it is (easing down, not stopping in one frame). | false |
onDone | (request: Request, order: number) => voidLive: called as each request's purchase order goes out, with its number. | — |
mode | "demo" | "live""demo" plays the sample requests in a loop; "live" plays a request only when you send it (see WorkflowHandle). | "demo" |
ref | React.Ref<WorkflowHandle> | — |
className | string | — |
type Person
| Prop | Type | Default |
|---|---|---|
name | string | — |
role | string | — |
src | string | — |
type Request
A request going round for approval: what it's for, how much, and whether Finance sends it back once.
| Prop | Type | Default |
|---|---|---|
title | string | — |
amount | number | — |
requester | Person | — |
changes | boolean | — |
type WorkflowHandle
Plays your own requests (mode="live").
| Prop | Type | Default |
|---|---|---|
send | (request: Request) => voidPlays one request round its approvers (the last only above | — |