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:
51
frontend/src/types/billing.ts
Normal file
51
frontend/src/types/billing.ts
Normal 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>
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user