Payment Method
Saved cards and accounts, with expiry warnings. A card expiring next month is the reason a subscription fails, and saying so before it does is the entire value of this list.
src/components/ui/payment-method.tsxAbout
From the component's own source, where it was written.
Saved payment methods, selectable, with one default.
An expired or expiring card is flagged in the list rather than at checkout. The card that fails is almost always one that expired months ago and nobody told the customer — surfacing it here is the difference between a prompt and an involuntary churn.
Only the last four digits are ever rendered. A saved method has no business holding a full PAN client-side, and a component that accepts one invites somebody to pass it.
Install
npx astralyx-ui add payment-method
Usage
import { PaymentMethodList } from '@/components/ui/payment-method'
<PaymentMethodList methods={methods} selected={id} onSelect={setId} />Composer
Change the props and the source below follows.
<PaymentMethodList methods={methods} selected={id} onSelect={setId} />Examples
Selectable list
<PaymentMethodList methods={methods} selected={id} onSelect={setId} onSetDefault={makeDefault} onRemove={remove} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
PaymentMethodList
Saved payment methods, selectable, with one default.
Extends Omit<ComponentProps<'div'>, 'onSelect'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| methods | PaymentMethod[] | required | { id, kind, last4, brand?, expiry?, holder?, isDefault? }. Only ever the last four digits — a full PAN has no business reaching a component. |
| selected | string | — | — |
| onSelect | (id: string) => void | — | Omit any of them to render that affordance not at all, rather than disabled. |
| onRemove | (id: string) => void | — | Omit any of them to render that affordance not at all, rather than disabled. |
| onSetDefault | (id: string) => void | — | Omit any of them to render that affordance not at all, rather than disabled. |
| now | Date | — | Reference point for expiry, so tests are not time-dependent. |
| emptyLabel | ReactNode | 'No payment methods' | — |
| defaultLabel | ReactNode | 'Default' | Badge on the method charged by default. |
| expiredLabel | ReactNode | 'Expired' | — |
| expiringLabel | ReactNode | 'Expiring soon' | Badge on a card within 60 days of expiry. |
| expiresLabel | ReactNode | 'Expires' | Precedes the MM/YY expiry. |
| setDefaultLabel | ReactNode | 'Make default' | — |
| removeLabel | ReactNode | 'Remove' | — |
| expiredNote | ReactNode | 'An expired card will decline. Update it before the next charge.' | Note shown when any card has already expired. Pass null to drop it. |
Functions
| Function | Signature | Description |
|---|---|---|
| expiryState | (expiry: string | undefined, now: Date) => 'none' | 'expired' | 'expiring' | 'ok' | Expired, or inside the window where the issuer reissues. |
Types
PaymentMethod
| Field | Type | Description |
|---|---|---|
| id | string | — |
| kind | 'card' | 'bank' | 'wallet' | — |
| last4 | string | Last four digits or account suffix. Never the full number. |
| brand? | ReactNode | — |
| expiry? | string | Cards within 60 days of expiry are flagged, expired ones are marked and cannot be made default. |
| holder? | ReactNode | — |
| isDefault? | boolean | — |