274
A billing state for a declined renewal that names the card and the reason, counts down the grace period, and puts the fixes right there: retry, switch to a saved card or add a new one.
akapayment·billing·declined
Run this in any project set up for the shadcn CLI. It copies the Payment Failed source into your components folder, so the code is yours to change.
npx shadcn@latest add https://devl.dev/r/payment-failed.jsonImport it and render it. Every prop has a typed default, so it works straight away, and you pass your own data when you’re ready.
import { PaymentFailed } from "@/components/payment-failed";
export default function Page() {
return <PaymentFailed />;
}A free React component in the Empty & Error collection, written in TypeScript with Tailwind CSS on coss ui. MIT licensed.
Read from the Payment Failed source. Everything is optional unless it says required.
| Prop | Type | Default |
|---|---|---|
| amount | number | 96 |
| currency | string | "USD" |
| plan | string | "Team" |
| cards | PaymentCard[] | defaultCards |
| failedCardId | string | "visa" |
| declineReason | string | "insufficient funds" |
| declineCode | string | "insufficient_funds" |
| declineExplanation | string | — |
| declines | Record<string, string> | { visa: "Declined Oct 28: insufficient funds" } |
| graceUntil | string | "Nov 4" |
| graceSeconds | number | 6 * 86400 + 9 * 3600 + 41 * 60 + 12 |
| graceTotalSeconds | number | 7 * 86400 |
| billingEmail | string | "billing@ridgeline.app" |
| status | "due" | "processing" | "paid" | "due" |
| paidCardId | string | — |
| reasons | string[] | defaultReasons |
| onPay | (cardId: string) => void | — |
| onAddCard | (details: NewCardDetails) => void | — |
| className | string | — |