Skip to content

feat: adjust the express checkout flow to support both stripe and ady… - #8

Open
rebzden-centra wants to merge 39 commits into
mainfrom
stripe-ec
Open

feat: adjust the express checkout flow to support both stripe and ady…#8
rebzden-centra wants to merge 39 commits into
mainfrom
stripe-ec

Conversation

@rebzden-centra

Copy link
Copy Markdown
Contributor

…en payment providers

@vercel

vercel Bot commented Mar 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
centra-commerce Ready Ready Preview Jul 21, 2026 9:40am

Request Review

Comment thread src/features/checkout/components/Payment/AdyenExpressCheckoutErrorBoundary.tsx Outdated
Comment thread src/features/checkout/components/Payment/ExpressCheckout.tsx
Comment thread src/features/checkout/queries.ts Outdated
},
});

const { error, paymentIntent } = result as (typeof result) & { paymentIntent?: PaymentIntent };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
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')} />

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
.filter((line): line is NonNullable<typeof line> => line !== null)
.filter((line) => line !== null)

Comment on lines +16 to 22
export function fetchCheckout(): Promise<CheckoutData> {
return sendWidgetData({ expressCheckout: false });
}

export function fetchExpressCheckout(): Promise<CheckoutData> {
return sendWidgetData({ expressCheckout: true });
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

szymonfe and others added 4 commits June 29, 2026 09:34
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
szymonfe and others added 2 commits July 20, 2026 09:16
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
szymonfe and others added 2 commits July 21, 2026 11:19
…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>
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.

4 participants