Handoff card
ProA run passed from one person to another while it's in flight: who from, who to, the run and where it is, the note, and what does and doesn't transfer. The recipient accepts or declines; until then it stays with the sender, unless pendingNote says what happens instead (say, the sender has already stepped back).
Preview
Install
With the Candor CLI
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/handoff-card
Brings in: button, locale, relative-time, status, status-dot, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import * as React from "react"
import { HandoffCard } from "@/components/handoff-card"
const ago = (m: number) => new Date(Date.now() - m * 60_000).toISOString()
export default function Example() {
const [state, setState] = React.useState<"pending" | "accepted" | "declined">("pending")
return (
<HandoffCard
className="max-w-xl"
run="Add region to customers"
status="waiting"
from="Sam"
to="Priya"
note="Backfill is paused at batch 12. Staging looks good; Production needs an approver."
at={ago(20)}
moves={["The thread and its history", "The pending approval request", "Notifications for this run"]}
stays={["Sam’s drafts in other threads", "Sam’s role on Production"]}
state={state}
onAccept={() => setState("accepted")}
onDecline={() => setState("declined")}
/>
)
}<HandoffCard>
| Prop | Type | Default | Description |
|---|---|---|---|
| runrequired | string | — | The run or thread being handed over. |
| statusrequired | RunStatus | — | Where the run is now. |
| fromrequired | string | — | Who hands it over. |
| torequired | string | — | Who it goes to: a person or a team. |
| note | string | undefined | — | The sender's note for the recipient. |
| atrequired | string | — | When it was handed over (ISO). |
| movesrequired | string[] | — | What transfers, as the service defines it. |
| staysrequired | string[] | — | What doesn't. |
| staterequired | "pending" | "accepted" | "declined" | — | Whether the recipient has taken it over yet. |
| pendingNote | string | undefined | — | What happens while it waits, in place of "Stays with <from> until <to> accepts." E.g. "The agent has stopped replying; it waits for Support." |
| onAccept | (() => void) | undefined | — | Take it over. Without it, there's no button. |
| onDecline | (() => void) | undefined | — | Turn it down. Without it, there's no button. |
| className | string | undefined | — | Extra classes for the outer element. |
Strings
The fixed words, in English by default. Change any of them under handoffCard in <LocaleProvider strings={{ … }}>; the table is exported as handoffCardStrings.
| Key | English |
|---|---|
| handoff | Handoff: {run} |
| to | to |
| note | “{note}” |
| movesTo | Moves to {to} |
| doesntMove | Doesn’t move |
| staysWith | Stays with {from} until {to} accepts. |
| decline | Decline |
| takeOver | Take it over |
| accepted | {to} took it over. |
| declined | {to} declined; it’s still with {from}. |