fix(billing): Prevent checkout form resetting when payment details are updated#110681
Draft
fix(billing): Prevent checkout form resetting when payment details are updated#110681
Conversation
When a free/trial user selects the Team plan during checkout and then saves their credit card, the plan selection silently resets to Business. Root cause: PR #105861 converted AMCheckout from a class component to a function component. The old componentDidUpdate only re-fetched billing config when checkoutTier changed. The new useEffect includes fetchBillingConfig in its dependency array, whose identity changes on every subscription prop update (via SubscriptionStore). This causes the effect to re-run fetchBillingConfig(), which re-initializes form data with the default Business plan for free/trial users. Fix: Two complementary defenses: 1. Add isFormInitialized ref guard inside fetchBillingConfig to prevent re-initialization of form data after the first successful load. 2. Stabilize the useEffect dependency array to [subscription.canSelfServe, checkoutTier], matching the original class component behavior.
Add tests verifying that the checkout form preserves the user's plan selection when the subscription store updates (e.g. after saving payment details). Covers: - Free user: select Team → subscription update → Team preserved - Trial user: select Team → subscription update → Team preserved - Multiple rapid subscription updates → form data preserved
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
Problem
When a free/trial user selects the Team plan during checkout and then saves their credit card, the plan selection silently resets to Business. Multiple customers reported being charged for the wrong plan.
Root cause: PR #105861 converted
AMCheckoutfrom a class component to a function component. The oldcomponentDidUpdateonly re-fetched billing config whencheckoutTierchanged. The newuseEffectincludesfetchBillingConfigin its dependency array, whose identity changes on everysubscriptionprop update (viaSubscriptionStore). This causes the effect to re-runfetchBillingConfig(), which re-initializes form data with the default Business plan for free/trial users.Fix
Two complementary defenses:
isFormInitialized): InsidefetchBillingConfig, form data initialization is wrapped in a ref guard that prevents re-initialization after the first successful load[subscription.canSelfServe, checkoutTier](primitives only), matching the original class component'scomponentDidUpdatebehaviorFollows React best practices:
rerender-dependencies: Narrow effect dependencies to primitives instead of object referencesadvanced-init-once: Ref guard for one-time initializationTest plan
Closes https://linear.app/getsentry/issue/BIL-2186/checkout-form-resets-plan-when-payment-details-are-entered