feat: adjust the express checkout flow to support both stripe and ady… - #8
feat: adjust the express checkout flow to support both stripe and ady…#8rebzden-centra wants to merge 39 commits into
Conversation
…en payment providers
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
2040bae to
5953951
Compare
| }, | ||
| }); | ||
|
|
||
| const { error, paymentIntent } = result as (typeof result) & { paymentIntent?: PaymentIntent }; |
There was a problem hiding this comment.
According to docs, return type is dependant on redirect argument and default is 'always'. We should probably just remove the manual redirect and type assertion
There was a problem hiding this comment.
Don't you want to extract types / utils / form component to different files?
| const { lines } = data; | ||
|
|
||
| if (lines.length === 0) { | ||
| const filteredLines = lines.filter((line): line is LineFragment => !!line); |
There was a problem hiding this comment.
| const filteredLines = lines.filter((line): line is LineFragment => !!line); | |
| const filteredLines = lines.filter((line) => !!line); |
| /> | ||
| )} | ||
| </div> | ||
| <CheckoutSummary language={language} market={market} summary={t('server:checkout.summary')} /> |
There was a problem hiding this comment.
Can we move summary translation to checkout namespace?
Or alternatively, keep that part out of CheckoutSummary?
<div className="sticky top-20 mx-auto flex w-100 flex-col gap-8 lg:mx-0">
<div>
<h2 className="text-3xl font-medium">{t('server:checkout.summary')}</h2>
<p className="text-mono-500">{t('checkout:cart.hint')}</p>
</div>
<CheckoutSummary language={language} market={market} />
</div>| const hasSubscriptionItems = lines.some((line) => line?.subscriptionId != null); | ||
| const cartTotal = checkout.totals.find((total) => total.type === 'GRAND_TOTAL')?.price.value ?? 0; | ||
| const lineItems = lines | ||
| .filter((line): line is NonNullable<typeof line> => line !== null) |
There was a problem hiding this comment.
| .filter((line): line is NonNullable<typeof line> => line !== null) | |
| .filter((line) => line !== null) |
| export function fetchCheckout(): Promise<CheckoutData> { | ||
| return sendWidgetData({ expressCheckout: false }); | ||
| } | ||
|
|
||
| export function fetchExpressCheckout(): Promise<CheckoutData> { | ||
| return sendWidgetData({ expressCheckout: true }); | ||
| } |
There was a problem hiding this comment.
Can we add some comments explaining why we do this? Maybe it's also not a bad idea to leave the old fetchCheckout commented out since that one should be used most of the time
Turbopack/SWC compiles each module in isolation and emitted a runtime import for the type, which @stripe/stripe-js does not export as a value, breaking the Vercel build. tsc erased it locally so it passed there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regenerate GraphQL types for the new add-ons schema (ProductLineWithAddons, setLineAddons) and treat it as a product line in line displays so line.bundle access stays type-safe. Unblocks the build after upstream schema drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: separate billing address form
Omitting billingAddress in setAddress left Centra's separateBillingAddress with only country/city/zipCode synced from shipping. Payment widgets then forwarded that partial address to paymentInstructions, which failed on the empty email and silently reverted the selected payment method to the default, so no Stripe payment options rendered. Mirror NativeAddressForm: when billing is same as shipping, send a copy of the shipping address with companyName/vatNumber cleared. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: always send complete billing address from Stripe address form
…checkout address The Stripe ExpressCheckoutElement's onShippingAddressChange handler called Centra's paymentInstructions mutation with the wallet's tentative shipping address. Google Pay fires that event when the wallet merely opens (with only city/state/postal/country, address1 empty), and paymentInstructions PERSISTS the address onto the selection. So opening Google Pay without paying silently overwrote the shopper's already-confirmed Address Element address, and since the standard Payment Element builds its order from the persisted selection address, the order shipped to the wallet's address instead (BUG-1 / PE-295). A preview must not mutate persisted checkout state. The handler no longer writes anything to Centra: it keeps country validation and ensureSelectionReady (so shipping-rate selection still works for buy-now) and resolves the wallet with the pre-configured shipping rates. The real, complete address is written only at confirm time (requirePaymentIntent), which runs solely when the shopper actually authorizes payment. Centra recomputes the authoritative total at confirm, so amounts stay correct. Note: the Adyen express checkout (googlePay.ts, applePay.ts) has the identical persisting pattern and is not addressed here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…en payment providers