Skip to content

feat: add crypto payment options to dashboard Stripe modal (CPL-274)#314

Merged
GTC6244 merged 1 commit into
mainfrom
feature/cpl-274-add-crypto-payment-options-in-the-stripe-modal-in-the
May 21, 2026
Merged

feat: add crypto payment options to dashboard Stripe modal (CPL-274)#314
GTC6244 merged 1 commit into
mainfrom
feature/cpl-274-add-crypto-payment-options-in-the-stripe-modal-in-the

Conversation

@GTC6244
Copy link
Copy Markdown
Contributor

@GTC6244 GTC6244 commented Apr 24, 2026

Summary

Switches the Add Funds modal in the dashboard from Stripe's Card Element to the Payment Element, which auto-renders whichever methods are enabled on the Stripe account (card + crypto: USDC, USDP, ETH, SOL). Backend billing endpoints already support crypto — this is a frontend-only change.

Linear: CPL-274

What changed

  • lit-static/dapps/dashboard/index.html — Billing modal split into a two-step flow: amount selector + Continue (step 1), then Payment Element mount point + Back/Pay (step 2). stripe-card-element renamed to stripe-payment-element.
  • lit-static/dapps/dashboard/billing.js — Rewrote the payment flow. Continue creates the PaymentIntent and mounts elements({ clientSecret }).create('payment'). Pay calls stripe.confirmPayment({ elements, confirmParams: { return_url }, redirect: 'if_required' }) — card stays inline, crypto redirects to the wallet flow. Exports new handleBillingReturn() that detects ?payment_intent=…&redirect_status=… on page load, calls the backend confirm_payment endpoint, and strips the query params.
  • lit-static/dapps/dashboard/app.js — Imports and invokes handleBillingReturn() from the setOnAuthReady callback so the crypto-redirect return is processed once the API key is loaded.

Why

The existing modal used elements.create('card') + confirmCardPayment(), which is card-only and doesn't surface Stripe's crypto options. The Payment Element approach is a minimal frontend refactor that unlocks card + crypto in one UI — no backend changes needed.

Pre-Landing Review

No blocking issues found.

  • Security/data safety: return_url is built from window.location.origin + window.location.pathname (no user input). Status display uses textContent (no XSS surface). No new credentials/tokens exposed.
  • Error handling: handleContinue, handlePay, and handleBillingReturn all wrap network calls in try/catch. confirmPayment-backend failure preserves the prior "card charged, credit pending" fallback. URL params stripped before confirm_payment call so reloads don't retrigger.
  • Edge cases checked: double-click on Continue/Pay (buttons disabled in-flight, re-enabled in finally); amount change mid-flow (Back fully unmounts the element, next Continue creates a fresh intent); repeated handleBillingReturn calls (URL cleaned first, subsequent fires no-op); Stripe account without crypto enabled (Payment Element gracefully shows card only).

Test plan

Requires a dev backend with Stripe test keys and a Stripe account that has crypto payment methods enabled.

  • Open dashboard → Add Funds → amount step shows with dropdown + Continue
  • Pick $5 → Continue → Payment Element renders with card (and crypto tabs if enabled)
  • Back button returns to amount step (unmounts element; next Continue creates a fresh PaymentIntent)
  • Card path: submit test card 4242… → stays inline → balance updates → modal closes
  • Crypto path: select crypto → connect wallet → approve → redirects out → returns to dashboard root → auth ready fires → handleBillingReturn calls confirm_payment → overview shows "Credits added" → balance refreshes
  • Confirm that an unauthenticated user hitting ?payment_intent=… silently strips the params without processing (no crash, no retry loop)

Notes

  • No unit tests exist for the vanilla-JS dashboard module — node --check passes on both JS files.
  • Crypto docs at docs/management/crypto.mdx already describe the intended user flow and reference the Payment Element approach this PR implements.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the dashboard “Add Funds” modal to use Stripe’s Payment Element so enabled payment methods (including crypto) can be used in a single flow, and adds return-handling for redirect-based methods.

Changes:

  • Replaced the Card Element UI with a two-step modal (amount → payment) and a Payment Element mount point.
  • Reworked the billing flow to create a PaymentIntent on “Continue” and confirm via stripe.confirmPayment(..., redirect: 'if_required') on “Pay”.
  • Added handleBillingReturn() and wired it into the auth-ready callback to confirm redirect-based payments on return.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
lit-static/dapps/dashboard/index.html Updates modal markup for a two-step flow and Payment Element container/buttons.
lit-static/dapps/dashboard/billing.js Implements Payment Element flow, confirm logic, and redirect-return processing.
lit-static/dapps/dashboard/app.js Calls handleBillingReturn() after auth is ready so redirect returns are processed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lit-static/dapps/dashboard/billing.js Outdated
Comment thread lit-static/dapps/dashboard/billing.js Outdated
Comment thread lit-static/dapps/dashboard/index.html Outdated
Copy link
Copy Markdown
Contributor

@glitch003 glitch003 left a comment

Choose a reason for hiding this comment

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

looks solid

@GTC6244 GTC6244 changed the base branch from next to main May 21, 2026 17:46
Switch the Add Funds modal from Stripe Card Element to Payment Element,
which auto-renders any payment methods enabled on the Stripe account
(card and supported crypto: USDC, USDP, ETH, SOL). Backend billing
endpoints already support crypto, so this is frontend-only.

Flow: user picks an amount → Continue creates a PaymentIntent and mounts
the Payment Element with its client_secret → Pay calls
stripe.confirmPayment with redirect: 'if_required'. Card stays inline;
crypto methods redirect to the wallet/Stripe-hosted flow and return to
the dashboard with ?payment_intent=...&redirect_status=...; the new
handleBillingReturn() picks that up on auth-ready, calls
confirm_payment, and refreshes the balance.

Carries forward the session-protection patterns the rest of billing.js
adopted in CPL-285/286: every handler captures billingAuthKey() up
front, uses ensureAbortController(), re-checks the captured key after
each await, attaches walletAuthHeader via billingRequestOptions in
sovereign mode, swallows AbortError, and evicts the wallet-auth cache
on auth errors. Also primes the wallet-auth signature when the modal
opens in sovereign mode so the user only sees one popup per session.

Payment Element is configured with
fields.billingDetails.address='never' so the address form is never
rendered; confirmPayment passes a default billing country in
payment_method_data so card AVS still works.

handleBillingReturn treats Stripe's `processing` redirect_status as a
non-error and shows "credits will appear once settled"; only `failed`,
`canceled`, and `requires_*` surface as errors. The
confirmPayment-backend-failure fallback now shows the pending-credit
message via the top-level status banner so closeBillingModal() can't
swallow it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@GTC6244 GTC6244 force-pushed the feature/cpl-274-add-crypto-payment-options-in-the-stripe-modal-in-the branch from 73da663 to ba9fcb6 Compare May 21, 2026 17:51
@GTC6244 GTC6244 merged commit a16af57 into main May 21, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants