Household pattern
ApprovalCard
The ask as you see it: what it wants, why it stopped, how long it will wait, and afterwards what you said.
States
Waiting on you (live)
the buttons answer the fixture's recorded yes
Needs you
7:00 amThe 5-litre detergent from Valley Wholesale is $55.00. Go ahead?
Sent through a card in the app on Wednesday, Aug 26 at 7:00 am.
If there is no answer by Thursday, Aug 27 at 7:00 am, it will let this go.
Waiting on you (replay)
Needs you
7:00 amThe 5-litre detergent from Valley Wholesale is $55.00. Go ahead?
Sent through a card in the app on Wednesday, Aug 26 at 7:00 am.
If there is no answer by Thursday, Aug 27 at 7:00 am, it will let this go.
Limit hit, approved
You said yes
7:00 amThe 5-litre detergent from Valley Wholesale is $55.00. Go ahead?
Sent through a card in the app on Wednesday, Aug 26 at 7:00 am.
You said yes at 12:12 pm, “Go ahead”.
Declined
You said no
9:00 amYou're out during Sunday's delivery window. Move it to Monday 8–10 am?
Sent through a card in the app on Saturday, Aug 29 at 9:00 am.
You said no at 11:00 am, “Keep Sunday, the neighbor can take it”.
Expired, let it go
No answer. It let this go.
3:40 pmValley Wholesale is out of the 12-pack paper towels. Swap for the 8-pack ($3.10 more)?
Sent through a card in the app on Thursday, Aug 27 at 3:40 pm.
Nothing by Friday, Aug 28 at 3:40 pm. It let this go.
Expired, went ahead
wait 4 hours, then proceed
No answer. It went ahead.
7:00 amThe 5-litre detergent from Valley Wholesale is $55.00. Go ahead?
Sent through a card in the app on Wednesday, Aug 26 at 7:00 am.
Nothing by Wednesday, Aug 26 at 11:00 am. It went ahead as if you had said yes.
You said yes at 12:12 pm, after it had already expired.
Expired with a late answer
wait 4 hours; you said yes after 5
No answer. It let this go.
7:00 amThe 5-litre detergent from Valley Wholesale is $55.00. Go ahead?
Sent through a card in the app on Wednesday, Aug 26 at 7:00 am.
Nothing by Wednesday, Aug 26 at 11:00 am. It let this go.
You said yes at 12:12 pm, after it had already expired.
Coming up
Coming up
9:30 amGreenleaf is out of plain Cheerios. Swap for Honey Nut Cheerios (40¢ more)?
Sent through a card in the app on Monday, Aug 24 at 9:30 am.
If there is no answer by Tuesday, Aug 25 at 9:30 am, it will let this go.
When to use
- In the detail panel for any event whose decision is asked.
- Live, with onApprove/onDecline, in a real inbox.
When not to
- For events that were done or refused. Use Receipt, or the TraceEvent detail.
- As a notification toast. It is a full card.
Props
| Name | Type | Notes |
|---|---|---|
| event* | EvaluatedEvent | Must have decision.kind === "asked"; otherwise renders nothing. |
| escalation* | Escalation | From the contract, for the channel and deadline copy. |
| now* | number | The playhead. Decides whether the ask is open or answered. |
| onApprove / onDecline | () => void | Both together make the buttons live while the ask is open. |
| link / linkHref | ContractLink, string | Footer link to the governing line. |
* required
Accessibility invariants
- An article named by the heading and the action.
- The primary button is the only accent-coloured control in the product and only appears while the ask is open.
- A limit hit is a chip with a glyph and words ("$55, over $40 an order").
- What happens on no answer is always stated in text, with "go ahead anyway" in the refused tone.
Agent instructions
For anything generating UI from this system
Show an ApprovalCard when the selected event's decision.kind is "asked". Pass the contract's escalation and the same now the Timeline uses. In a replay do not pass onApprove/onDecline; the card then shows the recorded answer once now passes it. In a live inbox pass both. Never render approve/decline for a resolved ask.