fix(billing): redirect free workspace to checkout instead of alerting#44
Merged
Conversation
A free workspace clicking "Connect repository" hit `POST /api/workspaces/:id/projects`, got a 402 with `requiresCheckout: true`, but the dialog only surfaced a toast — the plan-selection modal was never opened, leaving the user stuck. Make 402 + `requiresCheckout` open the plan modal globally via a shared `usePlanModal` composable, triggered from `resolveApiError` as a side effect so every existing catch site (ConnectRepoDialog, useChat, useBranches, useContentEditor, useMembers, ContentCollectionView…) routes locked workspaces through the checkout flow rather than dying as a toast. - New `usePlanModal` composable backed by `useState` for SSR-safe shared state - `resolveApiError` opens the modal on 402 + `requiresCheckout` - `default` layout mounts `PlanSelectionModal` (was only on `workspace` layout) - `workspace` layout switches to the same global state for consistency - `ConnectRepoDialog` closes its own dialog on 402 so the modal lands on top
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
POST /api/workspaces/:id/projectsand the server correctly returned402 { requiresCheckout: true }— butConnectRepoDialogonly surfaced atoast.error, never opened the plan-selection modal. User saw an alert and got stuck.useChat,useBranches,useContentEditor,useMembers,ContentCollectionView, etc. all funnel API errors throughresolveApiError → toast.error. A billing-locked workspace (trial_expired/grace_expired/canceled_expired) emitted byserver/middleware/03.billing.tswould silently toast across the app.usePlanModalcomposable —useState-backed global open state.resolveApiErroropens the modal as a side effect when status is402+requiresCheckout. All existing catch sites now route locked workspaces through checkout for free.defaultlayout mountsOrganismsPlanSelectionModal(previously only mounted inworkspacelayout / settings panels /error.vue).workspacelayout swaps its localplanModalOpenref for the shared composable soTrialBanner+ middleware 402s drive the same modal.ConnectRepoDialogcloses its own dialog on402 + requiresCheckoutso the plan modal lands cleanly instead of stacking.Why this is the right shape
resolveApiErroris already the single client-side entry point for API errors. Adding the side effect there (instead of patching every composable or introducing a custom$fetchinstance) keeps the change small and ensures any new call site that follows the existing pattern is covered without extra wiring.Test plan
PlanSelectionModal(not a toast). The repo dialog is closed.hasManagedBillingis false → modal is not mounted; UI degrades to existing toast behavior.