Attempts selector
An attempts filter for cards showing approval-rate / conversion metrics. "First attempts" ignores retries (only the first charge of each payment); "All attempts" includes retries in the denominator. Canonical placement is inside the ChartCard `actions` slot on cards where retry logic changes the interpretation of the metric.
Anatomy
A DropdownMenu whose trigger is a small outline Button showing the currently selected label + a CaretDown. The menu has exactly two items: First attempts / All attempts. Controlled — the caller owns the state.
- 1Trigger
shadcn <Button variant="outline" size="sm"> with the active label on the left and a CaretDown icon (Phosphor, weight light) on the right. h-8 default, rounded-md, uses the standard outline hover (bg-accent).
- 2Menu
shadcn <DropdownMenuContent align="end"> anchored to the right edge of the trigger. Two <DropdownMenuItem>s that fire onChange with 'first' or 'all'.
- 3Labels (overridable)
Defaults are the Yuno canon copy 'First attempts' / 'All attempts'. Pass `labels={{ first, all }}` to override for a specific locale. Prefer defaults unless you have a translation constraint.
Recipes
Just the selector on its own. Rare on its own — it always attaches to something showing an approval-rate metric — but useful for a top-of-page filter row when the whole page's data reacts to First / All attempts.
const [value, setValue] = React.useState<AttemptsValue>("first");
<AttemptsSelector value={value} onChange={setValue} />The canonical placement: inside the `actions` slot on cards where retry logic changes the interpretation of the metric (Daily cards approval rate by provider, Daily approval rate by provider + PM). Compatible with `viewPaymentsFilter` — the selector and the drilldown work independently.
Daily cards approval rate by provider
<ChartCard
title="Daily cards approval rate by provider"
actions={<AttemptsSelector value={value} onChange={setValue} />}
>
<MultiLineChart series={series} />
</ChartCard>Override the default English labels via the `labels` prop. Only do this when the surface renders the selector in a non-English locale where a translation is mandatory — otherwise stay on defaults for consistency with the rest of the Yuno Dashboard.
<AttemptsSelector
value={value}
onChange={setValue}
labels={{ first: "Solo primer intento", all: "Todos los intentos" }}
/>Import
Copy this import line at the top of the file where you compose this molecule.
import { AttemptsSelector, type AttemptsValue } from "@/components/patterns/attempts-selector";Props
Everything else is forwarded to the underlying elements via ...props.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | 'first' | 'all' (required) | — | Current selection. Controlled — the caller owns state. |
| onChange | (v: 'first' | 'all') => void (required) | — | Fires when the user picks a different option. |
| labels | { first?: string; all?: string } | — | Optional label overrides. Defaults to the Yuno canon copy ("First attempts" / "All attempts"). Use only when your surface renders the selector in a non-English locale. |
| className | string | — | Extra classes on the trigger Button. |
Related
Cross-links to the atoms this molecule composes and sibling patterns.
- Chart cardCanonical host — the selector goes in the `actions` slot on approval-rate cards.
- Dropdown menuThe underlying primitive. If you need a bigger menu or more options, drop the selector and compose DropdownMenu directly.
- ButtonThe trigger is a shadcn <Button variant="outline" size="sm">. Match the same variant + size when placing controls next to it.