@flopay/react 1.1.4 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1759,12 +1759,14 @@ function SplitCardFormInner({
1759
1759
  showApplePay = true,
1760
1760
  showGooglePay = true,
1761
1761
  layout = "default",
1762
+ theme,
1762
1763
  buttonsTheme,
1763
1764
  buttonsStyles: buttonsStylesOverride,
1765
+ appearance: appearanceOverride,
1764
1766
  cardButtonContent,
1765
1767
  cardBackButtonContent,
1766
1768
  cardTitleContent,
1767
- showSecurityFooter = true,
1769
+ showSecurityFooter: _showSecurityFooter,
1768
1770
  onButtonClick,
1769
1771
  onBeforeButtonClick,
1770
1772
  enableAVS: enableAVSProp,
@@ -1839,8 +1841,9 @@ function SplitCardFormInner({
1839
1841
  }, [paypalDirectRetry]);
1840
1842
  const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
1841
1843
  const displayError = externalError ?? error;
1844
+ const themeBundle = (0, import_react8.useMemo)(() => (0, import_shared6.resolveTheme)(theme), [theme]);
1842
1845
  const bStyles = (0, import_react8.useMemo)(() => {
1843
- const base = (0, import_shared5.resolveButtonsLayoutTheme)(buttonsTheme);
1846
+ const base = themeBundle?.buttonsLayout ?? (0, import_shared5.resolveButtonsLayoutTheme)(buttonsTheme);
1844
1847
  if (!buttonsStylesOverride) return base;
1845
1848
  return {
1846
1849
  ...base,
@@ -1852,7 +1855,8 @@ function SplitCardFormInner({
1852
1855
  submitButton: { ...base.submitButton, ...buttonsStylesOverride.submitButton },
1853
1856
  title: { ...base.title, ...buttonsStylesOverride.title }
1854
1857
  };
1855
- }, [buttonsTheme, buttonsStylesOverride]);
1858
+ }, [themeBundle, buttonsTheme, buttonsStylesOverride]);
1859
+ const appearance = appearanceOverride ?? themeBundle?.appearance;
1856
1860
  const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
1857
1861
  const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
1858
1862
  const isSelfContained = !onTokenizedBody;
@@ -2380,17 +2384,24 @@ function SplitCardFormInner({
2380
2384
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
2381
2385
  }
2382
2386
  const isButtons = layout === "buttons";
2383
- const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
2384
- const cardBg = isButtons ? bStyles.cardFormContainer?.backgroundColor ?? "white" : "#EDEDFF";
2385
- const cardInputBg = isButtons ? bStyles.cardInputBackground ?? "white" : "white";
2387
+ const appearanceVars = appearance?.variables;
2388
+ const SDK_DEFAULT_WHITES = /* @__PURE__ */ new Set(["#FFFFFF", "#ffffff", "#fff", "#FFF", "white"]);
2389
+ const appearanceColorBg = appearanceVars?.colorBackground;
2390
+ const themedWrapperBg = appearanceColorBg && !SDK_DEFAULT_WHITES.has(appearanceColorBg) ? appearanceColorBg : void 0;
2391
+ const resolvedBorder = bStyles.cardInputBorder ?? (isButtons ? "#e5e7eb" : "#A4A4FF");
2392
+ const cardBg = bStyles.cardFormContainer?.backgroundColor ?? themedWrapperBg ?? (isButtons ? "white" : "#EDEDFF");
2393
+ const cardInputBg = bStyles.cardInputBackground ?? appearanceVars?.colorBackground ?? "white";
2386
2394
  const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
2387
2395
  const hideTitle = isEmptySlotContent(cardTitleContent);
2388
- const nameInputOverrides = isButtons ? bStyles.nameInput : void 0;
2389
- const resolvedInputFontSize = bStyles.cardInputFontSize ?? toCssSize(nameInputOverrides?.fontSize) ?? "16px";
2390
- const resolvedInputFontFamily = typeof nameInputOverrides?.fontFamily === "string" ? nameInputOverrides.fontFamily : "Poppins, sans-serif";
2396
+ const nameInputOverrides = bStyles.nameInput;
2397
+ const resolvedInputFontSize = bStyles.cardInputFontSize ?? toCssSize(nameInputOverrides?.fontSize) ?? appearanceVars?.fontSizeBase ?? "16px";
2398
+ const resolvedInputFontFamily = typeof nameInputOverrides?.fontFamily === "string" ? nameInputOverrides.fontFamily : appearanceVars?.fontFamily ?? "Poppins, sans-serif";
2391
2399
  const resolvedInputFontWeight = toCssWeight(nameInputOverrides?.fontWeight) ?? 400;
2392
- const resolvedInputColor = bStyles.cardInputColor ?? (typeof nameInputOverrides?.color === "string" ? nameInputOverrides.color : void 0) ?? "#262833";
2400
+ const resolvedInputColor = bStyles.cardInputColor ?? (typeof nameInputOverrides?.color === "string" ? nameInputOverrides.color : void 0) ?? appearanceVars?.colorText ?? "#262833";
2393
2401
  const resolvedPlaceholderColor = bStyles.cardInputPlaceholderColor ?? "#9ca3af";
2402
+ const resolvedBorderRadius = appearanceVars?.borderRadius ?? "8px";
2403
+ const resolvedPrimaryColor = appearanceVars?.colorPrimary ?? "#4A49FF";
2404
+ const resolvedTitleColor = appearanceVars?.colorText ?? "#262833";
2394
2405
  const sharedInputTypography = {
2395
2406
  fontSize: resolvedInputFontSize,
2396
2407
  fontFamily: resolvedInputFontFamily,
@@ -2420,12 +2431,14 @@ function SplitCardFormInner({
2420
2431
  invalid: { color: "#ef4444" }
2421
2432
  }
2422
2433
  };
2434
+ const containerOverrides = bStyles.cardFormContainer ?? {};
2435
+ const containerPadding = containerOverrides.padding ?? (isButtons ? "0" : "1rem");
2436
+ const containerRadius = containerOverrides.borderRadius ?? resolvedBorderRadius;
2423
2437
  const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2424
2438
  backgroundColor: cardBg,
2425
- borderRadius: "8px",
2426
- padding: isButtons ? "0" : "1rem",
2427
- ...isButtons ? bStyles.cardFormContainer : {},
2428
- ...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
2439
+ borderRadius: containerRadius,
2440
+ ...containerOverrides,
2441
+ padding: containerPadding,
2429
2442
  ...sharedInputPlaceholderVars
2430
2443
  }, children: [
2431
2444
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
@@ -2489,7 +2502,14 @@ function SplitCardFormInner({
2489
2502
  ...bStyles.title
2490
2503
  }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
2491
2504
  ] }),
2492
- !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
2505
+ !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2506
+ textAlign: "center",
2507
+ fontWeight: 600,
2508
+ fontSize: "1.1rem",
2509
+ padding: "0.5rem 0",
2510
+ color: resolvedTitleColor,
2511
+ ...bStyles.title
2512
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
2493
2513
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2494
2514
  backgroundColor: cardInputBg,
2495
2515
  border: `1px solid ${resolvedBorder}`,
@@ -2746,7 +2766,7 @@ function SplitCardFormInner({
2746
2766
  display: "flex",
2747
2767
  alignItems: "center",
2748
2768
  gap: "0.5rem",
2749
- ...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
2769
+ ...bStyles.errorBanner ? bStyles.errorBanner : {}
2750
2770
  }, children: [
2751
2771
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2752
2772
  displayError
@@ -2761,29 +2781,19 @@ function SplitCardFormInner({
2761
2781
  width: "100%",
2762
2782
  padding: "0.875rem",
2763
2783
  marginTop: "1rem",
2764
- backgroundColor: "#4A49FF",
2784
+ backgroundColor: resolvedPrimaryColor,
2765
2785
  color: "white",
2766
2786
  border: "none",
2767
- borderRadius: "8px",
2768
- fontSize: isButtons && bStyles.submitButtonFontSize ? bStyles.submitButtonFontSize : "1rem",
2787
+ borderRadius: resolvedBorderRadius,
2788
+ fontSize: bStyles.submitButtonFontSize ?? "1rem",
2769
2789
  fontWeight: 600,
2770
2790
  cursor: !formReady || isSubmitting ? "not-allowed" : "pointer",
2771
2791
  opacity: !formReady || isSubmitting ? 0.5 : 1,
2772
- ...isButtons ? bStyles.submitButton : {}
2792
+ ...bStyles.submitButton
2773
2793
  },
2774
2794
  children: isSubmitting ? "PROCESSING..." : submitLabel
2775
2795
  }
2776
- ),
2777
- !isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2778
- backgroundColor: "#EFF9F0",
2779
- borderRadius: "8px",
2780
- padding: "0.75rem",
2781
- marginTop: "0.75rem",
2782
- textAlign: "center",
2783
- fontSize: "0.85rem",
2784
- fontWeight: 600,
2785
- color: "#7DAD3A"
2786
- }, children: "Secure Card Checkout" })
2796
+ )
2787
2797
  ] });
