feat: add full billing address collection to Stripe payment forms (refs #55)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m4s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped

- Replace CardElement with PaymentElement + AddressElement in subscription forms
- Add AddressElement to donation forms for billing address collection
- Now collects: Name, Address Line 1/2, City, State, Postal Code, Country
- Card details: Card Number, Expiration, CVC
- Both desktop and mobile forms updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eric Gullickson
2026-01-18 20:58:49 -06:00
parent 0674056e7e
commit 9f6832097c
5 changed files with 218 additions and 40 deletions

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import type { StripeElementsOptions } from '@stripe/stripe-js';
import { format } from 'date-fns';
import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard';
import { MobileContainer } from '../../../shared-minimal/components/mobile/MobileContainer';
@@ -18,6 +19,12 @@ import type { BillingCycle, SubscriptionTier, SubscriptionPlan } from '../types/
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY || '');
const paymentElementsOptions: StripeElementsOptions = {
mode: 'setup',
currency: 'usd',
paymentMethodCreation: 'manual',
};
interface MobileTierCardProps {
plan: SubscriptionPlan;
billingCycle: BillingCycle;
@@ -358,7 +365,7 @@ export const SubscriptionMobileScreen: React.FC = () => {
onClose={() => !checkoutMutation.isPending && setShowPaymentDialog(false)}
title={`Upgrade to ${selectedTier && PLANS.find((p) => p.tier === selectedTier)?.name}`}
>
<Elements stripe={stripePromise}>
<Elements stripe={stripePromise} options={paymentElementsOptions}>
<PaymentMethodForm
onSubmit={handlePaymentSubmit}
isLoading={checkoutMutation.isPending}