Subscriptions app
This page covers the app side: the composables for your own pricing page, a middleware that guards pages by plan, the components and the ready-made pages. It is for app developers, in server mode. Set up the module first: Overview.
Composables
Both composables are auto-imported, and exported from @frigear-nu/subscriptions/composables.
usePlans(): { plans, status, loading, error, refresh } // plans sorted by rank
useSubscription(): {
subscription, plan, status, loading, loadError, isActive, cancelsAt,
has(planKey: string): boolean,
pending, error, refresh,
subscribe(planKeyOrPriceId: string, options?: { successUrl?: string, cancelUrl?: string }): Promise<CheckoutResponse>,
openPortal(returnUrl?: string): Promise<void>,
}
Both load through useCachedFetch, so their
data survives navigation. Plans are cached for five minutes, and the subscription for one minute.
loadingistrueonly while nothing is loaded yet. Render a placeholder for it, not the "no subscription" state.loadErroris the error of loading the subscription.errorandpendingbelong tosubscribeandopenPortal.subscribesends a string that starts withprice_aspriceId, and anything else asplanKey. It redirects to Stripe Checkout, or refreshes when an existing subscription was changed.openPortalredirects to the billing portal.returnUrldefaults to the current page.
Middleware
The subscription route middleware sends people without the right plan away from a page:
definePageMeta({
middleware: 'subscription',
subscription: { plans: ['member'], redirectTo: '/join' }, // both optional
})
- It redirects to
redirectTo, else to the membership page, with the original route in?redirect=. Without either target it does nothing. - Visitors and users without an active plan are redirected.
- A subscription on a price outside every configured plan has no
activePlan, so it is redirected too.
hasActiveSubscription.Components
SubscriptionPlans and SubscriptionStatus are built on @nuxt/ui and expose scoped slots.
SubscriptionPlans prop | Type | Default | Purpose |
|---|---|---|---|
locale | string | – | The formatting locale. |
currency | string | the price's | Overrides the currency for formatting. |
interval | 'day' | 'week' | 'month' | 'year' | the first price | Which price to show per plan. |
plans | string[] | all | Shows only these plan keys. |
confirmChange | boolean | false | Asks before changing an existing subscription. |
mode | 'auto' | 'list' | 'tabs' | 'auto' | auto shows tabs on small screens and cards side by side from sm up. |
highlight | string | the current plan | The plan key to emphasise. |
SubscriptionPlans emits select(plan, price). Each plan has a state: 'current', 'upgrade', 'downgrade' or
'subscribe'. A visitor who picks a plan is sent to the Users register page, with
?redirect=<membership page>?plan=<key>.
| Component | Slot | Slot props |
|---|---|---|
SubscriptionPlans | loading, empty | – |
header, badge | { plan, state } | |
price | { plan, price, formatPrice, intervalLabel } | |
features | { plan } | |
action | { plan, state, pending, select } | |
confirm | { plan, price } | |
confirm-actions | { plan, price, confirm } | |
SubscriptionStatus | header, loading, empty | – (prop locale) |
plan | { plan, label, subscription } | |
badge | { subscription, badge }, where badge is { status, label, color, icon } | |
dates | { subscription, cancelsAt, dateText } | |
actions | { manage, resubscribe, cancelling, pending } |
UsersAdminMembership (prop user, emits refresh) is the panel in the admin user tab where
staff grant and revoke a free membership.
Pages and menu
Each page you turn on in settings.pages is added at its path, unless a page already exists there.
| Page | Default path | What it shows |
|---|---|---|
| Membership | /account/membership | The current subscription, or a "No membership yet" state, then the plans. |
| Success | /account/membership/success | Checks again every 3 seconds, for about 2 minutes, until the webhook has arrived. |
| Cancel | /account/membership/cancel | A way back to the membership page. |
The pages sit under /account/**, so they use the account layout. They follow the
UX patterns for account pages.
Other modules add more when they are installed:
- Menu, with the membership page on: a Membership item (id
membership, order 15) in theaccountmenu. - Widget: a membership summary in the
account.overviewwidget area. - Widget and Admin: a Membership tab (
?tab=membership, order 10) and a Current membership card on the admin user page. They sit in theadmin.userstab area and theadmin.users.overviewwidget area. Revoking a free membership asks for confirmation first.
Next steps
- Subscriptions server API – check the plan on the server, where it is enforced.
- Subscriptions reference – change the texts of the pages and components.