2788
2798
  if (layout === "buttons") {
2789
2799
  const isButtonsView = viewState === "buttons" || viewState === "expanding";
@@ -3300,105 +3310,6 @@ async function processSavedPaymentForMode({
3300
3310
  }
3301
3311
  );
3302
3312
  }
3303
- async function processSavedPaymentWithIntent({
3304
- billingApiUrl,
3305
- sessionId,
3306
- session,
3307
- paymentMethodId,
3308
- flopay,
3309
- returnUrl
3310
- }) {
3311
- const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
3312
- if (!customerEmail) {
3313
- throw Object.assign(
3314
- new import_shared7.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
3315
- param: "email"
3316
- }),
3317
- { checkoutMethod: "card" }
3318
- );
3319
- }
3320
- const api = new import_js3.PaymentAPI(billingApiUrl);
3321
- const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
3322
- sessionId,
3323
- customerEmail,
3324
- paymentMethodId
3325
- ));
3326
- const intentJson = await intentResponse.json().catch(() => null);
3327
- if (!intentResponse.ok) {
3328
- const intentError = buildFloPayApiError(
3329
- intentJson,
3330
- "Failed to create payment intent."
3331
- );
3332
- throw Object.assign(
3333
- intentError,
3334
- { checkoutMethod: "card" }
3335
- );
3336
- }
3337
- const intentClientSecret = getRedirectTokenFromProcessResponse(intentJson, {
3338
- requirePaymentIntentClientSecret: true
3339
- });
3340
- if (!intentClientSecret) {
3341
- throw Object.assign(
3342
- new import_shared7.FloPayError("No client secret in payment intent response.", "api_error"),
3343
- { checkoutMethod: "card" }
3344
- );
3345
- }
3346
- const confirmResult = await flopay.confirmCardPayment({
3347
- clientSecret: intentClientSecret,
3348
- paymentMethodId
3349
- });
3350
- if (confirmResult.error) {
3351
- throw Object.assign(
3352
- confirmResult.error,
3353
- { checkoutMethod: "card" }
3354
- );
3355
- }
3356
- const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
3357
- const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
3358
- rawProvider,
3359
- intentClientSecret
3360
- );
3361
- const confirmedPaymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
3362
- const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
3363
- if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
3364
- throw Object.assign(
3365
- new import_shared7.FloPayError(
3366
- `Unfortunately, your payment could not be processed. Please try again using a different payment method or contact your bank for assistance. If the issue persists, feel free to reach out to us for support.`,
3367
- "api_error",
3368
- {
3369
- code: confirmResult.status === "requires_action" ? "authentication_required" : void 0
3370
- }
3371
- ),
3372
- { checkoutMethod: "card" }
3373
- );
3374
- }
3375
- const followUp = await processSavedPaymentForMode({
3376
- billingApiUrl,
3377
- sessionId,
3378
- session,
3379
- tokenizedData: {
3380
- id: confirmedPaymentMethodId,
3381
- type: "card",
3382
- threeDSecureActionResultTokenId: confirmedPaymentIntentId
3383
- },
3384
- returnUrl
3385
- });
3386
- const finalResult = followUp.type === "success" ? followUp.result : await handleSavedPaymentRedirectResult(followUp, {
3387
- flopay,
3388
- paypalFlopay: null,
3389
- attempt3DS: true,
3390
- billingApiUrl,
3391
- sessionId,
3392
- session,
3393
- returnUrl
3394
- });
3395
- return {
3396
- ...finalResult,
3397
- paymentIntentId: finalResult.paymentIntentId ?? confirmedPaymentIntentId,
3398
- paymentMethodId: finalResult.paymentMethodId ?? confirmedPaymentMethodId,
3399
- checkoutMethod: finalResult.checkoutMethod ?? "card"
3400
- };
3401
- }
3402
3313
  async function handleSavedPaymentRedirectResult(redirectResult, {
3403
3314
  flopay,
3404
3315
  paypalFlopay,
@@ -3720,7 +3631,7 @@ function FloPayCheckout({
3720
3631
  sessionId: sessionIdProp,
3721
3632
  createSession: createSessionParams,
3722
3633
  billingApiUrl,
3723
- appearance,
3634
+ appearance: appearanceOverride,
3724
3635
  locale,
3725
3636
  loading: loadingNode,
3726
3637
  error: errorNode,
@@ -3735,12 +3646,13 @@ function FloPayCheckout({
3735
3646
  showGooglePay = true,
3736
3647
  debug = false,
3737
3648
  layout,
3649
+ theme,
3738
3650
  buttonsTheme,
3739
3651
  buttonsStyles,
3740
3652
  cardButtonContent,
3741
3653
  cardBackButtonContent,
3742
3654
  cardTitleContent,
3743
- showSecurityFooter = true,
3655
+ showSecurityFooter: _showSecurityFooter,
3744
3656
  onButtonClick,
3745
3657
  onBeforeButtonClick,
3746
3658
  enableAVS,
@@ -3755,6 +3667,8 @@ function FloPayCheckout({
3755
3667
  onSessionCompleted
3756
3668
  }) {
3757
3669
  const resolvedBillingUrl = (0, import_shared8.resolveBillingApiUrl)(billingApiUrl);
3670
+ const themeBundle = (0, import_react9.useMemo)(() => (0, import_shared8.resolveTheme)(theme), [theme]);
3671
+ const appearance = appearanceOverride ?? themeBundle?.appearance;
3758
3672
  const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
3759
3673
  const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
3760
3674
  const [unified, setUnified] = (0, import_react9.useState)(null);
@@ -4517,6 +4431,7 @@ function FloPayCheckout({
4517
4431
  showPayPal,
4518
4432
  showApplePay,
4519
4433
  showGooglePay,
4434
+ theme,
4520
4435
  buttonsTheme,
4521
4436
  buttonsStyles,
4522
4437
  cardButtonContent,
@@ -4661,12 +4576,13 @@ function FloPayCheckout({
4661
4576
  showApplePay,
4662
4577
  showGooglePay,
4663
4578
  layout,
4579
+ theme,
4664
4580
  buttonsTheme,
4665
4581
  buttonsStyles,
4582
+ appearance,
4666
4583
  cardButtonContent,
4667
4584
  cardBackButtonContent,
4668
4585
  cardTitleContent,
4669
- showSecurityFooter,
4670
4586
  onButtonClick,
4671
4587
  onBeforeButtonClick,
4672
4588
  enableAVS,
@@ -4723,6 +4639,7 @@ function InterimButtonsView({
4723
4639
  showPayPal,
4724
4640
  showApplePay,
4725
4641
  showGooglePay,
4642
+ theme,
4726
4643
  buttonsTheme,
4727
4644
  buttonsStyles: stylesOverride,
4728
4645
  cardButtonContent,
@@ -4736,8 +4653,9 @@ function InterimButtonsView({
4736
4653
  setShowCardForm(cardOpen);
4737
4654
  }
4738
4655
  }, [cardOpen, isCardOpenControlled]);
4656
+ const themeBundle = (0, import_react9.useMemo)(() => (0, import_shared8.resolveTheme)(theme), [theme]);
4739
4657
  const bStyles = (0, import_react9.useMemo)(() => {
4740
- const base = (0, import_shared8.resolveButtonsLayoutTheme)(buttonsTheme);
4658
+ const base = themeBundle?.buttonsLayout ?? (0, import_shared8.resolveButtonsLayoutTheme)(buttonsTheme);
4741
4659
  if (!stylesOverride) return base;
4742
4660
  return {
4743
4661
  ...base,
@@ -4749,7 +4667,7 @@ function InterimButtonsView({
4749
4667
  submitButton: { ...base.submitButton, ...stylesOverride.submitButton },
4750
4668
  title: { ...base.title, ...stylesOverride.title }
4751
4669
  };
4752
- }, [buttonsTheme, stylesOverride]);
4670
+ }, [themeBundle, buttonsTheme, stylesOverride]);
4753
4671
  const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
4754
4672
  height: h,
4755
4673
  borderRadius: 8,
@@ -5448,7 +5366,6 @@ var import_js7 = require("@flopay/js");
5448
5366
  var import_shared11 = require("@flopay/shared");
5449
5367
  var import_jsx_runtime10 = require("react/jsx-runtime");
5450
5368
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
5451
- var PAYPAL_RESUME_STORAGE_KEY2 = "flopay_automatic_payment_button_resume";
5452
5369
  function sleep2(ms) {
5453
5370
  return new Promise((resolve) => setTimeout(resolve, ms));
5454
5371
  }
@@ -5461,9 +5378,6 @@ function coerceError(err, fallbackMessage) {
5461
5378
  "api_error"
5462
5379
  );
5463
5380
  }
5464
- function canUseStorage2() {
5465
- return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
5466
- }
5467
5381
  function shouldShowFallbackCheckout(error, sessionId) {
5468
5382
  if (!sessionId) return false;
5469
5383
  if (error.type === "validation_error") return false;
@@ -5472,47 +5386,6 @@ function shouldShowFallbackCheckout(error, sessionId) {
5472
5386
  }
5473
5387
  return true;
5474
5388
  }
5475
- function readPayPalResumeState2() {
5476
- if (!canUseStorage2()) return null;
5477
- try {
5478
- const raw = window.sessionStorage.getItem(PAYPAL_RESUME_STORAGE_KEY2);
5479
- if (!raw) return null;
5480
- return JSON.parse(raw);
5481
- } catch {
5482
- return null;
5483
- }
5484
- }
5485
- function persistPayPalResumeState2(state) {
5486
- if (!canUseStorage2()) return;
5487
- try {
5488
- window.sessionStorage.setItem(PAYPAL_RESUME_STORAGE_KEY2, JSON.stringify(state));
5489
- } catch (error) {
5490
- console.warn("[FloPayAutomaticPaymentButton] Failed to persist PayPal resume state.", error);
5491
- }
5492
- }
5493
- function clearPayPalResumeState2() {
5494
- if (!canUseStorage2()) return;
5495
- try {
5496
- window.sessionStorage.removeItem(PAYPAL_RESUME_STORAGE_KEY2);
5497
- } catch (error) {
5498
- console.warn("[FloPayAutomaticPaymentButton] Failed to clear PayPal resume state.", error);
5499
- }
5500
- }
5501
- function clearPayPalRedirectParams2() {
5502
- if (typeof window === "undefined") return;
5503
- const url = new URL(window.location.href);
5504
- const keys = ["payment_intent", "payment_intent_client_secret", "redirect_status"];
5505
- let changed = false;
5506
- for (const key of keys) {
5507
- if (url.searchParams.has(key)) {
5508
- url.searchParams.delete(key);
5509
- changed = true;
5510
- }
5511
- }
5512
- if (changed) {
5513
- window.history.replaceState({}, "", url.toString());
5514
- }
5515
- }
5516
5389
  function resolveCreateSessionDraft(props) {
5517
5390
  if (props.createSession) {
5518
5391
  return {
@@ -5539,8 +5412,10 @@ function resolveCreateSessionDraft(props) {
5539
5412
  function FloPayAutomaticPaymentButton({
5540
5413
  sessionId,
5541
5414
  createSession,
5542
- paymentMethodId,
5543
- checkoutMethod,
5415
+ // Deprecated — accepted for back-compat and silently ignored. Backend
5416
+ // resolves the customer's latest payment method server-side.
5417
+ paymentMethodId: _deprecatedPaymentMethodId,
5418
+ checkoutMethod: _deprecatedCheckoutMethod,
5544
5419
  clientId,
5545
5420
  items,
5546
5421
  subscriptions,
@@ -5552,6 +5427,7 @@ function FloPayAutomaticPaymentButton({
5552
5427
  utmMetadata,
5553
5428
  billingApiUrl,
5554
5429
  locale,
5430
+ theme,
5555
5431
  buttonsTheme,
5556
5432
  buttonsStyles: stylesOverride,
5557
5433
  onSuccess,
@@ -5597,20 +5473,7 @@ function FloPayAutomaticPaymentButton({
5597
5473
  const [overlayStatus, setOverlayStatus] = (0, import_react12.useState)(null);
5598
5474
  const [overlayError, setOverlayError] = (0, import_react12.useState)(null);
5599
5475
  const [fallbackSession, setFallbackSession] = (0, import_react12.useState)(null);
5600
- const automaticPaymentToken = (0, import_react12.useMemo)(
5601
- () => paymentMethodId ? {
5602
- id: paymentMethodId,
5603
- // Saved PayPal `user_payment_method` records are submitted with
5604
- // `type: 'paypal'` so the backend routes the upsell through the
5605
- // direct PayPal gateway's vaulted-token flow. Card and wallet PMs
5606
- // continue to use `type: 'card'`.
5607
- type: checkoutMethod === "paypal" ? "paypal" : "card",
5608
- ...checkoutMethod === "paypal" ? { isPaypal: true } : {}
5609
- } : void 0,
5610
- [checkoutMethod, paymentMethodId]
5611
- );
5612
5476
  const isMountedRef = (0, import_react12.useRef)(true);
5613
- const resumeAttemptedRef = (0, import_react12.useRef)(false);
5614
5477
  const fallbackSessionRef = (0, import_react12.useRef)(fallbackSession);
5615
5478
  const onSuccessRef = (0, import_react12.useRef)(onSuccess);
5616
5479
  const onErrorRef = (0, import_react12.useRef)(onError);
@@ -5691,10 +5554,6 @@ function FloPayAutomaticPaymentButton({
5691
5554
  });
5692
5555
  }
5693
5556
  try {
5694
- let paymentResult = null;
5695
- const redirectResult = getRedirectResultFromCheckoutProcessError(apiResult.autoProcessingError);
5696
- const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
5697
- const shouldRetryPayPalClientSide = checkoutMethod === "paypal" && automaticPaymentToken?.isPaypal === true && options?.fromCreateSession === true;
5698
5557
  if (apiResult.autoProcessingPending) {
5699
5558
  const api = new import_js7.PaymentAPI(resolvedBillingUrl);
5700
5559
  const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
@@ -5707,50 +5566,14 @@ function FloPayAutomaticPaymentButton({
5707
5566
  });
5708
5567
  }
5709
5568
  await showSuccess({
5710
- result: {
5711
- status: "succeeded",
5712
- paymentMethodId: paymentMethodId ?? void 0,
5713
- checkoutMethod
5714
- },
5569
+ result: { status: "succeeded" },
5715
5570
  session: completedSession,
5716
5571
  sessionId: completedSession.id || resolvedSessionId,
5717
5572
  autoCompleted: false
5718
5573
  });
5719
5574
  return;
5720
5575
  }
5721
- if (redirectResult) {
5722
- const {
5723
- publishableKey,
5724
- paypalPublishableKey
5725
- } = resolveSavedPaymentPublishableKeys(apiResult);
5726
- if (redirectResult.type === "paypal_redirect_required" && publishableKey) {
5727
- persistPayPalResumeState2({
5728
- sessionId: session.id || resolvedSessionId,
5729
- publishableKey,
5730
- paypalPublishableKey
5731
- });
5732
- }
5733
- const {
5734
- flopay,
5735
- paypalFlopay
5736
- } = await loadSavedPaymentProviders({
5737
- publishableKey,
5738
- paypalPublishableKey,
5739
- billingApiUrl: resolvedBillingUrl,
5740
- locale
5741
- });
5742
- paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
5743
- flopay,
5744
- paypalFlopay,
5745
- attempt3DS: true,
5746
- billingApiUrl: resolvedBillingUrl,
5747
- sessionId: session.id || resolvedSessionId,
5748
- session
5749
- });
5750
- if (redirectResult.type === "paypal_redirect_required") {
5751
- clearPayPalResumeState2();
5752
- }
5753
- } else if (apiResult.autoProcessingError && !shouldRetryPayPalClientSide) {
5576
+ if (apiResult.autoProcessingError) {
5754
5577
  throw checkoutProcessErrorToFloPayError(
5755
5578
  apiResult.autoProcessingError,
5756
5579
  "Automatic payment failed. Please try again.",
@@ -5758,7 +5581,22 @@ function FloPayAutomaticPaymentButton({
5758
5581
  checkoutMethod: apiResult.autoProcessingError.checkoutMethod
5759
5582
  }
5760
5583
  );
5761
- } else if (shouldTreatCreateSessionFlowAsServerAutoAttempt && !shouldRetryPayPalClientSide) {
5584
+ }
5585
+ if (options?.fromCreateSession && apiResult.autoProcessingAttempted === true) {
5586
+ throw checkoutProcessErrorToFloPayError(
5587
+ {
5588
+ type: "unknown",
5589
+ message: "Automatic payment failed. Please try again."
5590
+ },
5591
+ "Automatic payment failed. Please try again."
5592
+ );
5593
+ }
5594
+ const result = await processSavedPaymentForMode({
5595
+ billingApiUrl: resolvedBillingUrl,
5596
+ sessionId: resolvedSessionId ?? session.id,
5597
+ session
5598
+ });
5599
+ if (result.type !== "success") {
5762
5600
  throw checkoutProcessErrorToFloPayError(
5763
5601
  {
5764
5602
  type: "unknown",
@@ -5766,121 +5604,16 @@ function FloPayAutomaticPaymentButton({
5766
5604
  },
5767
5605
  "Automatic payment failed. Please try again."
5768
5606
  );
5769
- } else {
5770
- const result = await processSavedPaymentForMode({
5771
- billingApiUrl: resolvedBillingUrl,
5772
- sessionId: resolvedSessionId ?? session.id,
5773
- session,
5774
- tokenizedData: automaticPaymentToken
5775
- });
5776
- paymentResult = result.type === "success" ? result.result : null;
5777
- if (result.type !== "success") {
5778
- const {
5779
- publishableKey,
5780
- paypalPublishableKey
5781
- } = resolveSavedPaymentPublishableKeys(apiResult);
5782
- if (result.type === "paypal_redirect_required" && publishableKey) {
5783
- persistPayPalResumeState2({
5784
- sessionId: session.id || resolvedSessionId,
5785
- publishableKey,
5786
- paypalPublishableKey
5787
- });
5788
- }
5789
- const {
5790
- flopay,
5791
- paypalFlopay
5792
- } = await loadSavedPaymentProviders({
5793
- publishableKey,
5794
- paypalPublishableKey,
5795
- billingApiUrl: resolvedBillingUrl,
5796
- locale
5797
- });
5798
- paymentResult = await handleSavedPaymentRedirectResult(result, {
5799
- flopay,
5800
- paypalFlopay,
5801
- attempt3DS: true,
5802
- billingApiUrl: resolvedBillingUrl,
5803
- sessionId: session.id || resolvedSessionId,
5804
- session
5805
- });
5806
- if (result.type === "paypal_redirect_required") {
5807
- clearPayPalResumeState2();
5808
- }
5809
- }
5810
5607
  }
5811
5608
  await showSuccess({
5812
- result: paymentResult ? {
5813
- ...paymentResult,
5814
- paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId,
5815
- checkoutMethod: paymentResult.checkoutMethod ?? checkoutMethod
5816
- } : {
5817
- status: "succeeded",
5818
- paymentMethodId: paymentMethodId ?? void 0,
5819
- checkoutMethod
5820
- },
5609
+ result: result.result,
5821
5610
  session,
5822
5611
  sessionId: session.id || resolvedSessionId,
5823
5612
  autoCompleted: false
5824
5613
  });
5825
5614
  } catch (err) {
5826
- let floPayErr = normalizeSavedPaymentError(err);
5615
+ const floPayErr = normalizeSavedPaymentError(err);
5827
5616
  const fallbackSessionId = session.id || resolvedSessionId;
5828
- const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && apiResult.autoProcessingAttempted === true;
5829
- if (!shouldTreatCreateSessionFlowAsServerAutoAttempt && floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
5830
- try {
5831
- const {
5832
- publishableKey,
5833
- paypalPublishableKey
5834
- } = resolveSavedPaymentPublishableKeys(apiResult);
5835
- const {
5836
- flopay
5837
- } = await loadSavedPaymentProviders({
5838
- publishableKey,
5839
- paypalPublishableKey,
5840
- billingApiUrl: resolvedBillingUrl,
5841
- locale
5842
- });
5843
- if (!flopay) {
5844
- throw new import_shared11.FloPayError(
5845
- "Stripe is not available for 3DS authentication.",
5846
- "api_error",
5847
- { code: "authentication_required" }
5848
- );
5849
- }
5850
- const paymentResult = await processSavedPaymentWithIntent({
5851
- billingApiUrl: resolvedBillingUrl,
5852
- sessionId: fallbackSessionId,
5853
- session,
5854
- paymentMethodId: automaticPaymentToken.id,
5855
- flopay
5856
- });
5857
- await showSuccess({
5858
- result: {
5859
- ...paymentResult,
5860
- paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId,
5861
- checkoutMethod: paymentResult.checkoutMethod ?? checkoutMethod
5862
- },
5863
- session,
5864
- sessionId: fallbackSessionId,
5865
- autoCompleted: false
5866
- });
5867
- return;
5868
- } catch (intentRecoveryErr) {
5869
- floPayErr = normalizeSavedPaymentError(intentRecoveryErr);
5870
- }
5871
- }
5872
- const inResumeWindow = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent_client_secret") && !!readPayPalResumeState2();
5873
- if (floPayErr.code === "payment_intent_unexpected_state" && inResumeWindow) {
5874
- return;
5875
- }
5876
- const isSilentFallbackCase = (floPayErr.code === "paypal_requires_user_interaction" || floPayErr.code === "payment_intent_unexpected_state") && shouldShowFallbackCheckout(floPayErr, fallbackSessionId) && !!fallbackSessionId && isMountedRef.current;
5877
- if (isSilentFallbackCase) {
5878
- setFallbackSession({
5879
- sessionId: fallbackSessionId,
5880
- errorMessage: ""
5881
- });
5882
- return;
5883
- }
5884
5617
  await showError(floPayErr, {
5885
5618
  emitDecline: true,
5886
5619
  method: floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD
@@ -5893,10 +5626,6 @@ function FloPayAutomaticPaymentButton({
5893
5626
  }
5894
5627
  }
5895
5628
  }, [
5896
- checkoutMethod,
5897
- locale,
5898
- automaticPaymentToken,
5899
- paymentMethodId,
5900
5629
  resolvedBillingUrl,
5901
5630
  showError,
5902
5631
  showSuccess
@@ -5943,8 +5672,7 @@ function FloPayAutomaticPaymentButton({
5943
5672
  }
5944
5673
  try {
5945
5674
  const result = await api.createAndFetchSession({
5946
- ...createSessionDraft,
5947
- ...automaticPaymentToken ? { tokenizedData: automaticPaymentToken } : {}
5675
+ ...createSessionDraft
5948
5676
  });
5949
5677
  await processResolvedSession(result, result.data.session?.id ?? null, {
5950
5678
  fromCreateSession: true
@@ -5999,146 +5727,16 @@ function FloPayAutomaticPaymentButton({
5999
5727
  const handleFallbackDecline = (0, import_react12.useCallback)((decline) => {
6000
5728
  onDeclineRef.current?.(decline);
6001
5729
  }, []);
6002
- (0, import_react12.useEffect)(() => {
6003
- if (typeof window === "undefined" || resumeAttemptedRef.current) {
6004
- return;
6005
- }
6006
- const params = new URLSearchParams(window.location.search);
6007
- const clientSecret = params.get("payment_intent_client_secret");
6008
- if (!clientSecret) {
6009
- return;
6010
- }
6011
- const resumeState = readPayPalResumeState2();
6012
- if (!resumeState) {
6013
- return;
6014
- }
6015
- resumeAttemptedRef.current = true;
6016
- void (async () => {
6017
- setIsProcessing(true);
6018
- setOverlayError(null);
6019
- setOverlayStatus("processing");
6020
- try {
6021
- if (params.get("redirect_status") === "failed") {
6022
- throw Object.assign(
6023
- new import_shared11.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
6024
- { checkoutMethod: "paypal" }
6025
- );
6026
- }
6027
- const {
6028
- flopay,
6029
- paypalFlopay
6030
- } = await loadSavedPaymentProviders({
6031
- publishableKey: resumeState.publishableKey,
6032
- paypalPublishableKey: resumeState.paypalPublishableKey,
6033
- billingApiUrl: resolvedBillingUrl,
6034
- locale
6035
- });
6036
- const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
6037
- if (!paypalStripe) {
6038
- throw Object.assign(
6039
- new import_shared11.FloPayError("PayPal is not available.", "api_error"),
6040
- { checkoutMethod: "paypal" }
6041
- );
6042
- }
6043
- const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
6044
- if (error) {
6045
- throw Object.assign(
6046
- new import_shared11.FloPayError(
6047
- error.message ?? "Failed to retrieve PayPal payment status.",
6048
- "api_error",
6049
- { code: error.code }
6050
- ),
6051
- { checkoutMethod: "paypal" }
6052
- );
6053
- }
6054
- const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
6055
- if (!paymentIntent || resultStatus === "failed") {
6056
- throw Object.assign(
6057
- new import_shared11.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
6058
- { checkoutMethod: "paypal" }
6059
- );
6060
- }
6061
- const paymentMethodId2 = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
6062
- if (!resumeState.sessionId) {
6063
- throw Object.assign(
6064
- new import_shared11.FloPayError("Missing session id on PayPal resume.", "api_error"),
6065
- { checkoutMethod: "paypal" }
6066
- );
6067
- }
6068
- const api = new import_js7.PaymentAPI(resolvedBillingUrl);
6069
- const sessionResult = await api.getUnifiedCheckoutSession(resumeState.sessionId);
6070
- let resumeSession = sessionResult.data.session;
6071
- if (!resumeSession) {
6072
- throw Object.assign(
6073
- new import_shared11.FloPayError("Could not load session to capture PayPal payment.", "api_error"),
6074
- { checkoutMethod: "paypal" }
6075
- );
6076
- }
6077
- let finalResultStatus = resultStatus;
6078
- if (resumeSession.status !== "complete") {
6079
- const processResult = await processSavedPaymentForMode({
6080
- billingApiUrl: resolvedBillingUrl,
6081
- sessionId: resumeState.sessionId,
6082
- session: resumeSession,
6083
- tokenizedData: {
6084
- id: paymentMethodId2 ?? paymentIntent.id,
6085
- type: "card",
6086
- threeDSecureActionResultTokenId: paymentIntent.id,
6087
- isPaypal: true
6088
- }
6089
- });
6090
- if (processResult.type !== "success") {
6091
- throw Object.assign(
6092
- new import_shared11.FloPayError("Failed to finalize PayPal payment.", "api_error"),
6093
- { checkoutMethod: "paypal" }
6094
- );
6095
- }
6096
- finalResultStatus = processResult.result.status;
6097
- try {
6098
- const refreshed = await api.getUnifiedCheckoutSession(resumeState.sessionId);
6099
- if (refreshed.data.session) {
6100
- resumeSession = refreshed.data.session;
6101
- }
6102
- } catch {
6103
- }
6104
- }
6105
- await showSuccess({
6106
- result: {
6107
- status: finalResultStatus,
6108
- paymentIntentId: paymentIntent.id,
6109
- paymentMethodId: paymentMethodId2,
6110
- checkoutMethod: "paypal"
6111
- },
6112
- session: resumeSession,
6113
- sessionId: resumeState.sessionId,
6114
- autoCompleted: false
6115
- });
6116
- } catch (err) {
6117
- const floPayErr = normalizeSavedPaymentError(err);
6118
- await showError(floPayErr, {
6119
- emitDecline: true,
6120
- method: floPayErr.checkoutMethod ?? "paypal"
6121
- });
6122
- } finally {
6123
- clearPayPalResumeState2();
6124
- clearPayPalRedirectParams2();
6125
- if (isMountedRef.current) {
6126
- setOverlayStatus(null);
6127
- setOverlayError(null);
6128
- setIsProcessing(false);
6129
- }
6130
- }
6131
- })();
6132
- }, [locale, resolvedBillingUrl, showError, showSuccess]);
5730
+ const themeBundle = (0, import_react12.useMemo)(() => (0, import_shared11.resolveTheme)(theme), [theme]);
6133
5731
  const bStyles = (0, import_react12.useMemo)(() => {
6134
- const base = (0, import_shared11.resolveButtonsLayoutTheme)(buttonsTheme);
5732
+ const base = themeBundle?.buttonsLayout ?? (0, import_shared11.resolveButtonsLayoutTheme)(buttonsTheme);
6135
5733
  if (!stylesOverride) return base;
6136
5734
  return {
6137
5735
  ...base,
6138
5736
  ...stylesOverride,
6139
5737
  cardButton: { ...base.cardButton, ...stylesOverride.cardButton }
6140
5738
  };
6141
- }, [buttonsTheme, stylesOverride]);
5739
+ }, [themeBundle, buttonsTheme, stylesOverride]);
6142
5740
  const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
6143
5741
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
6144
5742
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -6235,9 +5833,12 @@ function FloPayAutomaticPaymentButton({
6235
5833
  sessionId: fallbackSession.sessionId,
6236
5834
  checkoutMode: "full",
6237
5835
  billingApiUrl: resolvedBillingUrl,
5836
+ locale,
5837
+ theme,
5838
+ buttonsTheme,
5839
+ buttonsStyles: stylesOverride,
6238
5840
  initialErrorMessage: fallbackSession.errorMessage,
6239
5841
  cardTitleContent: null,
6240
- showSecurityFooter: false,
6241
5842
  onComplete: handleFallbackComplete,
6242
5843
  onError: handleFallbackError,
6243
5844
  onDecline: handleFallbackDecline