feat(ui-react): add billing & subscription management#6232
feat(ui-react): add billing & subscription management#6232
Conversation
|
/review |
|
Claude finished @gustavosbarreto's task in 3m 8s —— View job Code Review CompleteReviewed 31 files across code quality, security, testing, TypeScript/React patterns, and architecture. 2 inline issues posted (2 medium). Additional notes
If you've addressed the feedback and want a new review, tag |
7a8fe14 to
a50cf8c
Compare
|
/review |
|
Claude finished @otavio's task in 7m 6s —— View job Code Review CompleteReviewed 32 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. Summary
If you've addressed the feedback and want a new review, tag |
550a8b5 to
10d6db6
Compare
|
/review |
|
Claude finished @gustavosbarreto's task in 2m 28s —— View job Code Review CompleteReviewed 32 files across code quality, security, testing, TypeScript/React patterns, and architecture. 1 inline issue posted (1 medium). Additional notes
If you've addressed the feedback and want a new review, tag |
10d6db6 to
96bff2c
Compare
|
/review |
|
Claude finished @otavio's task in 2m 47s —— View job Code Review CompleteReviewed 32 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. Summary
If you push additional changes and want a new review, tag |
96bff2c to
1e8d224
Compare
|
/review |
|
Claude finished @gustavosbarreto's task in 5m 20s —— View job Code Review CompleteReviewed 32 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. Summary
If you push additional changes and want a new review, tag |
f0f3578 to
26d6783
Compare
|
/review |
|
Claude finished @gustavosbarreto's task in 2m 51s —— View job Code Review CompleteReviewed 32 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. Summary
If you've addressed the feedback and want a new review, tag |
Implements the full billing workstream for Cloud tenants: - New hooks/useBilling.ts: useSubscription, useCustomer, useCreateCustomer, useCreateSubscription, useAttachPaymentMethod, useDetachPaymentMethod, useSetDefaultPaymentMethod, useOpenBillingPortal (axios wrapper for /api/billing/portal) - New types/billing.ts: BillingStatus union, typed Customer, Subscription, PaymentMethod, NamespaceBilling with safe narrowing - New utils/stripeErrors.ts: Stripe error-code → user message map - New BillingSection in Settings.tsx: status badge, warning banners (past_due / unpaid / incomplete / incomplete_expired / to_cancel), Subscribe button (inactive/canceled/incomplete_expired only), Open Portal button, hash-scroll + pageshow refetch for portal return - New BillingDialog wizard (4 steps): Overview → Payment method → Review → Success; lazy-loaded to exclude Stripe from initial chunk - New BillingPayment: Stripe Elements card form, payment-method list with set-default / detach, auto-creates Stripe customer on mount - New BillingWarning: 402 device-limit dialog wired to DeviceActionDialog + ContainerActionDialog - env.ts: add stripePublishableKey to ClientConfig + in-flight promise dedup for concurrent loadConfig callers - App.tsx: /settings/billing redirect route for Stripe portal return - gen-config.sh: emit SHELLHUB_STRIPE_PUBLISHABLE_KEY into config.json - docker-compose.yml: add SHELLHUB_STRIPE_PUBLISHABLE_KEY env var Fixes: shellhub-io/team#71
Covers the billing workstream with Vitest + React Testing Library: - useBilling.test.ts: mutations (create customer/subscription, attach/detach/default PM), query enable/disable behavior, useOpenBillingPortal URL open + missing-URL error - billing.test.ts (types): toCustomer and toSubscription transforms, readNamespaceBilling safe narrowing, getSubscriptionStatus sentinel - stripeErrors.test.ts: known-code mapping + unknown-code fallback - BillingDialog.test.tsx: all 4 wizard steps, Next/Back nav, error paths (402, generic, incomplete status), pending state, live region announcements, close buttons - BillingSection.test.tsx: Subscribe/portal button visibility per status, non-owner view, warning banners, dialog open/close - BillingWarning.test.tsx: renders, confirm navigates, cancel closes - Update CreateNamespaceDialog + InvitationsMenu + Login mock getConfig to include new stripePublishableKey field in ClientConfig
26d6783 to
0aa82a8
Compare
What
Adds the full billing and subscription management surface to the React console for Cloud tenants. Cloud users can now subscribe, manage payment methods, access the Stripe Billing Portal, and see billing-status warnings — all from the Settings page.
Why
The React UI had zero billing functionality (Team #71: 0 of 7 billing tasks done). The backend (9 billing endpoints) and design system were already in place; this PR wires the UI to them.
Fixes: shellhub-io/team#71
Changes
hooks/useBilling.ts: React Query wrappers for all billing mutations and queries (
useSubscription,useCustomer,useCreateCustomer,useCreateSubscription,useAttachPaymentMethod,useDetachPaymentMethod,useSetDefaultPaymentMethod). IncludesuseOpenBillingPortalas a manual axios wrapper for/api/billing/portal, which is not in the OpenAPI spec (registered dynamically in the cloud module).types/billing.ts:
BillingStatusunion literal, typedCustomer,Subscription,PaymentMethod,NamespaceBillingwith safe narrowing functions.cvcis intentionally absent — the backend always sends the masked sentinel"xxx"and the field is never displayed.BillingSection (Settings.tsx): Status badge, per-status warning banners, Subscribe button (shown only for
inactive/canceled/incomplete_expired— statuses where no active Stripe subscription exists), and Open Portal button. Includes hash-scroll on mount for the/settings/billingreturn URL and apageshowlistener to refetch subscription state after navigating back from the Portal.BillingDialog: 4-step wizard (Overview → Payment method → Review → Success), lazy-loaded so Stripe never lands in the Settings initial chunk. Step 3 gates success on
activeortrialingstatus only —incompleteand other non-terminal states surface specific error messages rather than false positives.BillingPayment: Stripe Elements card form with payment-method list (set-default / detach). Bootstraps the Stripe customer on mount with a cancellation-safe sequential flow: refresh namespace → create customer if absent → refresh namespace again.
BillingWarning: Device-limit dialog for HTTP 402 responses, wired into
DeviceActionDialogandContainerActionDialog. Non-owners see a passive message; owners get a "Go to Billing" shortcut.env.ts: Added
stripePublishableKeytoClientConfig; fixed a concurrency bug where simultaneousloadConfig()callers could each fire a separatefetch("/config.json").App.tsx: Added
/settings/billingredirect route so the Stripe Portalreturn_url(hardcoded to that path in the backend) lands correctly.gen-config.sh / docker-compose.yml: Emit
SHELLHUB_STRIPE_PUBLISHABLE_KEYintoconfig.json.Testing
End-to-end requires
SHELLHUB_CLOUD=true,SHELLHUB_BILLING=stripe, and valid Stripe keys. Key paths to verify:4242 4242 4242 4242→ Confirm → status flips toactive.4000 0000 0000 0002and4000 0000 0000 9995should surface mapped error messages.role="alert"./settings/billingdirect navigation → Settings opens with Billing section in view.BillingWarning→ "Go to Billing" →/settings#billing.SHELLHUB_CLOUD=false): billing section not rendered.