Skip to content

refactor(billing): unify add-credits and coupon on the shared tabbed sheet - #3412

Merged
baktun14 merged 5 commits into
mainfrom
refactor/billing-unify-add-credits-sheet
Jul 13, 2026
Merged

refactor(billing): unify add-credits and coupon on the shared tabbed sheet#3412
baktun14 merged 5 commits into
mainfrom
refactor/billing-unify-add-credits-sheet

Conversation

@baktun14

@baktun14 baktun14 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Why

Closes CON-639

CON-368 introduced the redesigned tabbed "Add credits" sheet (Buy Credit + Apply Coupon) but only wired it into onboarding and the hackathon sidebar. The billing section still opened the legacy PaymentPopup modal with its own parallel purchase and coupon-redemption logic: two implementations of the same behavior that drift and double maintenance cost.

What

The sheet itself landed in #3403 and its onboarding/hackathon entry points in #3404 (both merged). This PR completes the migration by moving billing onto the shared sheet and deleting the legacy popup.

  • AccountOverview now renders the shared AddCreditsSheet instead of PaymentPopup. The ?openPayment=true deep link and the purchase confetti (PaymentSuccessAnimation) are preserved. The "Add Funds" button no longer requires a saved payment method (the sheet's new-card entry handles that case in place).
  • AddCreditsForm gains always-on saved-payment-method support: saved methods are offered in a select (default card pre-selected) with "Add new payment method" as an explicit choice; the Stripe SetupIntent is created lazily only in new-card mode; the "First-purchase match" banner is gated on isTrialing. Onboarding is unchanged, since a trialing user has no saved methods and falls through to the exact current new-card path.
  • AddCreditsSheet header description is now a prop (defaults to the free-plan copy) so billing shows neutral copy instead of "You're on the free plan…".
  • Deleted PaymentPopup.tsx (+ spec, ~1500 lines), removing the duplicated charge/coupon logic. Coupon redemption now uses the shared tab's inline feedback (no confetti on coupon, an intentional change from legacy).
  • E2E: BillingPage.submitPayment drives the sheet via the custom-amount field, covering both callers ("100" credits spec, "20" deposit flow). The "Payment Successful!" assertion still holds since purchase confetti is retained.

Billing stays gated behind auto_credit_reload; onboarding's coupon entry stays behind hackathons (unchanged).

Note: the deploy-web E2E suite (managed-wallet-credits) requires deployed-env credentials (env/.env.test) not available locally; needs a CI/release run to confirm.

Also in this PR: minimum-amount validation + new-card retry fix

Fixes CON-654

  • The trial top-up minimum default is lowered to $20 (MANAGED_WALLET_TRIAL_MIN_TOP_UP_AMOUNT, was $100): the free trial changed and the higher first-purchase minimum no longer applies. Ops note: any environment that sets this variable explicitly in Doppler overrides the code default; update/remove it there for the $20 minimum to take effect.
  • The add-credits form now validates against the wallet-provided topUpMinAmountUsd instead of a hardcoded 20, and a below-minimum amount shows an inline "Minimum amount is $X" error under the amount field instead of only silently disabling the purchase button.
  • Fixed a Stripe 400 on retry with a new card: the first submit consumes the SetupIntent via confirmSetup; if the charge then fails (decline, 402), resubmitting re-confirmed the consumed intent. The form now confirms a new card once and reuses the saved payment method on retry, surfaces the saved card in the methods select after a failure, and creates a fresh SetupIntent when "Add new payment method" is picked again.

Summary by CodeRabbit

  • New Features
    • Updated the add-funds experience to use a credits purchase sheet (including via supported billing links and the Add Funds button).
    • Added saved payment method selection with an option to add a new payment method.
    • Added support for customizing the sheet description, with a default when omitted.
  • Bug Fixes
    • Improved purchase completion handling with success feedback and automatic sheet closure.
  • UI/Validation
    • Updated top-up minimums to use dynamic minimum values and show inline validation errors; managed wallet trial default minimum now applies as 20.
  • Chores
    • Refreshed/expanded automated tests for the updated sheet and payment-method flows; removed PaymentPopup test coverage.

@baktun14
baktun14 requested a review from a team as a code owner July 10, 2026 23:43
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23075d0b-bfbc-4ef6-b5c8-612c772d899b

📥 Commits

Reviewing files that changed from the base of the PR and between faf0ed3 and b55fdf7.

📒 Files selected for processing (2)
  • apps/deploy-web/src/components/auth/EmailCodeVerify/EmailCodeVerify.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx

📝 Walkthrough

Walkthrough

The billing flow replaces PaymentPopup with AddCreditsSheet, adds saved-payment-method selection and new-card handling, supports dynamic minimum validation and customizable descriptions, updates related tests and automation, and changes the verifying-status container markup.

Changes

Credits purchase flow

Layer / File(s) Summary
Dynamic amount validation
apps/api/src/billing/config/env.config.ts, apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/*
The minimum top-up default is set to 20, and amount fields render the configured minimum and optional validation errors.
Payment method selection and submission
apps/deploy-web/src/components/billing-usage/AddCreditsForm/*
AddCreditsForm selects saved payment methods by default, supports adding a new card, conditionally creates setup intents, and submits the selected payment method.
Credits sheet description contract
apps/deploy-web/src/components/auth/AddCreditsSheet/*
AddCreditsSheet accepts an optional description and renders supplied content or the existing default text.
Account overview sheet integration
apps/deploy-web/src/components/billing-usage/AccountOverview/*, apps/deploy-web/src/components/billing-usage/PaymentPopup/*
AccountOverview opens and closes AddCreditsSheet, handles URL and button entry points, and reports successful purchases; the former PaymentPopup implementation and tests are removed.
Billing page automation integration
apps/deploy-web/tests/ui/pages/BillingPage.ts
BillingPage.submitPayment waits for AddCreditsSheetPage, fills the custom amount, and submits through the sheet helper.
Verification status markup
apps/deploy-web/src/components/auth/EmailCodeVerify/EmailCodeVerify.tsx
The verifying-status container changes from a paragraph to a div.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: stalniy, ygrishajev

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/billing-unify-add-credits-sheet

Comment @coderabbitai help to get the list of available commands.

@baktun14
baktun14 force-pushed the refactor/billing-unify-add-credits-sheet branch from 32aa590 to b28e26c Compare July 10, 2026 23:50
@baktun14
baktun14 force-pushed the feat/billing-hackathon-coupon-entrypoints branch from 5349bca to eb3535a Compare July 13, 2026 14:36
Base automatically changed from feat/billing-hackathon-coupon-entrypoints to main July 13, 2026 14:58
…sheet

Billing's AccountOverview now opens the shared AddCreditsSheet (Buy Credit +
Apply Coupon tabs) instead of the legacy PaymentPopup modal, which is deleted
along with its duplicated charge/coupon logic.

- AddCreditsForm offers saved payment methods (default pre-selected) with
  new-card entry as fallback or explicit choice; the SetupIntent is created
  lazily only in new-card mode; the first-purchase match banner is gated on
  isTrialing
- AddCreditsSheet header description is now a prop (defaults to the free-plan
  copy) so billing can show neutral copy
- The billing Add Funds button no longer requires a saved payment method; the
  ?openPayment=true deep link and the purchase confetti are preserved
- E2E BillingPage.submitPayment drives the sheet via the custom amount field

Refs CON-639
@baktun14
baktun14 force-pushed the refactor/billing-unify-add-credits-sheet branch from b28e26c to 075df0b Compare July 13, 2026 15:06
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.52941% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 72.27%. Comparing base (16165e0) to head (b55fdf7).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ts/billing-usage/AddCreditsForm/AddCreditsForm.tsx 98.18% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3412      +/-   ##
==========================================
+ Coverage   72.20%   72.27%   +0.07%     
==========================================
  Files        1158     1157       -1     
  Lines       29367    29299      -68     
  Branches     7253     7245       -8     
==========================================
- Hits        21205    21177      -28     
+ Misses       7172     7134      -38     
+ Partials      990      988       -2     
Flag Coverage Δ
api 85.59% <ø> (ø)
deploy-web 61.05% <98.52%> (+0.07%) ⬆️
log-collector 85.85% <ø> (ø)
notifications 91.44% <ø> (+0.06%) ⬆️
provider-console 81.38% <ø> (ø)
provider-inventory 85.20% <ø> (ø)
provider-proxy 86.42% <ø> (ø)
tx-signer 85.56% <ø> (ø)
Files with missing lines Coverage Δ
apps/api/src/billing/config/env.config.ts 87.50% <ø> (ø)
...omponents/auth/AddCreditsSheet/AddCreditsSheet.tsx 100.00% <100.00%> (ø)
...omponents/auth/EmailCodeVerify/EmailCodeVerify.tsx 100.00% <100.00%> (ø)
.../billing-usage/AccountOverview/AccountOverview.tsx 73.07% <100.00%> (+0.85%) ⬆️
.../AddCreditsAmountFields/AddCreditsAmountFields.tsx 100.00% <100.00%> (ø)
...ts/billing-usage/AddCreditsForm/AddCreditsForm.tsx 94.40% <98.18%> (-0.90%) ⬇️

... and 15 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx (1)

93-93: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No error state for the payment-methods query.

Only data/isLoading are destructured from usePaymentMethodsQuery(); a fetch failure silently falls back to the new-card flow with no indication to the user that their saved cards failed to load. Consider surfacing isError so users understand why their saved methods vanished rather than assuming they have none.

As per path instructions, "Focus on: ... missing loading/error states in data fetching" for apps/{deploy-web,stats-web,provider-console}/**/*.{ts,tsx}.

Also applies to: 267-288

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx`
at line 93, Update AddCreditsForm’s usePaymentMethodsQuery handling to include
its error state and surface a clear user-facing indication when saved payment
methods fail to load, rather than silently using the new-card flow. Preserve the
existing loading and successful payment-method rendering behavior.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx`:
- Line 93: Update AddCreditsForm’s usePaymentMethodsQuery handling to include
its error state and surface a clear user-facing indication when saved payment
methods fail to load, rather than silently using the new-card flow. Preserve the
existing loading and successful payment-method rendering behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 309ecc10-9604-4785-9b07-926858fee1f5

📥 Commits

Reviewing files that changed from the base of the PR and between fca5202 and 075df0b.

📒 Files selected for processing (9)
  • apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsx
  • apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsx
  • apps/deploy-web/src/components/billing-usage/AccountOverview/AccountOverview.spec.tsx
  • apps/deploy-web/src/components/billing-usage/AccountOverview/AccountOverview.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx
  • apps/deploy-web/src/components/billing-usage/PaymentPopup/PaymentPopup.spec.tsx
  • apps/deploy-web/src/components/billing-usage/PaymentPopup/PaymentPopup.tsx
  • apps/deploy-web/tests/ui/pages/BillingPage.ts
💤 Files with no reviewable changes (2)
  • apps/deploy-web/src/components/billing-usage/PaymentPopup/PaymentPopup.spec.tsx
  • apps/deploy-web/src/components/billing-usage/PaymentPopup/PaymentPopup.tsx

… card on retry

- lower the trial top-up minimum default to $20 (free trial changed)
- drive the add-credits minimum from the wallet's topUpMinAmountUsd instead
  of a hardcoded 20 and show an inline error below the amount field
- confirm a new card's SetupIntent only once: retries after a failed charge
  reuse the saved payment method instead of re-confirming the consumed
  intent (Stripe 400), surface the saved card in the methods list, and mint
  a fresh SetupIntent when a different new card is requested

Fixes CON-654

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsx`:
- Around line 76-80: Update the number input in AddCreditsAmountFields to define
an explicit fractional-compatible step, such as 0.01, alongside min={minAmount},
so values at or above fractional MANAGED_WALLET_TRIAL_MIN_TOP_UP_AMOUNT pass
native validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ab44f130-1235-4906-81c4-4a12060cb4f7

📥 Commits

Reviewing files that changed from the base of the PR and between 075df0b and 111f96d.

📒 Files selected for processing (5)
  • apps/api/src/billing/config/env.config.ts
  • apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsx
  • apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx

baktun14 added 3 commits July 13, 2026 13:48
…s load failure

- set step=0.01 on the custom-amount input so a fractional wallet minimum
  does not fail native step validation
- show a notice when the saved payment methods query errors instead of
  silently falling back to new-card entry
@baktun14
baktun14 added this pull request to the merge queue Jul 13, 2026
Merged via the queue into main with commit f1b322b Jul 13, 2026
57 checks passed
@baktun14
baktun14 deleted the refactor/billing-unify-add-credits-sheet branch July 13, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants