Files
twenty/packages
Félix Malfait 6201d06141 Preload Stripe.js before the onboarding payment step (#22858)
## Context

On the plan-required onboarding step, the card form was slow to appear
because Stripe.js is loaded lazily (`@stripe/stripe-js/pure`): the
script download only started once the payment page rendered, and the
PaymentElement iframe could only boot after that.

## What this does

- Adds `usePreloadStripeForPlanRequiredStep`, called once from
`OnboardingStepLayout` (the shared layout for the authenticated
onboarding step routes), so Stripe.js is already loaded by the time the
user reaches the payment step. The hook only triggers when billing is
enabled, the workspace has no subscription yet, and a publishable key is
configured, so self-hosted instances still never contact Stripe.
- Moves the memoized loader to
`settings/billing/utils/getStripePromise.ts`, shared by
`useStripePromise` and the preload hook.
- Stops caching failed script loads: previously a rejected `loadStripe`
promise stayed in the cache forever, which would have made a failed
preload permanently break the payment form. Now a later call retries
(stripe-js re-injects the script tag on retry).
- Extracts the plan-required predicate into
`onboarding/utils/getIsPlanRequired.ts`, now shared with
`useSetNextOnboardingStatus`.

The in-app add-credit-card modal is intentionally left untouched: it has
no preceding step to preload from.

## Tests

- `getStripePromise.test.ts`: dedup per publishable key, retry after a
failed load.
- `usePreloadStripeForPlanRequiredStep.test.ts`: preloads when billing
is enabled and no subscription exists; skips when billing is disabled, a
subscription exists, or the key is missing.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01NtUN99tHPZ6bPWwpYKMbpE)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22858?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-07-13 14:30:38 +02:00
..