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:
27
frontend/src/api/billing.ts
Normal file
27
frontend/src/api/billing.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import apiClient from './client'
|
||||
import type { BillingStateApiResponse, BillingStatePayload } from '@/types'
|
||||
|
||||
/**
|
||||
* Single boundary where the snake_case backend payload is transformed
|
||||
* into the camelCase shape used by the rest of the frontend.
|
||||
*
|
||||
* Keeping the transform here means the store, hooks, and components
|
||||
* never see snake_case keys.
|
||||
*/
|
||||
function transformBillingState(raw: BillingStateApiResponse): BillingStatePayload {
|
||||
return {
|
||||
subscription: raw.subscription ?? null,
|
||||
planBilling: raw.plan_billing ?? null,
|
||||
planLimits: raw.plan_limits ?? {},
|
||||
enabledFeatures: raw.enabled_features ?? {},
|
||||
}
|
||||
}
|
||||
|
||||
export const billingApi = {
|
||||
async getState(): Promise<BillingStatePayload> {
|
||||
const response = await apiClient.get<BillingStateApiResponse>('/billing/state')
|
||||
return transformBillingState(response.data)
|
||||
},
|
||||
}
|
||||
|
||||
export default billingApi
|
||||
Reference in New Issue
Block a user