Billing and team
Screens for the paying workspace: plan and invoices, usage and charges, and members with roles and seats.
Installation & usage
npx @youj/cli add app-billingAlso installs alert, app-page, async-button, badge, button, card, counter, dialog, field, icon-credit-card, icon-download, icon-lock, icon-refresh, input, presence-list, radio-group, reveal, skeleton, table, textarea, toast, toggle-group, typography, youj-core, youj-ui-core.
The CLI copies the block to blocks/app/billing.tsx with every component it uses, so it’s yours to edit.
Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:
'use client'
import { Billing, type BillingProps } from '@/blocks/app/billing'
export function BillingView({ plans, cycle, card, invoices }: Pick<BillingProps, 'plans' | 'cycle' | 'card' | 'invoices'>) {
return (
<Billing
plans={plans}
cycle={cycle}
card={card}
invoices={invoices}
copy={{ title: 'Billing' }}
onRetry={() => {
// your code
}}
onChangePlan={async (change) => {
// await your API here; the block shows progress until it settles
}}
onUpdatePayment={async (input) => {
// await your API here; the block shows progress until it settles
}}
/>
)
}Description
Give customers a place to manage their plan, payment details and invoices, with a dialog for changing plan and another for the card.
Give customers a place to manage their plan, payment details and invoices, with a dialog for changing plan and another for the card.
Show what the workspace used and what it was charged: a date range, a project filter and Export CSV over the total, the days as stacked bars by SKU with a tooltip, and a table of SKUs with usage against the allowance as a ring, the part past it, the charge and a total row.
Show what the workspace used and what it was charged: a date range, a project filter and Export CSV over the total, the days as stacked bars by SKU with a tooltip, and a table of SKUs with usage against the allowance as a ring, the part past it, the charge and a total row.
Manage workspace members, roles and pending invitations with seat usage in view.
Manage workspace members, roles and pending invitations with seat usage in view.
Code
Billing, the Billing story: the files youj add writes.
blocks/app
Reference
Props26 props, 5 types
Props
| Prop | Type | |
|---|---|---|
theme | ThemeInputA theme to force on the block. Default: none, so it inherits the app's (YoujProvider or a ThemeScope around it). | – |
embedded | booleanA page in your app's frame: the shared page header (AppPage) and the frame's gutter, across the whole width, with no top bar of its own. default true | true |
failedPayment | booleanStarts with September's charge failed, which raises the payment alert. Only applies to the demo invoices. default true | true |
brand | { name: string; logo?: ReactNode }The product in the top bar. default Tern | Tern |
plans | BillingPlan[]The plans on offer, cheapest first. default Starter, Growth, Scale | Starter, Growth, Scale |
plan | stringThe current plan's id, to control it. Pair with | – |
defaultPlan | stringThe current plan's id at first, when uncontrolled. default 'growth' | 'growth' |
cycle | BillingCycle'monthly''annual'The billing cycle, to control it. | – |
defaultCycle | BillingCycle'monthly''annual'The billing cycle at first, when uncontrolled. default 'monthly' | 'monthly' |
seats | numberSeats the workspace pays for. default 14 | 14 |
card | BillingCardThe card on file. default a Visa ending 4242 | a Visa ending 4242 |
invoices | BillingInvoice[]Every invoice, newest first; one with status | – |
details | BillingInfoWho invoices are addressed to. default Tern Analytics GmbH | Tern Analytics GmbH |
locale | stringFormats every amount. Default: the app's locale (YoujProvider's | – |
currency | stringThe ISO currency of every amount. default 'USD' | 'USD' |
headingLevel | 1 | 2 | 3The page title's level; section headings sit one below. default 1 | 1 |
loading | booleanShows skeleton rows in place of the invoices while they load. default false | false |
error | ReactNodeA load failure, shown under the title with a Retry button when | – |
onRetry | () => voidCalled from the error's Retry button. | – |
empty | ReactNodeReplaces the empty state shown when there are no invoices. default `copy.emptyInvoices` | `copy.emptyInvoices` |
copy | Partial<BillingCopy>Any of the page's strings, to rewrite or translate. | – |
onChangePlan | (change: { plan: BillingPlan; cycle: BillingCycle }) => Promise<unknown> | unknownSwitches plan or cycle; resolve when done, throw to show the error in the dialog. Default: a demo wait. | – |
onUpdatePayment | (input: BillingCardInput) => Promise<BillingCard | void> | BillingCard | voidSaves a new card from the form; resolve with the card on file (or nothing to show what was typed). Default: a demo wait. | – |
onRetryPayment | (invoice: BillingInvoice) => Promise<unknown> | unknownRetries a failed charge; resolve when paid, throw when declined. Default: a demo wait. | – |
onDownloadInvoice | (invoice: BillingInvoice) => Promise<unknown> | unknownFetches an invoice's PDF; resolve when it's ready. Default: a demo wait. | – |
onSaveDetails | (details: BillingInfo) => Promise<unknown> | unknownSaves the billing details; resolve when saved, throw to show the error. Default: a demo wait. | – |
BillingPlan
| Prop | Type | |
|---|---|---|
idRequired | string | – |
nameRequired | string | – |
blurbRequired | string | – |
priceRequired | numberPer seat per month, billed monthly, in the block's currency. Annual billing takes two months off. | – |
BillingCard
| Prop | Type | |
|---|---|---|
brandRequired | stringe.g. | – |
last4Required | string | – |
expMonthRequired | number | – |
expYearRequired | numberFour digits. | – |
nameRequired | string | – |
BillingCardInput
| Prop | Type | |
|---|---|---|
nameRequired | string | – |
numberRequired | string | – |
expiryRequired | string
| – |
cvcRequired | string | – |
BillingInvoice
| Prop | Type | |
|---|---|---|
idRequired | string | – |
numberRequired | stringAs printed, e.g. | – |
dateRequired | stringAs it reads, e.g. | – |
periodRequired | stringWhat it covers, e.g. | – |
amountRequired | numberIn the block's currency; negative for a credit. | – |
statusRequired | BillingInvoiceStatus'paid''due''failed''refunded' | – |
BillingInfo
| Prop | Type | |
|---|---|---|
companyRequired | string | – |
emailRequired | string | – |
addressRequired | string | – |
taxIdRequired | string | – |
Strings98 keys for copy
Strings
copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.
titledescriptionbreadcrumbplanBadgeerrorTitleretryfailedTitlefailedDescriptionretryPaymentchargingpaiddeclinedpaidToastchargedTocurrentPlanmonthlyannualchangePlanperSeatperMonthseatsnextInvoicenextInvoiceDaterenewsrenewsDatebilledMonthlybilledYearlychangePlanTitlechangePlanDescriptionbillingCycleannualSavingplanLabelcurrentBadgeperSeatMonthnoChangechangeFromcancelupdatingplanUpdatedconfirmChangeplanChangedinvoicesHeadinginvoicesLabelshowInvoicesfilterAllfilterPaidfilterOpennothingOpenemptyInvoicesloadinginvoiceColumndateColumnperiodColumnstatusColumnamountColumnactionsColumnstatusretryChargeretryFordownloadAspreparingdownloadedpaymentTitlepaymentDescriptionupdateendingIncardSummaryexpirescardUpdatedupdateCardTitleupdateCardDescriptionnameOnCardcardNumbercardNumberPlaceholderexpiryexpiryPlaceholdercvccvcPlaceholdernameErrornumberErrorexpiryErrorcvcErrorprocessorNotesavingcardSavedsaveCarddetailsTitledetailsDescriptioncompanyinvoiceEmailaddresstaxIdemailErrorresetsavedsaveDetailsdetailsSaveddetailsSavedNoteBuilt from18 components
Accessibilitylandmarks, dialogs, tables, status
Accessibility
The screens are a main with a header and labelled sections. The dialogs (change plan, payment method, invite) trap focus and close with Escape; payment errors appear in an alert and a plan change is announced in a live region. The members table has a label, a member’s role is a select labelled with their name, and each member’s actions are a menu labelled the same way. Seat usage is a labelled meter. Usage and charges names its chart and gives the same days as a table for screen readers; focus the chart and the arrow keys walk the days, opening the tooltip, and each SKU row says its usage and whether it is over the allowance in words, with the ring only decorative. Links and buttons are real a and button elements with the kit’s focus ring.