feat(billing): add useBillingStore and /billing/state integration

T32: Single frontend source of truth for subscription / plan / feature
state. New Zustand `useBillingStore` fetches `/billing/state` (auto-fetch
on login via authStore, reset on logout), exposes `refetch` for
post-Checkout refresh, and is supported by a `useBillingPoll` hook
that re-fetches every 60s while authenticated. The new `billingApi`
client transforms the snake_case backend payload to camelCase at a
single boundary so the rest of the frontend never sees `plan_billing`
or `enabled_features`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 20:44:20 -04:00
parent 80baf89b00
commit 7a9cb4b03b
9 changed files with 330 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
/**
* Billing state types for the unified `/billing/state` endpoint.
*
* The backend returns snake_case keys (`plan_billing`, `enabled_features`);
* the API client (`frontend/src/api/billing.ts`) transforms the payload to
* camelCase before it reaches the rest of the frontend.
*/
export type SubscriptionStatus =
| 'trialing'
| 'active'
| 'past_due'
| 'canceled'
| 'incomplete'
| 'complimentary'
export interface SubscriptionState {
status: SubscriptionStatus
plan: string
/** ISO 8601 string or null */
current_period_start: string | null
/** ISO 8601 string or null */
current_period_end: string | null
cancel_at_period_end: boolean
seat_limit: number | null
has_pro_entitlement: boolean
is_paid: boolean
}
export interface PlanBillingState {
display_name: string
description: string | null
monthly_price_cents: number | null
annual_price_cents: number | null
}
/** Camel-cased billing-state payload, post-transform. */
export interface BillingStatePayload {
subscription: SubscriptionState | null
planBilling: PlanBillingState | null
planLimits: Record<string, unknown>
enabledFeatures: Record<string, boolean>
}
/** Raw snake_case payload returned by the backend. */
export interface BillingStateApiResponse {
subscription: SubscriptionState | null
plan_billing: PlanBillingState | null
plan_limits: Record<string, unknown>
enabled_features: Record<string, boolean>
}

View File

@@ -93,6 +93,14 @@ export type {
KBQuotaResponse,
} from './kbAccelerator'
export type {
SubscriptionStatus,
SubscriptionState as BillingSubscriptionState,
PlanBillingState,
BillingStatePayload,
BillingStateApiResponse,
} from './billing'
export * from './scripts'
export * from './script-builder'
export * from './integrations'