@flopay/react 0.4.2 → 0.4.4

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
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  CardExpiryElement: () => CardExpiryElement,
37
37
  CardNumberElement: () => CardNumberElement,
38
38
  CheckoutForm: () => CheckoutForm,
39
+ FloPayAutomaticPaymentButton: () => FloPayAutomaticPaymentButton,
39
40
  FloPayCheckout: () => FloPayCheckout,
40
41
  FloPayProvider: () => FloPayProvider,
41
42
  PayPalButton: () => PayPalButton,
@@ -141,9 +142,9 @@ function FloPayProvider({
141
142
  }
142
143
 
143
144
  // src/flopay-checkout.tsx
144
- var import_react7 = __toESM(require("react"), 1);
145
- var import_js = require("@flopay/js");
146
- var import_shared6 = require("@flopay/shared");
145
+ var import_react8 = __toESM(require("react"), 1);
146
+ var import_js2 = require("@flopay/js");
147
+ var import_shared7 = require("@flopay/shared");
147
148
 
148
149
  // src/card-button-content.tsx
149
150
  var import_react3 = require("react");
@@ -275,7 +276,7 @@ var AddressElement = createElementComponent("address", "AddressElement");
275
276
  // src/split-card-form.tsx
276
277
  var import_react_stripe_js = require("@stripe/react-stripe-js");
277
278
  var import_shared4 = require("@flopay/shared");
278
- var import_react6 = require("react");
279
+ var import_react7 = require("react");
279
280
 
280
281
  // src/hooks.ts
281
282
  var import_react5 = require("react");
@@ -300,6 +301,157 @@ function useBillingApiUrl() {
300
301
  return ctx.billingApiUrl || (0, import_shared2.resolveBillingApiUrl)();
301
302
  }
302
303
 
304
+ // src/processing-overlay.tsx
305
+ var import_react6 = require("react");
306
+ var import_jsx_runtime4 = require("react/jsx-runtime");
307
+ var PROCESSING_OVERLAY_SUCCESS_DELAY_MS = 1200;
308
+ var PROCESSING_OVERLAY_ERROR_DELAY_MS = 1500;
309
+ function ProcessingOverlay({
310
+ status,
311
+ errorMessage
312
+ }) {
313
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
314
+ "div",
315
+ {
316
+ "data-testid": "flopay-processing-overlay",
317
+ "data-status": status,
318
+ role: "dialog",
319
+ "aria-modal": "true",
320
+ style: {
321
+ position: "fixed",
322
+ inset: 0,
323
+ background: "rgba(0,0,0,0.35)",
324
+ display: "flex",
325
+ alignItems: "center",
326
+ justifyContent: "center",
327
+ zIndex: 1e3,
328
+ backdropFilter: "blur(2px)"
329
+ },
330
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
331
+ "div",
332
+ {
333
+ style: {
334
+ background: "white",
335
+ borderRadius: 12,
336
+ padding: "2rem 2.5rem",
337
+ textAlign: "center",
338
+ boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
339
+ minWidth: 240,
340
+ display: "flex",
341
+ flexDirection: "column",
342
+ alignItems: "center",
343
+ gap: 16
344
+ },
345
+ children: [
346
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { width: 48, height: 48, position: "relative" }, children: [
347
+ status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
348
+ "svg",
349
+ {
350
+ width: "48",
351
+ height: "48",
352
+ viewBox: "0 0 24 24",
353
+ fill: "none",
354
+ xmlns: "http://www.w3.org/2000/svg",
355
+ style: { animation: "flopay-spin 0.8s linear infinite" },
356
+ children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10", stroke: "#e5e7eb", strokeWidth: "3" }),
358
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 12a8 8 0 018-8v3a5 5 0 00-5 5H4z", fill: "#4A49FF" })
359
+ ]
360
+ }
361
+ ),
362
+ status === "success" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { animation: "flopay-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "11", fill: "#22c55e" }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
365
+ "path",
366
+ {
367
+ d: "M7 12.5l3 3 7-7",
368
+ stroke: "white",
369
+ strokeWidth: "2.5",
370
+ strokeLinecap: "round",
371
+ strokeLinejoin: "round",
372
+ style: {
373
+ strokeDasharray: 20,
374
+ strokeDashoffset: 20,
375
+ animation: "flopay-draw 0.4s 0.15s ease forwards"
376
+ }
377
+ }
378
+ )
379
+ ] }) }),
380
+ status === "error" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { animation: "flopay-shake 0.4s ease" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
381
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "11", fill: "#ef4444" }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
383
+ "path",
384
+ {
385
+ d: "M8 8l8 8M16 8l-8 8",
386
+ stroke: "white",
387
+ strokeWidth: "2.5",
388
+ strokeLinecap: "round",
389
+ style: {
390
+ strokeDasharray: 12,
391
+ strokeDashoffset: 12,
392
+ animation: "flopay-draw 0.3s 0.1s ease forwards"
393
+ }
394
+ }
395
+ )
396
+ ] }) })
397
+ ] }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
399
+ "span",
400
+ {
401
+ style: {
402
+ fontSize: 14,
403
+ fontWeight: 600,
404
+ letterSpacing: "0.05em",
405
+ color: status === "success" ? "#16a34a" : status === "error" ? "#dc2626" : "#374151"
406
+ },
407
+ children: [
408
+ status === "processing" && "PROCESSING...",
409
+ status === "success" && "PAYMENT SUCCESSFUL",
410
+ status === "error" && "PAYMENT FAILED"
411
+ ]
412
+ }
413
+ ),
414
+ status === "success" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
415
+ "p",
416
+ {
417
+ style: {
418
+ fontSize: 13,
419
+ color: "#6b7280",
420
+ fontWeight: 400,
421
+ maxWidth: 260,
422
+ lineHeight: 1.4,
423
+ margin: 0
424
+ },
425
+ children: "You will be automatically redirected, do not close or navigate away from this window."
426
+ }
427
+ ),
428
+ status === "error" && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
429
+ "p",
430
+ {
431
+ style: {
432
+ fontSize: 13,
433
+ color: "#6b7280",
434
+ fontWeight: 400,
435
+ maxWidth: 260,
436
+ lineHeight: 1.4,
437
+ margin: 0
438
+ },
439
+ children: errorMessage
440
+ }
441
+ ),
442
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
443
+ @keyframes flopay-spin { to { transform: rotate(360deg); } }
444
+ @keyframes flopay-pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
445
+ @keyframes flopay-draw { to { stroke-dashoffset: 0; } }
446
+ @keyframes flopay-shake { 0%,100% { transform: translateX(0); } 20%,60% { transform: translateX(-4px); } 40%,80% { transform: translateX(4px); } }
447
+ ` })
448
+ ]
449
+ }
450
+ )
451
+ }
452
+ );
453
+ }
454
+
303
455
  // src/checkout-utils.ts
304
456
  var import_shared3 = require("@flopay/shared");
305
457
  function mergeInlineSessionPatches(base, patch) {
@@ -357,7 +509,7 @@ function buildSyntheticSession(params, checkoutModeOverride) {
357
509
  },
358
510
  successUrl: params.successUrl,
359
511
  cancelUrl: params.cancelUrl,
360
- checkoutMode: params.checkoutMode ?? checkoutModeOverride ?? "full",
512
+ checkoutMode: checkoutModeOverride ?? params.checkoutMode ?? "full",
361
513
  items: (params.items ?? []).map((item, idx) => ({
362
514
  uuid: `synthetic-item-${idx}`,
363
515
  checkoutSessionId: "",
@@ -398,10 +550,22 @@ function buildDeclineEvent(method, input, overrides) {
398
550
  ...declineCode ? { declineCode } : {}
399
551
  };
400
552
  }
553
+ function resolveTokenizedPaymentMethodId(tokenizedBody) {
554
+ const candidates = [
555
+ tokenizedBody?.id,
556
+ tokenizedBody?.originalPaymentMethodId
557
+ ];
558
+ for (const candidate of candidates) {
559
+ if (typeof candidate === "string" && candidate.startsWith("pm_")) {
560
+ return candidate;
561
+ }
562
+ }
563
+ return void 0;
564
+ }
401
565
 
402
566
  // src/split-card-form.tsx
403
567
  var import_shared5 = require("@flopay/shared");
404
- var import_jsx_runtime4 = require("react/jsx-runtime");
568
+ var import_jsx_runtime5 = require("react/jsx-runtime");
405
569
  var WALLET_RESUME_KEY = "flopay_wallet_resume";
406
570
  var FLOPAY_KEYFRAMES = `
407
571
  @keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
@@ -443,7 +607,7 @@ function normalizeBeforeButtonClickError(method, err) {
443
607
  );
444
608
  }
445
609
  function FloPayKeyframes() {
446
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: FLOPAY_KEYFRAMES });
610
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: FLOPAY_KEYFRAMES });
447
611
  }
448
612
  function toCssSize(value) {
449
613
  if (typeof value === "number") return `${value}px`;
@@ -464,8 +628,8 @@ function ExpressCheckoutReadySwap({
464
628
  children
465
629
  }) {
466
630
  if (state === "unavailable") return null;
467
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
468
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
631
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
632
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
469
633
  "div",
470
634
  {
471
635
  "data-testid": placeholderTestId,
@@ -484,7 +648,7 @@ function ExpressCheckoutReadySwap({
484
648
  }
485
649
  }
486
650
  ),
487
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
488
652
  "div",
489
653
  {
490
654
  style: {
@@ -499,109 +663,9 @@ function ExpressCheckoutReadySwap({
499
663
  )
500
664
  ] });
501
665
  }
502
- function ProcessingOverlay({ status, errorMessage }) {
503
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
504
- position: "fixed",
505
- inset: 0,
506
- background: "rgba(0,0,0,0.35)",
507
- display: "flex",
508
- alignItems: "center",
509
- justifyContent: "center",
510
- zIndex: 1e3,
511
- backdropFilter: "blur(2px)"
512
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
513
- background: "white",
514
- borderRadius: 12,
515
- padding: "2rem 2.5rem",
516
- textAlign: "center",
517
- boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
518
- minWidth: 240,
519
- display: "flex",
520
- flexDirection: "column",
521
- alignItems: "center",
522
- gap: 16
523
- }, children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { width: 48, height: 48, position: "relative" }, children: [
525
- status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
526
- "svg",
527
- {
528
- width: "48",
529
- height: "48",
530
- viewBox: "0 0 24 24",
531
- fill: "none",
532
- xmlns: "http://www.w3.org/2000/svg",
533
- style: { animation: "flopay-spin 0.8s linear infinite" },
534
- children: [
535
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10", stroke: "#e5e7eb", strokeWidth: "3" }),
536
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 12a8 8 0 018-8v3a5 5 0 00-5 5H4z", fill: "#4A49FF" })
537
- ]
538
- }
539
- ),
540
- status === "success" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { animation: "flopay-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
541
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "11", fill: "#22c55e" }),
542
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
543
- "path",
544
- {
545
- d: "M7 12.5l3 3 7-7",
546
- stroke: "white",
547
- strokeWidth: "2.5",
548
- strokeLinecap: "round",
549
- strokeLinejoin: "round",
550
- style: { strokeDasharray: 20, strokeDashoffset: 20, animation: "flopay-draw 0.4s 0.15s ease forwards" }
551
- }
552
- )
553
- ] }) }),
554
- status === "error" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { animation: "flopay-shake 0.4s ease" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
555
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "11", fill: "#ef4444" }),
556
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
557
- "path",
558
- {
559
- d: "M8 8l8 8M16 8l-8 8",
560
- stroke: "white",
561
- strokeWidth: "2.5",
562
- strokeLinecap: "round",
563
- style: { strokeDasharray: 12, strokeDashoffset: 12, animation: "flopay-draw 0.3s 0.1s ease forwards" }
564
- }
565
- )
566
- ] }) })
567
- ] }),
568
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: {
569
- fontSize: 14,
570
- fontWeight: 600,
571
- letterSpacing: "0.05em",
572
- color: status === "success" ? "#16a34a" : status === "error" ? "#dc2626" : "#374151"
573
- }, children: [
574
- status === "processing" && "PROCESSING...",
575
- status === "success" && "PAYMENT SUCCESSFUL",
576
- status === "error" && "PAYMENT FAILED"
577
- ] }),
578
- status === "success" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: {
579
- fontSize: 13,
580
- color: "#6b7280",
581
- fontWeight: 400,
582
- maxWidth: 260,
583
- lineHeight: 1.4,
584
- margin: 0
585
- }, children: "You will be automatically redirected, do not close or navigate away from this window." }),
586
- status === "error" && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: {
587
- fontSize: 13,
588
- color: "#6b7280",
589
- fontWeight: 400,
590
- maxWidth: 260,
591
- lineHeight: 1.4,
592
- margin: 0
593
- }, children: errorMessage }),
594
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
595
- @keyframes flopay-spin { to { transform: rotate(360deg); } }
596
- @keyframes flopay-pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
597
- @keyframes flopay-draw { to { stroke-dashoffset: 0; } }
598
- @keyframes flopay-shake { 0%,100% { transform: translateX(0); } 20%,60% { transform: translateX(-4px); } 40%,80% { transform: translateX(4px); } }
599
- ` })
600
- ] }) });
601
- }
602
- var SplitCardForm = (0, import_react6.forwardRef)(
666
+ var SplitCardForm = (0, import_react7.forwardRef)(
603
667
  function SplitCardForm2(props, ref) {
604
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
668
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
605
669
  }
606
670
  );
607
671
  function PayPalButtonInner({
@@ -617,12 +681,12 @@ function PayPalButtonInner({
617
681
  }) {
618
682
  const stripe = (0, import_react_stripe_js.useStripe)();
619
683
  const elements = (0, import_react_stripe_js.useElements)();
620
- const [loadState, setLoadState] = (0, import_react6.useState)("loading");
621
- const [submitting, setSubmitting] = (0, import_react6.useState)(false);
622
- const paypalResumeAttempted = (0, import_react6.useRef)(false);
623
- const beforeClickRef = (0, import_react6.useRef)(null);
684
+ const [loadState, setLoadState] = (0, import_react7.useState)("loading");
685
+ const [submitting, setSubmitting] = (0, import_react7.useState)(false);
686
+ const paypalResumeAttempted = (0, import_react7.useRef)(false);
687
+ const beforeClickRef = (0, import_react7.useRef)(null);
624
688
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
625
- (0, import_react6.useEffect)(() => {
689
+ (0, import_react7.useEffect)(() => {
626
690
  if (!stripe || paypalResumeAttempted.current) return;
627
691
  const params = new URLSearchParams(window.location.search);
628
692
  const paymentIntentId = params.get("payment_intent");
@@ -669,7 +733,7 @@ function PayPalButtonInner({
669
733
  }
670
734
  })();
671
735
  }, [stripe, onTokenizedBody, onErrorChange, onDecline]);
672
- const handlePayPalClick = (0, import_react6.useCallback)(async (event) => {
736
+ const handlePayPalClick = (0, import_react7.useCallback)(async (event) => {
673
737
  if (isProcessing || submitting) {
674
738
  event.reject();
675
739
  return;
@@ -686,7 +750,7 @@ function PayPalButtonInner({
686
750
  };
687
751
  event.resolve();
688
752
  }, [isProcessing, runBeforeButtonClick, submitting]);
689
- const handlePayPalConfirm = (0, import_react6.useCallback)(async (event) => {
753
+ const handlePayPalConfirm = (0, import_react7.useCallback)(async (event) => {
690
754
  if (!stripe || !elements) return;
691
755
  let prepared = beforeClickRef.current;
692
756
  beforeClickRef.current = null;
@@ -764,8 +828,8 @@ function PayPalButtonInner({
764
828
  setSubmitting(false);
765
829
  }
766
830
  }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
767
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
768
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
831
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
769
833
  import_react_stripe_js.ExpressCheckoutElement,
770
834
  {
771
835
  onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
@@ -787,7 +851,7 @@ function PayPalButtonInner({
787
851
  }
788
852
  }
789
853
  ) }),
790
- submitting && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProcessingOverlay, { status: "processing" })
854
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: "processing" })
791
855
  ] });
792
856
  }
793
857
  function WalletButtonInner({
@@ -804,12 +868,12 @@ function WalletButtonInner({
804
868
  }) {
805
869
  const stripe = (0, import_react_stripe_js.useStripe)();
806
870
  const elements = (0, import_react_stripe_js.useElements)();
807
- const [loadState, setLoadState] = (0, import_react6.useState)("loading");
808
- const [submitting, setSubmitting] = (0, import_react6.useState)(false);
871
+ const [loadState, setLoadState] = (0, import_react7.useState)("loading");
872
+ const [submitting, setSubmitting] = (0, import_react7.useState)(false);
809
873
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
810
- const lastWalletMethodRef = (0, import_react6.useRef)("card");
811
- const beforeClickRef = (0, import_react6.useRef)(null);
812
- const handleWalletConfirm = (0, import_react6.useCallback)(
874
+ const lastWalletMethodRef = (0, import_react7.useRef)("card");
875
+ const beforeClickRef = (0, import_react7.useRef)(null);
876
+ const handleWalletConfirm = (0, import_react7.useCallback)(
813
877
  async (event) => {
814
878
  if (!stripe || !elements) return;
815
879
  const walletType = event.expressPaymentType;
@@ -890,8 +954,8 @@ function WalletButtonInner({
890
954
  },
891
955
  [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
892
956
  );
893
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
894
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
957
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
958
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
895
959
  import_react_stripe_js.ExpressCheckoutElement,
896
960
  {
897
961
  onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
@@ -929,7 +993,7 @@ function WalletButtonInner({
929
993
  }
930
994
  }
931
995
  ) }),
932
- submitting && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProcessingOverlay, { status: "processing" })
996
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: "processing" })
933
997
  ] });
934
998
  }
935
999
  function SplitCardFormInner({
@@ -962,6 +1026,7 @@ function SplitCardFormInner({
962
1026
  cardButtonContent,
963
1027
  cardBackButtonContent,
964
1028
  cardTitleContent,
1029
+ showSecurityFooter = true,
965
1030
  onButtonClick,
966
1031
  onBeforeButtonClick,
967
1032
  enableAVS = false,
@@ -978,39 +1043,39 @@ function SplitCardFormInner({
978
1043
  const flopay = useFloPay();
979
1044
  const paypalFlopay = usePayPalFloPay();
980
1045
  const elements = useElements();
981
- const checkout = (0, import_react6.useContext)(CheckoutContext);
1046
+ const checkout = (0, import_react7.useContext)(CheckoutContext);
982
1047
  const contextBillingUrl = useBillingApiUrl();
983
- const [processing, setProcessing] = (0, import_react6.useState)(false);
984
- const [error, setError] = (0, import_react6.useState)(null);
985
- const [is3DSActive, setIs3DSActive] = (0, import_react6.useState)(false);
986
- const [selectedCountry, setSelectedCountry] = (0, import_react6.useState)(countryProp ?? "US");
987
- const [zipCode, setZipCode] = (0, import_react6.useState)(zipProp ?? "");
988
- const [accountPatch, setAccountPatch] = (0, import_react6.useState)({});
989
- const zipCodeRef = (0, import_react6.useRef)(zipProp ?? "");
990
- const selectedCountryRef = (0, import_react6.useRef)(countryProp ?? "US");
991
- const [viewState, setViewState] = (0, import_react6.useState)(initialCardOpen ? "card" : "buttons");
1048
+ const [processing, setProcessing] = (0, import_react7.useState)(false);
1049
+ const [error, setError] = (0, import_react7.useState)(null);
1050
+ const [is3DSActive, setIs3DSActive] = (0, import_react7.useState)(false);
1051
+ const [selectedCountry, setSelectedCountry] = (0, import_react7.useState)(countryProp ?? "US");
1052
+ const [zipCode, setZipCode] = (0, import_react7.useState)(zipProp ?? "");
1053
+ const [accountPatch, setAccountPatch] = (0, import_react7.useState)({});
1054
+ const zipCodeRef = (0, import_react7.useRef)(zipProp ?? "");
1055
+ const selectedCountryRef = (0, import_react7.useRef)(countryProp ?? "US");
1056
+ const [viewState, setViewState] = (0, import_react7.useState)(initialCardOpen ? "card" : "buttons");
992
1057
  const showCardForm = viewState === "expanding" || viewState === "card";
993
1058
  const TRANSITION_MS = 280;
994
- const expandToCard = (0, import_react6.useCallback)(() => {
1059
+ const expandToCard = (0, import_react7.useCallback)(() => {
995
1060
  setViewState("expanding");
996
1061
  setTimeout(() => setViewState("card"), TRANSITION_MS);
997
1062
  }, []);
998
- const collapseToButtons = (0, import_react6.useCallback)(() => {
1063
+ const collapseToButtons = (0, import_react7.useCallback)(() => {
999
1064
  setViewState("collapsing");
1000
1065
  setTimeout(() => setViewState("buttons"), TRANSITION_MS);
1001
1066
  }, []);
1002
- (0, import_react6.useEffect)(() => {
1067
+ (0, import_react7.useEffect)(() => {
1003
1068
  if (layout === "buttons" && initialCardOpen) {
1004
1069
  setViewState("card");
1005
1070
  }
1006
1071
  }, [layout, initialCardOpen]);
1007
- const [fullName, setFullName] = (0, import_react6.useState)("");
1008
- const [formReady, setFormReady] = (0, import_react6.useState)(false);
1009
- const [overlayStatus, setOverlayStatus] = (0, import_react6.useState)(null);
1010
- const processingRef = (0, import_react6.useRef)(false);
1072
+ const [fullName, setFullName] = (0, import_react7.useState)("");
1073
+ const [formReady, setFormReady] = (0, import_react7.useState)(false);
1074
+ const [overlayStatus, setOverlayStatus] = (0, import_react7.useState)(null);
1075
+ const processingRef = (0, import_react7.useRef)(false);
1011
1076
  const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
1012
1077
  const displayError = externalError ?? error;
1013
- const bStyles = (0, import_react6.useMemo)(() => {
1078
+ const bStyles = (0, import_react7.useMemo)(() => {
1014
1079
  const base = (0, import_shared4.resolveButtonsLayoutTheme)(buttonsTheme);
1015
1080
  if (!buttonsStylesOverride) return base;
1016
1081
  return {
@@ -1028,7 +1093,7 @@ function SplitCardFormInner({
1028
1093
  const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
1029
1094
  const isSelfContained = !onTokenizedBody;
1030
1095
  const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
1031
- const resolvedAccount = (0, import_react6.useMemo)(() => mergeAccountPatch({
1096
+ const resolvedAccount = (0, import_react7.useMemo)(() => mergeAccountPatch({
1032
1097
  userId,
1033
1098
  email,
1034
1099
  firstName,
@@ -1036,50 +1101,50 @@ function SplitCardFormInner({
1036
1101
  country: countryProp,
1037
1102
  zip: zipProp
1038
1103
  }, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
1039
- const stripeInstance = (0, import_react6.useMemo)(() => {
1104
+ const stripeInstance = (0, import_react7.useMemo)(() => {
1040
1105
  if (!flopay) return null;
1041
1106
  return flopay.getRawProvider();
1042
1107
  }, [flopay]);
1043
- const paypalStripeInstance = (0, import_react6.useMemo)(() => {
1108
+ const paypalStripeInstance = (0, import_react7.useMemo)(() => {
1044
1109
  if (!paypalFlopay) return null;
1045
1110
  return paypalFlopay.getRawProvider();
1046
1111
  }, [paypalFlopay]);
1047
1112
  const amountInCents = totalAmount || 100;
1048
- const walletOptions = (0, import_react6.useMemo)(() => ({
1113
+ const walletOptions = (0, import_react7.useMemo)(() => ({
1049
1114
  mode: "payment",
1050
1115
  amount: amountInCents,
1051
1116
  currency: currency.toLowerCase(),
1052
1117
  paymentMethodCreation: "manual",
1053
1118
  captureMethod: "manual"
1054
1119
  }), [amountInCents, currency]);
1055
- const paypalOptions = (0, import_react6.useMemo)(() => ({
1120
+ const paypalOptions = (0, import_react7.useMemo)(() => ({
1056
1121
  mode: "payment",
1057
1122
  amount: amountInCents,
1058
1123
  currency: currency.toLowerCase(),
1059
1124
  captureMethod: "manual"
1060
1125
  }), [amountInCents, currency]);
1061
- const updateError = (0, import_react6.useCallback)(
1126
+ const updateError = (0, import_react7.useCallback)(
1062
1127
  (err) => {
1063
1128
  setError(err);
1064
1129
  onErrorChange?.(err);
1065
1130
  },
1066
1131
  [onErrorChange]
1067
1132
  );
1068
- const emitDecline = (0, import_react6.useCallback)(
1133
+ const emitDecline = (0, import_react7.useCallback)(
1069
1134
  (method, input, overrides) => {
1070
1135
  onDecline?.(buildDeclineEvent(method, input, overrides));
1071
1136
  },
1072
1137
  [onDecline]
1073
1138
  );
1074
1139
  const showWallets = showApplePay || showGooglePay;
1075
- const handleNameChange = (0, import_react6.useCallback)((value) => {
1140
+ const handleNameChange = (0, import_react7.useCallback)((value) => {
1076
1141
  setFullName(value);
1077
1142
  onFullNameChange?.(value);
1078
1143
  const parts = value.trim().split(/\s+/);
1079
1144
  onFirstNameChange?.(parts[0] ?? "");
1080
1145
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
1081
1146
  }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
1082
- const applyInlineSessionPatch = (0, import_react6.useCallback)(
1147
+ const applyInlineSessionPatch = (0, import_react7.useCallback)(
1083
1148
  (patch, method) => {
1084
1149
  if (!checkout.applyInlineSessionPatch) {
1085
1150
  return Promise.resolve({ error: null, sessionId });
@@ -1096,7 +1161,7 @@ function SplitCardFormInner({
1096
1161
  },
1097
1162
  [checkout.applyInlineSessionPatch, onError, sessionId, updateError]
1098
1163
  );
1099
- const runBeforeButtonClick = (0, import_react6.useCallback)(async (method) => {
1164
+ const runBeforeButtonClick = (0, import_react7.useCallback)(async (method) => {
1100
1165
  if (!onBeforeButtonClick) return { proceed: true };
1101
1166
  try {
1102
1167
  const result = await onBeforeButtonClick({
@@ -1132,7 +1197,7 @@ function SplitCardFormInner({
1132
1197
  return { proceed: false };
1133
1198
  }
1134
1199
  }, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
1135
- const processPaymentInternal = (0, import_react6.useCallback)(
1200
+ const processPaymentInternal = (0, import_react7.useCallback)(
1136
1201
  async (tokenizedBody, overrides) => {
1137
1202
  if (processingRef.current) return;
1138
1203
  processingRef.current = true;
@@ -1163,10 +1228,11 @@ function SplitCardFormInner({
1163
1228
  });
1164
1229
  if (response.ok) {
1165
1230
  setOverlayStatus("success");
1166
- await new Promise((r) => setTimeout(r, 1200));
1231
+ await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
1167
1232
  onComplete?.({
1168
1233
  status: "succeeded",
1169
- paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId
1234
+ paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
1235
+ paymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
1170
1236
  });
1171
1237
  return;
1172
1238
  }
@@ -1196,7 +1262,8 @@ function SplitCardFormInner({
1196
1262
  await processPaymentInternal({
1197
1263
  id: result.paymentIntentId,
1198
1264
  type: "card",
1199
- threeDSecureActionResultTokenId: result.paymentIntentId
1265
+ threeDSecureActionResultTokenId: result.paymentIntentId,
1266
+ originalPaymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
1200
1267
  });
1201
1268
  }
1202
1269
  } finally {
@@ -1250,11 +1317,11 @@ function SplitCardFormInner({
1250
1317
  code: json?.code ?? json?.gatewayErrorCode,
1251
1318
  declineCode: json?.declineCode ?? json?.gatewayDeclineReason
1252
1319
  });
1253
- await new Promise((r) => setTimeout(r, 1500));
1320
+ await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
1254
1321
  } catch (err) {
1255
1322
  setOverlayStatus("error");
1256
1323
  updateError(err instanceof Error ? err.message : "An unexpected error occurred");
1257
- await new Promise((r) => setTimeout(r, 1500));
1324
+ await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
1258
1325
  } finally {
1259
1326
  setProcessing(false);
1260
1327
  setOverlayStatus(null);
@@ -1263,7 +1330,7 @@ function SplitCardFormInner({
1263
1330
  },
1264
1331
  [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
1265
1332
  );
1266
- const dispatchTokenizedBody = (0, import_react6.useCallback)(
1333
+ const dispatchTokenizedBody = (0, import_react7.useCallback)(
1267
1334
  (tokenizedBody, overrides) => {
1268
1335
  if (onTokenizedBody) {
1269
1336
  onTokenizedBody(tokenizedBody);
@@ -1273,7 +1340,7 @@ function SplitCardFormInner({
1273
1340
  },
1274
1341
  [onTokenizedBody, processPaymentInternal]
1275
1342
  );
1276
- (0, import_react6.useImperativeHandle)(innerRef, () => ({
1343
+ (0, import_react7.useImperativeHandle)(innerRef, () => ({
1277
1344
  async handleNextAction(secret) {
1278
1345
  if (!flopay) return;
1279
1346
  setIs3DSActive(true);
@@ -1300,7 +1367,7 @@ function SplitCardFormInner({
1300
1367
  }
1301
1368
  }
1302
1369
  }), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
1303
- (0, import_react6.useEffect)(() => {
1370
+ (0, import_react7.useEffect)(() => {
1304
1371
  if (typeof window === "undefined") return;
1305
1372
  const stored = localStorage.getItem(WALLET_RESUME_KEY);
1306
1373
  if (!stored) return;
@@ -1318,7 +1385,7 @@ function SplitCardFormInner({
1318
1385
  localStorage.removeItem(WALLET_RESUME_KEY);
1319
1386
  }
1320
1387
  }, [sessionId, dispatchTokenizedBody]);
1321
- const handleSubmit = (0, import_react6.useCallback)(
1388
+ const handleSubmit = (0, import_react7.useCallback)(
1322
1389
  async (e) => {
1323
1390
  e.preventDefault();
1324
1391
  if (!flopay || !elements || isSubmitting || processingRef.current) return;
@@ -1378,19 +1445,20 @@ function SplitCardFormInner({
1378
1445
  updateError(confirmResult.error.message);
1379
1446
  onError?.(confirmResult.error);
1380
1447
  emitDecline("card", confirmResult.error);
1381
- await new Promise((r) => setTimeout(r, 1500));
1448
+ await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
1382
1449
  return;
1383
1450
  }
1384
1451
  handedOff = isSelfContained;
1385
1452
  dispatchTokenizedBody({
1386
1453
  id: pmResult.paymentMethodId,
1387
1454
  type: "card",
1388
- threeDSecureActionResultTokenId: confirmResult.paymentIntentId
1455
+ threeDSecureActionResultTokenId: confirmResult.paymentIntentId,
1456
+ originalPaymentMethodId: pmResult.paymentMethodId
1389
1457
  });
1390
1458
  } catch (err) {
1391
1459
  setOverlayStatus("error");
1392
1460
  updateError(err instanceof Error ? err.message : "An unexpected error occurred");
1393
- await new Promise((r) => setTimeout(r, 1500));
1461
+ await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
1394
1462
  } finally {
1395
1463
  if (!handedOff) {
1396
1464
  setProcessing(false);
@@ -1402,7 +1470,7 @@ function SplitCardFormInner({
1402
1470
  );
1403
1471
  const isReady = flopay !== null && elements !== null;
1404
1472
  if (!isReady) {
1405
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
1473
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
1406
1474
  }
1407
1475
  const isButtons = layout === "buttons";
1408
1476
  const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
@@ -1445,7 +1513,7 @@ function SplitCardFormInner({
1445
1513
  invalid: { color: "#ef4444" }
1446
1514
  }
1447
1515
  };
1448
- const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1516
+ const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1449
1517
  backgroundColor: cardBg,
1450
1518
  borderRadius: "8px",
1451
1519
  padding: isButtons ? "0" : "1rem",
@@ -1453,7 +1521,7 @@ function SplitCardFormInner({
1453
1521
  ...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
1454
1522
  ...sharedInputPlaceholderVars
1455
1523
  }, children: [
1456
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
1524
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
1457
1525
  .flopay-shared-input::placeholder {
1458
1526
  color: var(--flopay-input-placeholder-color);
1459
1527
  opacity: 1;
@@ -1462,12 +1530,12 @@ function SplitCardFormInner({
1462
1530
  font-weight: var(--flopay-input-font-weight);
1463
1531
  }
1464
1532
  ` }),
1465
- isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1533
+ isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1466
1534
  display: "flex",
1467
1535
  alignItems: "center",
1468
1536
  padding: "0.75rem 0 0.625rem"
1469
1537
  }, children: [
1470
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1538
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1471
1539
  "button",
1472
1540
  {
1473
1541
  type: "button",
@@ -1489,7 +1557,7 @@ function SplitCardFormInner({
1489
1557
  },
1490
1558
  "aria-label": "Back to payment methods",
1491
1559
  children: [
1492
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: {
1560
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: {
1493
1561
  display: "inline-flex",
1494
1562
  alignItems: "center",
1495
1563
  justifyContent: "center",
@@ -1499,12 +1567,12 @@ function SplitCardFormInner({
1499
1567
  backgroundColor: "#f3f4f6",
1500
1568
  transition: "background-color 0.15s",
1501
1569
  ...bStyles.backButtonIcon
1502
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
1503
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
1570
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
1571
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
1504
1572
  ]
1505
1573
  }
1506
1574
  ),
1507
- hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1575
+ hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1508
1576
  flex: 1,
1509
1577
  textAlign: "center",
1510
1578
  fontWeight: 600,
@@ -1512,18 +1580,18 @@ function SplitCardFormInner({
1512
1580
  color: "#262833",
1513
1581
  paddingRight: 80,
1514
1582
  ...bStyles.title
1515
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TitleContentSlot, { content: cardTitleContent }) })
1583
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) })
1516
1584
  ] }),
1517
- !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
1518
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1585
+ !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
1586
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1519
1587
  backgroundColor: cardInputBg,
1520
1588
  border: `1px solid ${resolvedBorder}`,
1521
1589
  borderTopLeftRadius: "8px",
1522
1590
  borderTopRightRadius: "8px",
1523
1591
  padding: "10px"
1524
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
1525
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex" }, children: [
1526
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1592
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
1593
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex" }, children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1527
1595
  flex: 1,
1528
1596
  backgroundColor: cardInputBg,
1529
1597
  border: `1px solid ${resolvedBorder}`,
@@ -1531,23 +1599,23 @@ function SplitCardFormInner({
1531
1599
  borderRight: "none",
1532
1600
  borderBottomLeftRadius: "8px",
1533
1601
  padding: "10px"
1534
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
1535
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1602
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
1603
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1536
1604
  flex: 1,
1537
1605
  backgroundColor: cardInputBg,
1538
1606
  border: `1px solid ${resolvedBorder}`,
1539
1607
  borderTop: "none",
1540
1608
  borderBottomRightRadius: "8px",
1541
1609
  padding: "10px"
1542
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CardCvcElement, { options: stripeElementStyle }) })
1610
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardCvcElement, { options: stripeElementStyle }) })
1543
1611
  ] }),
1544
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1612
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1545
1613
  backgroundColor: cardInputBg,
1546
1614
  border: `1px solid ${resolvedBorder}`,
1547
1615
  borderRadius: "8px",
1548
1616
  marginTop: "0.5rem",
1549
1617
  padding: "10px"
1550
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1618
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1551
1619
  "input",
1552
1620
  {
1553
1621
  className: "flopay-shared-input",
@@ -1567,20 +1635,20 @@ function SplitCardFormInner({
1567
1635
  }
1568
1636
  }
1569
1637
  ) }),
1570
- enableAVS && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1638
+ enableAVS && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1571
1639
  display: "flex",
1572
1640
  flexDirection: avsLayoutProp === "column" ? "column" : "row",
1573
1641
  gap: avsLayoutProp === "column" ? "0.5rem" : "0",
1574
1642
  marginTop: "0.5rem"
1575
1643
  }, children: [
1576
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1644
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1577
1645
  flex: avsLayoutProp === "row" ? 1 : void 0,
1578
1646
  backgroundColor: cardInputBg,
1579
1647
  border: `1px solid ${resolvedBorder}`,
1580
1648
  padding: "10px",
1581
1649
  ...avsLayoutProp === "row" ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
1582
1650
  ...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
1583
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1651
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1584
1652
  "select",
1585
1653
  {
1586
1654
  value: selectedCountry,
@@ -1601,21 +1669,21 @@ function SplitCardFormInner({
1601
1669
  cursor: "pointer",
1602
1670
  ...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
1603
1671
  },
1604
- children: import_shared4.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("option", { value: c.code, children: [
1672
+ children: import_shared4.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("option", { value: c.code, children: [
1605
1673
  c.flag,
1606
1674
  " ",
1607
1675
  c.name
1608
1676
  ] }, c.code))
1609
1677
  }
1610
1678
  ) }),
1611
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1679
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1612
1680
  flex: avsLayoutProp === "row" ? 1 : void 0,
1613
1681
  backgroundColor: cardInputBg,
1614
1682
  border: `1px solid ${resolvedBorder}`,
1615
1683
  padding: "10px",
1616
1684
  ...avsLayoutProp === "row" ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
1617
1685
  ...isButtons && bStyles.zipInput ? bStyles.zipInput : {}
1618
- }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1686
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1619
1687
  "input",
1620
1688
  {
1621
1689
  className: "flopay-shared-input",
@@ -1641,7 +1709,7 @@ function SplitCardFormInner({
1641
1709
  }
1642
1710
  ) })
1643
1711
  ] }),
1644
- displayError && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
1712
+ displayError && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
1645
1713
  margin: "0.75rem 0",
1646
1714
  padding: "0.625rem 0.875rem",
1647
1715
  background: "#FEF2F2",
@@ -1655,10 +1723,10 @@ function SplitCardFormInner({
1655
1723
  gap: "0.5rem",
1656
1724
  ...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
1657
1725
  }, children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.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" }) }),
1726
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.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" }) }),
1659
1727
  displayError
1660
1728
  ] }),
1661
- children ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1729
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1662
1730
  "button",
1663
1731
  {
1664
1732
  type: "submit",
@@ -1681,7 +1749,7 @@ function SplitCardFormInner({
1681
1749
  children: isSubmitting ? "PROCESSING..." : submitLabel
1682
1750
  }
1683
1751
  ),
1684
- !isButtons && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1752
+ !isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1685
1753
  backgroundColor: "#EFF9F0",
1686
1754
  borderRadius: "8px",
1687
1755
  padding: "0.75rem",
@@ -1698,11 +1766,11 @@ function SplitCardFormInner({
1698
1766
  const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
1699
1767
  const buttonsAnim = viewState === "expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
1700
1768
  const cardAnim = viewState === "expanding" ? `flopay-card-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-card-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : void 0;
1701
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
1702
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FloPayKeyframes, {}),
1703
- overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
1704
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "grid" }, children: [
1705
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1769
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
1770
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayKeyframes, {}),
1771
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
1772
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "grid" }, children: [
1773
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1706
1774
  gridArea: "1 / 1",
1707
1775
  display: "flex",
1708
1776
  flexDirection: "column",
@@ -1711,7 +1779,7 @@ function SplitCardFormInner({
1711
1779
  ...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
1712
1780
  ...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
1713
1781
  }, children: [
1714
- showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1782
+ showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1715
1783
  PayPalButtonInner,
1716
1784
  {
1717
1785
  sessionId,
@@ -1725,7 +1793,7 @@ function SplitCardFormInner({
1725
1793
  runBeforeButtonClick
1726
1794
  }
1727
1795
  ) }),
1728
- showWallets && stripeInstance ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1796
+ showWallets && stripeInstance ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1729
1797
  WalletButtonInner,
1730
1798
  {
1731
1799
  sessionId,
@@ -1739,8 +1807,8 @@ function SplitCardFormInner({
1739
1807
  onDecline,
1740
1808
  runBeforeButtonClick
1741
1809
  }
1742
- ) }) : showWallets ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1743
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1810
+ ) }) : showWallets ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1811
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1744
1812
  "button",
1745
1813
  {
1746
1814
  type: "button",
@@ -1778,10 +1846,10 @@ function SplitCardFormInner({
1778
1846
  onMouseUp: (e) => {
1779
1847
  e.currentTarget.style.transform = "scale(1)";
1780
1848
  },
1781
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CardButtonContentSlot, { content: cardButtonContent })
1849
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardButtonContentSlot, { content: cardButtonContent })
1782
1850
  }
1783
1851
  ),
1784
- displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
1852
+ displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
1785
1853
  margin: "0.25rem 0",
1786
1854
  padding: "0.625rem 0.875rem",
1787
1855
  background: "#FEF2F2",
@@ -1795,11 +1863,11 @@ function SplitCardFormInner({
1795
1863
  gap: "0.5rem",
1796
1864
  ...bStyles.errorBanner ? bStyles.errorBanner : {}
1797
1865
  }, children: [
1798
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.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" }) }),
1866
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.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" }) }),
1799
1867
  displayError
1800
1868
  ] })
1801
1869
  ] }),
1802
- isCardView && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1870
+ isCardView && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1803
1871
  gridArea: "1 / 1",
1804
1872
  ...cardAnim ? { animation: cardAnim } : {},
1805
1873
  ...viewState === "collapsing" ? { pointerEvents: "none" } : {}
@@ -1807,10 +1875,10 @@ function SplitCardFormInner({
1807
1875
  ] })
1808
1876
  ] });
1809
1877
  }
1810
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
1811
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FloPayKeyframes, {}),
1812
- overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
1813
- showWallets && stripeInstance && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1878
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
1879
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayKeyframes, {}),
1880
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
1881
+ showWallets && stripeInstance && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1814
1882
  WalletButtonInner,
1815
1883
  {
1816
1884
  sessionId,
@@ -1823,7 +1891,7 @@ function SplitCardFormInner({
1823
1891
  onDecline
1824
1892
  }
1825
1893
  ) }),
1826
- showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1894
+ showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1827
1895
  PayPalButtonInner,
1828
1896
  {
1829
1897
  sessionId,
@@ -1835,7 +1903,7 @@ function SplitCardFormInner({
1835
1903
  onDecline
1836
1904
  }
1837
1905
  ) }),
1838
- (showWallets && stripeInstance || showPayPal && paypalStripeInstance) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1906
+ (showWallets && stripeInstance || showPayPal && paypalStripeInstance) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
1839
1907
  display: "flex",
1840
1908
  alignItems: "center",
1841
1909
  gap: "0.75rem",
@@ -1843,17 +1911,503 @@ function SplitCardFormInner({
1843
1911
  color: "#999",
1844
1912
  fontSize: "0.85rem"
1845
1913
  }, children: [
1846
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
1847
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "or pay with card" }),
1848
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
1914
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "or pay with card" }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
1849
1917
  ] }),
1850
1918
  cardFormBlock
1851
1919
  ] });
1852
1920
  }
1853
1921
 
1922
+ // src/saved-payment-flow.ts
1923
+ var import_js = require("@flopay/js");
1924
+ var import_shared6 = require("@flopay/shared");
1925
+ var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
1926
+ function resolveSavedPaymentReturnUrl(session) {
1927
+ if (typeof window !== "undefined" && window.location.href) {
1928
+ return window.location.href;
1929
+ }
1930
+ return session.successUrl || session.cancelUrl || void 0;
1931
+ }
1932
+ function isStripePaymentIntentClientSecret(value) {
1933
+ return typeof value === "string" && value.startsWith("pi_") && value.includes("_secret_");
1934
+ }
1935
+ async function retryOnceOnFetchFailure(action) {
1936
+ try {
1937
+ return await action();
1938
+ } catch (err) {
1939
+ const message = err instanceof Error ? err.message : String(err);
1940
+ if (!/failed to fetch|fetch failed/i.test(message)) {
1941
+ throw err;
1942
+ }
1943
+ return action();
1944
+ }
1945
+ }
1946
+ function getRedirectTokenFromProcessResponse(json, options) {
1947
+ const directCandidates = [
1948
+ json?.threeDSecureToken,
1949
+ json?.clientSecret,
1950
+ json?.stripeClientSecret
1951
+ ];
1952
+ for (const candidate of directCandidates) {
1953
+ if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
1954
+ return candidate;
1955
+ }
1956
+ }
1957
+ const nested = json?.data;
1958
+ if (nested && typeof nested === "object") {
1959
+ const nestedRecord = nested;
1960
+ const nestedCandidates = [
1961
+ nestedRecord.threeDSecureToken,
1962
+ nestedRecord.clientSecret,
1963
+ nestedRecord.stripeClientSecret,
1964
+ nestedRecord.id
1965
+ ];
1966
+ for (const candidate of nestedCandidates) {
1967
+ if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
1968
+ return candidate;
1969
+ }
1970
+ }
1971
+ const nestedGatewayData = nestedRecord.gatewayData;
1972
+ if (nestedGatewayData && typeof nestedGatewayData === "object") {
1973
+ const nestedGatewayDataRecord = nestedGatewayData;
1974
+ const gatewayCandidates = [
1975
+ nestedGatewayDataRecord.stripeClientSecret,
1976
+ nestedGatewayDataRecord.clientSecret
1977
+ ];
1978
+ for (const candidate of gatewayCandidates) {
1979
+ if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
1980
+ return candidate;
1981
+ }
1982
+ }
1983
+ }
1984
+ }
1985
+ return void 0;
1986
+ }
1987
+ async function recover3DSRedirectResult({
1988
+ billingApiUrl,
1989
+ sessionId,
1990
+ responseJson
1991
+ }) {
1992
+ const directToken = getRedirectTokenFromProcessResponse(responseJson, {
1993
+ requirePaymentIntentClientSecret: true
1994
+ });
1995
+ if (typeof directToken === "string" && directToken.length > 0) {
1996
+ return {
1997
+ type: "3ds_required",
1998
+ threeDSecureToken: directToken
1999
+ };
2000
+ }
2001
+ if (!sessionId) {
2002
+ return null;
2003
+ }
2004
+ try {
2005
+ const api = new import_js.PaymentAPI(billingApiUrl);
2006
+ const unified = await api.getUnifiedCheckoutSession(sessionId);
2007
+ const refreshedToken = unified.provider === "stripe" ? unified.data.stripe?.clientSecret : void 0;
2008
+ if (isStripePaymentIntentClientSecret(refreshedToken)) {
2009
+ return {
2010
+ type: "3ds_required",
2011
+ threeDSecureToken: refreshedToken
2012
+ };
2013
+ }
2014
+ } catch {
2015
+ }
2016
+ return null;
2017
+ }
2018
+ async function processSavedPaymentForMode({
2019
+ billingApiUrl,
2020
+ sessionId,
2021
+ session,
2022
+ tokenizedData,
2023
+ returnUrl
2024
+ }) {
2025
+ const baseUrl = billingApiUrl.replace(/\/+$/, "");
2026
+ const resolvedSessionId = sessionId ?? session.id;
2027
+ const customerId = session.customer?.id ?? session.accountData?.userId ?? "";
2028
+ const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
2029
+ const firstName = session.customer?.firstName ?? session.accountData?.firstName ?? "";
2030
+ const lastName = session.customer?.lastName ?? session.accountData?.lastName ?? "";
2031
+ const country = session.customer?.country ?? session.accountData?.country ?? void 0;
2032
+ const zip = session.customer?.zip ?? session.accountData?.zip ?? void 0;
2033
+ const response = await retryOnceOnFetchFailure(() => fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
2034
+ method: "POST",
2035
+ headers: {
2036
+ "Content-Type": "application/json",
2037
+ "x-user-id": customerId
2038
+ },
2039
+ body: JSON.stringify({
2040
+ sessionId: resolvedSessionId,
2041
+ tokenizedData,
2042
+ accountData: {
2043
+ userId: customerId,
2044
+ email: customerEmail,
2045
+ firstName,
2046
+ lastName,
2047
+ country,
2048
+ zip
2049
+ },
2050
+ returnUrl: returnUrl ?? resolveSavedPaymentReturnUrl(session)
2051
+ })
2052
+ }));
2053
+ if (response.ok) {
2054
+ return {
2055
+ type: "success",
2056
+ result: {
2057
+ status: "succeeded",
2058
+ paymentIntentId: tokenizedData?.threeDSecureActionResultTokenId,
2059
+ paymentMethodId: resolveTokenizedPaymentMethodId(tokenizedData)
2060
+ }
2061
+ };
2062
+ }
2063
+ const json = await response.json().catch(() => null);
2064
+ if (json?.type === "paypal_redirect_required" || json?.type === "3ds_required") {
2065
+ const redirectToken = getRedirectTokenFromProcessResponse(json);
2066
+ if (!redirectToken) {
2067
+ throw new import_shared6.FloPayError(
2068
+ "Authentication is required but no redirect token was provided.",
2069
+ "api_error",
2070
+ { code: "authentication_required" }
2071
+ );
2072
+ }
2073
+ return {
2074
+ type: json.type,
2075
+ threeDSecureToken: redirectToken,
2076
+ paymentMethodId: json.paymentMethodId
2077
+ };
2078
+ }
2079
+ if (json?.gatewayErrorCode === "authentication_required") {
2080
+ const recoveredRedirect = await recover3DSRedirectResult({
2081
+ billingApiUrl: baseUrl,
2082
+ sessionId: resolvedSessionId,
2083
+ responseJson: json
2084
+ });
2085
+ if (recoveredRedirect) {
2086
+ return recoveredRedirect;
2087
+ }
2088
+ throw Object.assign(
2089
+ new import_shared6.FloPayError(
2090
+ "Your card requires authentication. Please enter your payment details below.",
2091
+ "api_error",
2092
+ { code: "authentication_required" }
2093
+ ),
2094
+ { checkoutMethod: "card" }
2095
+ );
2096
+ }
2097
+ throw new import_shared6.FloPayError(
2098
+ json?.message ?? "Payment failed. Please try again.",
2099
+ "api_error",
2100
+ {
2101
+ code: json?.code ?? json?.gatewayErrorCode,
2102
+ declineCode: json?.declineCode ?? json?.gatewayDeclineReason
2103
+ }
2104
+ );
2105
+ }
2106
+ async function processSavedPaymentWithIntent({
2107
+ billingApiUrl,
2108
+ sessionId,
2109
+ session,
2110
+ paymentMethodId,
2111
+ flopay,
2112
+ returnUrl
2113
+ }) {
2114
+ const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
2115
+ if (!customerEmail) {
2116
+ throw Object.assign(
2117
+ new import_shared6.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
2118
+ param: "email"
2119
+ }),
2120
+ { checkoutMethod: "card" }
2121
+ );
2122
+ }
2123
+ const api = new import_js.PaymentAPI(billingApiUrl);
2124
+ const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
2125
+ sessionId,
2126
+ customerEmail,
2127
+ paymentMethodId
2128
+ ));
2129
+ const intentJson = await intentResponse.json().catch(() => null);
2130
+ if (!intentResponse.ok) {
2131
+ throw Object.assign(
2132
+ new import_shared6.FloPayError(
2133
+ intentJson?.message ?? "Failed to create payment intent.",
2134
+ "api_error",
2135
+ { code: intentJson?.code ?? intentJson?.gatewayErrorCode }
2136
+ ),
2137
+ { checkoutMethod: "card" }
2138
+ );
2139
+ }
2140
+ const intentClientSecret = getRedirectTokenFromProcessResponse(intentJson, {
2141
+ requirePaymentIntentClientSecret: true
2142
+ });
2143
+ if (!intentClientSecret) {
2144
+ throw Object.assign(
2145
+ new import_shared6.FloPayError("No client secret in payment intent response.", "api_error"),
2146
+ { checkoutMethod: "card" }
2147
+ );
2148
+ }
2149
+ const confirmResult = await flopay.confirmCardPayment({
2150
+ clientSecret: intentClientSecret,
2151
+ paymentMethodId
2152
+ });
2153
+ if (confirmResult.error) {
2154
+ throw Object.assign(
2155
+ confirmResult.error,
2156
+ { checkoutMethod: "card" }
2157
+ );
2158
+ }
2159
+ if (!confirmResult.paymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
2160
+ throw Object.assign(
2161
+ new import_shared6.FloPayError(
2162
+ `Payment intent in unexpected status: ${confirmResult.status}`,
2163
+ "api_error",
2164
+ {
2165
+ code: confirmResult.status === "requires_action" ? "authentication_required" : void 0
2166
+ }
2167
+ ),
2168
+ { checkoutMethod: "card" }
2169
+ );
2170
+ }
2171
+ const followUp = await processSavedPaymentForMode({
2172
+ billingApiUrl,
2173
+ sessionId,
2174
+ session,
2175
+ tokenizedData: {
2176
+ id: paymentMethodId,
2177
+ type: "card",
2178
+ threeDSecureActionResultTokenId: confirmResult.paymentIntentId,
2179
+ originalPaymentMethodId: paymentMethodId
2180
+ },
2181
+ returnUrl
2182
+ });
2183
+ const finalResult = followUp.type === "success" ? followUp.result : await handleSavedPaymentRedirectResult(followUp, {
2184
+ flopay,
2185
+ paypalFlopay: null,
2186
+ attempt3DS: true,
2187
+ billingApiUrl,
2188
+ sessionId,
2189
+ session,
2190
+ returnUrl
2191
+ });
2192
+ return {
2193
+ ...finalResult,
2194
+ paymentIntentId: finalResult.paymentIntentId ?? confirmResult.paymentIntentId,
2195
+ paymentMethodId: finalResult.paymentMethodId ?? paymentMethodId
2196
+ };
2197
+ }
2198
+ async function handleSavedPaymentRedirectResult(redirectResult, {
2199
+ flopay,
2200
+ paypalFlopay,
2201
+ attempt3DS,
2202
+ billingApiUrl,
2203
+ sessionId,
2204
+ session,
2205
+ returnUrl
2206
+ }) {
2207
+ const stripe = flopay?.getRawProvider();
2208
+ if (!stripe) {
2209
+ throw new import_shared6.FloPayError("Payment provider is not available.", "api_error");
2210
+ }
2211
+ if (redirectResult.type === "3ds_required") {
2212
+ if (!attempt3DS || !redirectResult.threeDSecureToken) {
2213
+ throw Object.assign(
2214
+ new import_shared6.FloPayError(
2215
+ "Your card requires authentication. Please enter your payment details below.",
2216
+ "api_error",
2217
+ { code: "authentication_required" }
2218
+ ),
2219
+ { checkoutMethod: "card" }
2220
+ );
2221
+ }
2222
+ let paymentIntent = null;
2223
+ let savedPaymentMethodId = redirectResult.paymentMethodId;
2224
+ if (typeof stripe.retrievePaymentIntent === "function") {
2225
+ const { paymentIntent: existingPaymentIntent, error: retrieveError } = await stripe.retrievePaymentIntent(
2226
+ redirectResult.threeDSecureToken
2227
+ );
2228
+ if (retrieveError) {
2229
+ throw Object.assign(
2230
+ new import_shared6.FloPayError(
2231
+ retrieveError.message ?? "Failed to retrieve 3DS payment status.",
2232
+ "api_error",
2233
+ { code: retrieveError.code }
2234
+ ),
2235
+ { checkoutMethod: "card" }
2236
+ );
2237
+ }
2238
+ if (!savedPaymentMethodId && existingPaymentIntent?.payment_method) {
2239
+ if (typeof existingPaymentIntent.payment_method === "string") {
2240
+ savedPaymentMethodId = existingPaymentIntent.payment_method;
2241
+ } else if ("id" in existingPaymentIntent.payment_method) {
2242
+ savedPaymentMethodId = existingPaymentIntent.payment_method.id;
2243
+ }
2244
+ }
2245
+ }
2246
+ if (savedPaymentMethodId && typeof stripe.confirmCardPayment === "function") {
2247
+ const { error: confirmError, paymentIntent: confirmedPaymentIntent } = await stripe.confirmCardPayment(
2248
+ redirectResult.threeDSecureToken,
2249
+ {
2250
+ payment_method: savedPaymentMethodId,
2251
+ return_url: returnUrl ?? resolveSavedPaymentReturnUrl(session) ?? window.location.href
2252
+ }
2253
+ );
2254
+ if (confirmError) {
2255
+ throw Object.assign(
2256
+ new import_shared6.FloPayError(
2257
+ confirmError.message ?? "3DS authentication failed.",
2258
+ "api_error",
2259
+ { code: confirmError.code }
2260
+ ),
2261
+ { checkoutMethod: "card" }
2262
+ );
2263
+ }
2264
+ paymentIntent = confirmedPaymentIntent ?? null;
2265
+ } else {
2266
+ const { error: nextActionError, paymentIntent: nextActionPaymentIntent } = await stripe.handleNextAction({
2267
+ clientSecret: redirectResult.threeDSecureToken
2268
+ });
2269
+ if (nextActionError) {
2270
+ throw Object.assign(
2271
+ new import_shared6.FloPayError(
2272
+ nextActionError.message ?? "3DS authentication failed.",
2273
+ "api_error",
2274
+ { code: nextActionError.code }
2275
+ ),
2276
+ { checkoutMethod: "card" }
2277
+ );
2278
+ }
2279
+ paymentIntent = nextActionPaymentIntent ?? null;
2280
+ }
2281
+ if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded" || paymentIntent.status === "processing")) {
2282
+ const followUp = await processSavedPaymentForMode({
2283
+ billingApiUrl,
2284
+ sessionId,
2285
+ session,
2286
+ tokenizedData: {
2287
+ id: paymentIntent.id,
2288
+ type: "card",
2289
+ threeDSecureActionResultTokenId: paymentIntent.id,
2290
+ originalPaymentMethodId: savedPaymentMethodId
2291
+ },
2292
+ returnUrl
2293
+ });
2294
+ if (followUp.type === "success") {
2295
+ return {
2296
+ ...followUp.result,
2297
+ paymentIntentId: followUp.result.paymentIntentId ?? paymentIntent.id,
2298
+ paymentMethodId: followUp.result.paymentMethodId ?? savedPaymentMethodId
2299
+ };
2300
+ }
2301
+ return handleSavedPaymentRedirectResult(followUp, {
2302
+ flopay,
2303
+ paypalFlopay,
2304
+ attempt3DS,
2305
+ billingApiUrl,
2306
+ sessionId,
2307
+ session,
2308
+ returnUrl
2309
+ });
2310
+ }
2311
+ throw Object.assign(
2312
+ new import_shared6.FloPayError("3DS authentication did not complete successfully.", "api_error"),
2313
+ { checkoutMethod: "card" }
2314
+ );
2315
+ }
2316
+ if (redirectResult.type === "paypal_redirect_required") {
2317
+ const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
2318
+ if (!paypalStripe) {
2319
+ throw Object.assign(
2320
+ new import_shared6.FloPayError("PayPal is not available.", "api_error"),
2321
+ { checkoutMethod: "paypal" }
2322
+ );
2323
+ }
2324
+ const confirmParams = {
2325
+ return_url: returnUrl ?? resolveSavedPaymentReturnUrl(session) ?? window.location.href
2326
+ };
2327
+ if (redirectResult.paymentMethodId) {
2328
+ confirmParams["payment_method"] = redirectResult.paymentMethodId;
2329
+ }
2330
+ const { error } = await paypalStripe.confirmPayment({
2331
+ clientSecret: redirectResult.threeDSecureToken,
2332
+ confirmParams,
2333
+ redirect: "if_required"
2334
+ });
2335
+ if (error) {
2336
+ throw Object.assign(
2337
+ new import_shared6.FloPayError(
2338
+ error.message ?? "PayPal authorization failed.",
2339
+ "api_error",
2340
+ { code: error.code }
2341
+ ),
2342
+ { checkoutMethod: "paypal" }
2343
+ );
2344
+ }
2345
+ return { status: "succeeded" };
2346
+ }
2347
+ throw new import_shared6.FloPayError("Unsupported payment redirect state.", "api_error");
2348
+ }
2349
+ function normalizeSavedPaymentError(err) {
2350
+ if (err instanceof import_shared6.FloPayError) {
2351
+ return err;
2352
+ }
2353
+ return new import_shared6.FloPayError(
2354
+ err instanceof Error ? err.message : "Payment failed. Please try again.",
2355
+ "api_error"
2356
+ );
2357
+ }
2358
+ function resolveSavedPaymentPublishableKeys(unified, fallbackPublishableKey) {
2359
+ let publishableKey;
2360
+ let paypalPublishableKey;
2361
+ if (unified.provider === "stripe") {
2362
+ publishableKey = unified.data.stripe?.publishableKey;
2363
+ paypalPublishableKey = unified.data.stripe?.paypalPublishableKey ?? void 0;
2364
+ }
2365
+ if (!publishableKey) {
2366
+ publishableKey = fallbackPublishableKey;
2367
+ }
2368
+ if (!publishableKey) {
2369
+ throw new import_shared6.FloPayError(
2370
+ "No publishable key found. Provide fallbackPublishableKey or ensure the session includes gatewayData.publishableKey.",
2371
+ "validation_error"
2372
+ );
2373
+ }
2374
+ return {
2375
+ publishableKey,
2376
+ paypalPublishableKey
2377
+ };
2378
+ }
2379
+ async function loadSavedPaymentProviders({
2380
+ publishableKey,
2381
+ paypalPublishableKey,
2382
+ billingApiUrl,
2383
+ locale
2384
+ }) {
2385
+ const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2386
+ const [instance, paypalInstanceOrError] = await Promise.all([
2387
+ (0, import_js.loadFloPay)(publishableKey, {
2388
+ billingApiUrl,
2389
+ locale
2390
+ }),
2391
+ needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
2392
+ billingApiUrl,
2393
+ locale
2394
+ }).catch((err) => {
2395
+ console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
2396
+ return null;
2397
+ }) : Promise.resolve(null)
2398
+ ]);
2399
+ return {
2400
+ flopay: instance,
2401
+ paypalFlopay: paypalPublishableKey ? needsSeparatePaypal ? paypalInstanceOrError : instance : null
2402
+ };
2403
+ }
2404
+
1854
2405
  // src/flopay-checkout.tsx
1855
- var import_jsx_runtime5 = require("react/jsx-runtime");
2406
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1856
2407
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
2408
+ function sleep(ms) {
2409
+ return new Promise((resolve) => setTimeout(resolve, ms));
2410
+ }
1857
2411
  function hasInlineSessionPatchData(patch) {
1858
2412
  if (!patch) return false;
1859
2413
  return Boolean(
@@ -1884,6 +2438,7 @@ function FloPayCheckout({
1884
2438
  cardButtonContent,
1885
2439
  cardBackButtonContent,
1886
2440
  cardTitleContent,
2441
+ showSecurityFooter = true,
1887
2442
  onButtonClick,
1888
2443
  onBeforeButtonClick,
1889
2444
  enableAVS,
@@ -1896,171 +2451,131 @@ function FloPayCheckout({
1896
2451
  renderConfirmButton,
1897
2452
  onSessionCompleted
1898
2453
  }) {
1899
- const resolvedBillingUrl = (0, import_shared6.resolveBillingApiUrl)(billingApiUrl);
2454
+ const resolvedBillingUrl = (0, import_shared7.resolveBillingApiUrl)(billingApiUrl);
1900
2455
  const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
1901
2456
  const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
1902
- const [unified, setUnified] = (0, import_react7.useState)(null);
1903
- const [flopay, setFloPay] = (0, import_react7.useState)(null);
1904
- const flopayRef = (0, import_react7.useRef)(null);
1905
- const [paypalFlopay, setPaypalFloPay] = (0, import_react7.useState)(null);
1906
- const paypalFlopayRef = (0, import_react7.useRef)(null);
1907
- const [session, setSession] = (0, import_react7.useState)(null);
1908
- const [resolvedSessionId, setResolvedSessionId] = (0, import_react7.useState)(sessionIdProp ?? "");
1909
- const [isLoading, setIsLoading] = (0, import_react7.useState)(true);
1910
- const [loadError, setLoadError] = (0, import_react7.useState)(null);
1911
- const [currentMode, setCurrentMode] = (0, import_react7.useState)("full");
1912
- const [confirmProcessing, setConfirmProcessing] = (0, import_react7.useState)(false);
1913
- const [modeError, setModeError] = (0, import_react7.useState)(null);
1914
- const [createSessionPatch, setCreateSessionPatch] = (0, import_react7.useState)(void 0);
1915
- const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react7.useState)("");
1916
- const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react7.useState)(false);
1917
- const autoCheckoutAttempted = (0, import_react7.useRef)(false);
1918
- const onCompleteRef = (0, import_react7.useRef)(onComplete);
2457
+ const [unified, setUnified] = (0, import_react8.useState)(null);
2458
+ const [flopay, setFloPay] = (0, import_react8.useState)(null);
2459
+ const flopayRef = (0, import_react8.useRef)(null);
2460
+ const [paypalFlopay, setPaypalFloPay] = (0, import_react8.useState)(null);
2461
+ const paypalFlopayRef = (0, import_react8.useRef)(null);
2462
+ const [session, setSession] = (0, import_react8.useState)(null);
2463
+ const [resolvedSessionId, setResolvedSessionId] = (0, import_react8.useState)(sessionIdProp ?? "");
2464
+ const activeSessionId = sessionIdProp ?? resolvedSessionId;
2465
+ const initSessionDependency = createSessionParams ? "" : activeSessionId;
2466
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(true);
2467
+ const [loadError, setLoadError] = (0, import_react8.useState)(null);
2468
+ const [currentMode, setCurrentMode] = (0, import_react8.useState)("full");
2469
+ const [confirmProcessing, setConfirmProcessing] = (0, import_react8.useState)(false);
2470
+ const [modeError, setModeError] = (0, import_react8.useState)(null);
2471
+ const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react8.useState)(null);
2472
+ const [modeOverlayError, setModeOverlayError] = (0, import_react8.useState)(null);
2473
+ const [createSessionPatch, setCreateSessionPatch] = (0, import_react8.useState)(void 0);
2474
+ const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react8.useState)("");
2475
+ const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react8.useState)(false);
2476
+ const autoCheckoutAttempted = (0, import_react8.useRef)(false);
2477
+ const onCompleteRef = (0, import_react8.useRef)(onComplete);
1919
2478
  onCompleteRef.current = onComplete;
1920
- const onErrorRef = (0, import_react7.useRef)(onError);
2479
+ const onErrorRef = (0, import_react8.useRef)(onError);
1921
2480
  onErrorRef.current = onError;
1922
- const onDeclineRef = (0, import_react7.useRef)(onDecline);
2481
+ const onDeclineRef = (0, import_react8.useRef)(onDecline);
1923
2482
  onDeclineRef.current = onDecline;
1924
- const onSessionCompletedRef = (0, import_react7.useRef)(onSessionCompleted);
2483
+ const onSessionCompletedRef = (0, import_react8.useRef)(onSessionCompleted);
1925
2484
  onSessionCompletedRef.current = onSessionCompleted;
1926
- (0, import_react7.useEffect)(() => {
2485
+ (0, import_react8.useEffect)(() => {
1927
2486
  console.info("[FloPay] Checkout initialized", {
1928
- sdk_version: import_shared6.SDK_VERSION,
2487
+ sdk_version: import_shared7.SDK_VERSION,
1929
2488
  checkout_type: checkoutType,
1930
2489
  checkout_layout: checkoutLayout,
1931
2490
  billing_api_url: resolvedBillingUrl
1932
2491
  });
1933
2492
  }, [checkoutLayout, checkoutType, resolvedBillingUrl]);
1934
- const baseCreateSessionHash = (0, import_react7.useMemo)(
2493
+ const baseCreateSessionHash = (0, import_react8.useMemo)(
1935
2494
  () => createSessionParams ? hashCreateParams(createSessionParams) : "",
1936
2495
  [createSessionParams]
1937
2496
  );
1938
- const activeCreateSessionPatch = (0, import_react7.useMemo)(
2497
+ const activeCreateSessionPatch = (0, import_react8.useMemo)(
1939
2498
  () => createSessionPatchBaseHash === baseCreateSessionHash ? createSessionPatch : void 0,
1940
2499
  [createSessionPatch, createSessionPatchBaseHash, baseCreateSessionHash]
1941
2500
  );
1942
- const effectiveCreateSession = (0, import_react7.useMemo)(
2501
+ const effectiveCreateSessionBase = (0, import_react8.useMemo)(
1943
2502
  () => createSessionParams ? mergeInlineSessionPatch(createSessionParams, activeCreateSessionPatch) : void 0,
1944
2503
  [createSessionParams, activeCreateSessionPatch]
1945
2504
  );
1946
- (0, import_react7.useEffect)(() => {
2505
+ const effectiveCreateSessionMode = checkoutModeProp ?? effectiveCreateSessionBase?.checkoutMode ?? "full";
2506
+ const effectiveCreateSession = (0, import_react8.useMemo)(
2507
+ () => effectiveCreateSessionBase ? {
2508
+ ...effectiveCreateSessionBase,
2509
+ checkoutMode: effectiveCreateSessionMode
2510
+ } : void 0,
2511
+ [effectiveCreateSessionBase, effectiveCreateSessionMode]
2512
+ );
2513
+ (0, import_react8.useEffect)(() => {
1947
2514
  setCreateSessionPatch(void 0);
1948
2515
  setCreateSessionPatchBaseHash(baseCreateSessionHash);
1949
2516
  }, [baseCreateSessionHash]);
1950
- const emitDecline = (0, import_react7.useCallback)(
2517
+ const emitDecline = (0, import_react8.useCallback)(
1951
2518
  (method, input, overrides) => {
1952
2519
  onDeclineRef.current?.(buildDeclineEvent(method, input, overrides));
1953
2520
  },
1954
2521
  []
1955
2522
  );
1956
- const processPaymentForMode = (0, import_react7.useCallback)(
1957
- async (sess) => {
1958
- const baseUrl = resolvedBillingUrl.replace(/\/+$/, "");
1959
- const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
1960
- method: "POST",
1961
- headers: {
1962
- "Content-Type": "application/json",
1963
- "x-user-id": sess.customer?.id ?? ""
1964
- },
1965
- body: JSON.stringify({
1966
- sessionId: resolvedSessionId,
1967
- tokenizedData: { id: void 0 },
1968
- accountData: {
1969
- userId: sess.customer?.id ?? "",
1970
- email: sess.customer?.email ?? "",
1971
- firstName: sess.customer?.firstName ?? "",
1972
- lastName: sess.customer?.lastName ?? ""
1973
- }
1974
- })
1975
- });
1976
- if (response.ok) {
1977
- onCompleteRef.current?.({ status: "succeeded" });
1978
- return null;
1979
- }
1980
- const json = await response.json().catch(() => null);
1981
- if ((json?.type === "paypal_redirect_required" || json?.type === "3ds_required") && json?.threeDSecureToken) {
1982
- return {
1983
- type: json.type,
1984
- threeDSecureToken: json.threeDSecureToken,
1985
- paymentMethodId: json.paymentMethodId
1986
- };
1987
- }
1988
- if (json?.gatewayErrorCode === "authentication_required") {
1989
- return {
1990
- type: "3ds_required",
1991
- threeDSecureToken: ""
1992
- // No client secret available
1993
- };
1994
- }
1995
- throw new import_shared6.FloPayError(
1996
- json?.message ?? "Payment failed. Please try again.",
1997
- "api_error",
1998
- {
1999
- code: json?.code ?? json?.gatewayErrorCode,
2000
- declineCode: json?.declineCode ?? json?.gatewayDeclineReason
2001
- }
2002
- );
2003
- },
2004
- [resolvedBillingUrl, resolvedSessionId]
2005
- );
2006
- const handleRedirectResult = (0, import_react7.useCallback)(
2007
- async (redirectResult, sess, options) => {
2008
- const stripe = flopayRef.current?.getRawProvider();
2009
- if (!stripe) return false;
2010
- if (redirectResult.type === "3ds_required") {
2011
- if (!options?.attempt3DS || !redirectResult.threeDSecureToken) {
2012
- setModeError("Your card requires authentication. Please enter your payment details below.");
2013
- return false;
2014
- }
2015
- const { error: nextActionError, paymentIntent } = await stripe.handleNextAction({
2016
- clientSecret: redirectResult.threeDSecureToken
2523
+ const runSavedPaymentFlow = (0, import_react8.useCallback)(
2524
+ async (sess, options) => {
2525
+ setModeError(null);
2526
+ setModeOverlayError(null);
2527
+ setModeOverlayStatus("processing");
2528
+ const activeSessionId2 = options?.sessionId ?? sess.id;
2529
+ try {
2530
+ const result = await processSavedPaymentForMode({
2531
+ billingApiUrl: resolvedBillingUrl,
2532
+ sessionId: activeSessionId2,
2533
+ session: sess
2017
2534
  });
2018
- if (nextActionError) {
2019
- setModeError(nextActionError.message ?? "3DS authentication failed.");
2020
- emitDecline("card", nextActionError.message ?? "3DS authentication failed.", {
2021
- code: nextActionError.code
2022
- });
2023
- return false;
2024
- }
2025
- if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded")) {
2026
- onCompleteRef.current?.({ status: "succeeded", paymentIntentId: paymentIntent.id });
2027
- return true;
2028
- }
2029
- return false;
2030
- }
2031
- if (redirectResult.type === "paypal_redirect_required") {
2032
- const paypalStripe = paypalFlopayRef.current?.getRawProvider();
2033
- if (!paypalStripe) {
2034
- setModeError("PayPal is not available.");
2035
- return false;
2036
- }
2037
- const confirmParams = {
2038
- return_url: window.location.href
2039
- };
2040
- if (redirectResult.paymentMethodId) {
2041
- confirmParams["payment_method"] = redirectResult.paymentMethodId;
2042
- }
2043
- const { error } = await paypalStripe.confirmPayment({
2044
- clientSecret: redirectResult.threeDSecureToken,
2045
- confirmParams,
2046
- redirect: "if_required"
2535
+ const paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2536
+ flopay: flopayRef.current,
2537
+ paypalFlopay: paypalFlopayRef.current,
2538
+ attempt3DS: options?.attempt3DS,
2539
+ billingApiUrl: resolvedBillingUrl,
2540
+ sessionId: activeSessionId2,
2541
+ session: sess
2047
2542
  });
2048
- if (error) {
2049
- setModeError(error.message ?? "PayPal authorization failed.");
2050
- emitDecline("paypal", error.message ?? "PayPal authorization failed.", {
2051
- code: error.code
2052
- });
2053
- return false;
2054
- }
2055
- onCompleteRef.current?.({ status: "succeeded" });
2543
+ setModeOverlayStatus("success");
2544
+ await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2545
+ onCompleteRef.current?.(paymentResult);
2056
2546
  return true;
2547
+ } catch (err) {
2548
+ const floPayErr = normalizeSavedPaymentError(err);
2549
+ const method = floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD;
2550
+ setModeError(floPayErr.message);
2551
+ setModeOverlayError(floPayErr.message);
2552
+ if (options?.fallbackToFull) {
2553
+ setCurrentMode("full");
2554
+ }
2555
+ onErrorRef.current?.(floPayErr);
2556
+ emitDecline(method, floPayErr, {
2557
+ code: floPayErr.code,
2558
+ declineCode: floPayErr.declineCode
2559
+ });
2560
+ setModeOverlayStatus("error");
2561
+ await Promise.allSettled([
2562
+ sleep(PROCESSING_OVERLAY_ERROR_DELAY_MS),
2563
+ options?.ensureProvidersReady ? options.ensureProvidersReady() : Promise.resolve()
2564
+ ]);
2565
+ return false;
2566
+ } finally {
2567
+ setModeOverlayStatus(null);
2568
+ setModeOverlayError(null);
2057
2569
  }
2058
- return false;
2059
2570
  },
2060
- [resolvedBillingUrl, resolvedSessionId, emitDecline]
2571
+ [
2572
+ emitDecline,
2573
+ normalizeSavedPaymentError,
2574
+ resolvedBillingUrl
2575
+ ]
2061
2576
  );
2062
- const inflightRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2063
- const initializedHashRef = (0, import_react7.useRef)(null);
2577
+ const inflightRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
2578
+ const initializedHashRef = (0, import_react8.useRef)(null);
2064
2579
  function hashCreateParams(params) {
2065
2580
  const key = JSON.stringify({
2066
2581
  c: params?.clientId,
@@ -2080,17 +2595,23 @@ function FloPayCheckout({
2080
2595
  }
2081
2596
  return `flopay_session_${Math.abs(h).toString(36)}`;
2082
2597
  }
2083
- const createSessionHash = (0, import_react7.useMemo)(
2598
+ const createSessionHash = (0, import_react8.useMemo)(
2084
2599
  () => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
2085
2600
  [effectiveCreateSession]
2086
2601
  );
2087
- const createSessionParamsRef = (0, import_react7.useRef)(effectiveCreateSession);
2602
+ const createSessionParamsRef = (0, import_react8.useRef)(effectiveCreateSession);
2088
2603
  createSessionParamsRef.current = effectiveCreateSession;
2089
- (0, import_react7.useEffect)(() => {
2604
+ (0, import_react8.useEffect)(() => {
2090
2605
  setResolvedSessionId(sessionIdProp ?? "");
2091
2606
  }, [sessionIdProp]);
2607
+ (0, import_react8.useEffect)(() => {
2608
+ autoCheckoutAttempted.current = false;
2609
+ setModeError(null);
2610
+ setModeOverlayError(null);
2611
+ setModeOverlayStatus(null);
2612
+ }, [sessionIdProp, createSessionHash]);
2092
2613
  async function resolveInlineSession(params, cacheKey) {
2093
- const api = new import_js.PaymentAPI(resolvedBillingUrl);
2614
+ const api = new import_js2.PaymentAPI(resolvedBillingUrl);
2094
2615
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
2095
2616
  let realResult = null;
2096
2617
  if (sid) {
@@ -2115,11 +2636,11 @@ function FloPayCheckout({
2115
2636
  }
2116
2637
  return { sid: sid ?? "", result: realResult };
2117
2638
  }
2118
- const bootstrapInlineSession = (0, import_react7.useCallback)(
2639
+ const bootstrapInlineSession = (0, import_react8.useCallback)(
2119
2640
  async (patch) => {
2120
2641
  const baseParams = createSessionParamsRef.current;
2121
2642
  if (!baseParams) {
2122
- throw new import_shared6.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
2643
+ throw new import_shared7.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
2123
2644
  }
2124
2645
  const mergedParams = mergeInlineSessionPatch(baseParams, patch);
2125
2646
  const cacheKey = hashCreateParams(mergedParams);
@@ -2148,43 +2669,23 @@ function FloPayCheckout({
2148
2669
  if (sid) {
2149
2670
  setResolvedSessionId(sid);
2150
2671
  }
2151
- let publishableKey;
2152
- let paypalPublishableKey;
2153
- if (realResult.provider === "stripe") {
2154
- publishableKey = realResult.data.stripe?.publishableKey;
2155
- paypalPublishableKey = realResult.data.stripe?.paypalPublishableKey;
2156
- }
2157
- if (!publishableKey) publishableKey = fallbackPublishableKey;
2158
- if (!publishableKey) {
2159
- throw new import_shared6.FloPayError(
2160
- "No publishable key found. Provide fallbackPublishableKey or ensure the session includes gatewayData.publishableKey.",
2161
- "validation_error"
2162
- );
2163
- }
2164
- const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2165
- const [instance, paypalInstanceOrError] = await Promise.all([
2166
- (0, import_js.loadFloPay)(publishableKey, {
2167
- billingApiUrl: resolvedBillingUrl,
2168
- locale
2169
- }),
2170
- needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
2171
- billingApiUrl: resolvedBillingUrl,
2172
- locale
2173
- }).catch((err) => {
2174
- console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
2175
- return null;
2176
- }) : Promise.resolve(null)
2177
- ]);
2672
+ const {
2673
+ publishableKey,
2674
+ paypalPublishableKey
2675
+ } = resolveSavedPaymentPublishableKeys(realResult, fallbackPublishableKey);
2676
+ const {
2677
+ flopay: instance,
2678
+ paypalFlopay: paypalInstance
2679
+ } = await loadSavedPaymentProviders({
2680
+ publishableKey,
2681
+ paypalPublishableKey,
2682
+ billingApiUrl: resolvedBillingUrl,
2683
+ locale
2684
+ });
2178
2685
  flopayRef.current = instance;
2179
2686
  setFloPay(instance);
2180
- if (paypalPublishableKey) {
2181
- const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
2182
- paypalFlopayRef.current = paypalInstance;
2183
- setPaypalFloPay(paypalInstance);
2184
- } else {
2185
- paypalFlopayRef.current = null;
2186
- setPaypalFloPay(null);
2187
- }
2687
+ paypalFlopayRef.current = paypalInstance;
2688
+ setPaypalFloPay(paypalInstance);
2188
2689
  setIsLoading(false);
2189
2690
  } catch (err) {
2190
2691
  if (initializedHashRef.current === cacheKey) {
@@ -2196,7 +2697,7 @@ function FloPayCheckout({
2196
2697
  },
2197
2698
  [fallbackPublishableKey, locale, resolvedBillingUrl]
2198
2699
  );
2199
- const handleInlineSessionPatch = (0, import_react7.useCallback)(async (patch) => {
2700
+ const handleInlineSessionPatch = (0, import_react8.useCallback)(async (patch) => {
2200
2701
  if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
2201
2702
  return {
2202
2703
  sessionId: resolvedSessionId,
@@ -2219,21 +2720,61 @@ function FloPayCheckout({
2219
2720
  resolvedSessionId,
2220
2721
  session
2221
2722
  ]);
2222
- (0, import_react7.useEffect)(() => {
2723
+ (0, import_react8.useEffect)(() => {
2223
2724
  let cancelled = false;
2224
2725
  setLoadError(null);
2225
2726
  if (createSessionHash) {
2226
- if (initializedHashRef.current === createSessionHash) return;
2227
2727
  const params = createSessionParamsRef.current;
2228
2728
  setSession(buildSyntheticSession(params, checkoutModeProp));
2229
- setCurrentMode(params.checkoutMode ?? checkoutModeProp ?? "full");
2729
+ setCurrentMode(effectiveCreateSessionMode);
2230
2730
  setIsLoading(false);
2731
+ if (initializedHashRef.current === createSessionHash) {
2732
+ return () => {
2733
+ cancelled = true;
2734
+ };
2735
+ }
2231
2736
  (async () => {
2737
+ const shouldAutoProcessInlineSession = effectiveCreateSessionMode === "auto" && !autoCheckoutAttempted.current;
2738
+ if (shouldAutoProcessInlineSession) {
2739
+ setModeError(null);
2740
+ setModeOverlayError(null);
2741
+ setModeOverlayStatus("processing");
2742
+ }
2232
2743
  try {
2233
- await bootstrapInlineSession();
2744
+ const resolved = await bootstrapInlineSession();
2745
+ const resolvedSession = resolved.result.data.session ?? null;
2746
+ if (!cancelled && shouldAutoProcessInlineSession && resolvedSession) {
2747
+ autoCheckoutAttempted.current = true;
2748
+ await runSavedPaymentFlow(resolvedSession, {
2749
+ attempt3DS: true,
2750
+ fallbackToFull: true,
2751
+ sessionId: resolved.sid || resolvedSession.id
2752
+ });
2753
+ return;
2754
+ }
2755
+ if (!cancelled && shouldAutoProcessInlineSession) {
2756
+ setModeOverlayStatus(null);
2757
+ setModeOverlayError(null);
2758
+ }
2234
2759
  } catch (err) {
2235
2760
  if (cancelled) return;
2236
- const floPayErr = err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
2761
+ const errorCode = err instanceof import_shared7.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
2762
+ if (shouldAutoProcessInlineSession && errorCode === "session_auto_completed") {
2763
+ autoCheckoutAttempted.current = true;
2764
+ setModeOverlayStatus("success");
2765
+ await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2766
+ if (!cancelled) {
2767
+ onCompleteRef.current?.({ status: "succeeded" });
2768
+ setModeOverlayStatus(null);
2769
+ setModeOverlayError(null);
2770
+ }
2771
+ return;
2772
+ }
2773
+ if (shouldAutoProcessInlineSession) {
2774
+ setModeOverlayStatus(null);
2775
+ setModeOverlayError(null);
2776
+ }
2777
+ const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
2237
2778
  setLoadError(floPayErr);
2238
2779
  }
2239
2780
  })();
@@ -2244,14 +2785,14 @@ function FloPayCheckout({
2244
2785
  setIsLoading(true);
2245
2786
  async function init() {
2246
2787
  try {
2247
- const api = new import_js.PaymentAPI(resolvedBillingUrl);
2248
- const result = await api.getUnifiedCheckoutSession(resolvedSessionId);
2788
+ const api = new import_js2.PaymentAPI(resolvedBillingUrl);
2789
+ const result = await api.getUnifiedCheckoutSession(activeSessionId);
2249
2790
  if (cancelled) return;
2250
2791
  setUnified(result);
2251
2792
  const sess = result.data.session ?? null;
2252
2793
  setSession(sess);
2253
2794
  if (!sess) {
2254
- throw new import_shared6.FloPayError("No session data returned", "api_error");
2795
+ throw new import_shared7.FloPayError("No session data returned", "api_error");
2255
2796
  }
2256
2797
  if (sess.status === "complete") {
2257
2798
  setIsLoading(false);
@@ -2265,22 +2806,20 @@ function FloPayCheckout({
2265
2806
  autoCheckoutAttempted.current = true;
2266
2807
  const stripeInitPromise = initStripe(result);
2267
2808
  try {
2268
- const redirectResult = await processPaymentForMode(sess);
2269
- if (!redirectResult) {
2270
- if (!cancelled) setIsLoading(false);
2271
- return;
2272
- }
2809
+ await runSavedPaymentFlow(sess, {
2810
+ attempt3DS: true,
2811
+ fallbackToFull: true,
2812
+ ensureProvidersReady: () => stripeInitPromise,
2813
+ sessionId: activeSessionId || sess.id
2814
+ });
2273
2815
  if (cancelled) return;
2274
2816
  await stripeInitPromise;
2275
- const handled = await handleRedirectResult(redirectResult, sess, { attempt3DS: true });
2276
2817
  if (!cancelled) {
2277
- if (!handled) setCurrentMode("full");
2278
2818
  setIsLoading(false);
2279
2819
  }
2280
2820
  return;
2281
2821
  } catch {
2282
2822
  if (cancelled) return;
2283
- setCurrentMode("full");
2284
2823
  await stripeInitPromise;
2285
2824
  if (!cancelled) setIsLoading(false);
2286
2825
  return;
@@ -2290,82 +2829,56 @@ function FloPayCheckout({
2290
2829
  if (!cancelled) setIsLoading(false);
2291
2830
  } catch (err) {
2292
2831
  if (cancelled) return;
2293
- const floPayErr = err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
2832
+ const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
2294
2833
  setLoadError(floPayErr);
2295
2834
  setIsLoading(false);
2296
2835
  }
2297
2836
  }
2298
2837
  async function initStripe(result) {
2299
- let publishableKey;
2300
- let paypalPublishableKey;
2301
- if (result.provider === "stripe") {
2302
- publishableKey = result.data.stripe?.publishableKey;
2303
- paypalPublishableKey = result.data.stripe?.paypalPublishableKey;
2304
- }
2305
- if (!publishableKey) publishableKey = fallbackPublishableKey;
2306
- if (!publishableKey) {
2307
- throw new import_shared6.FloPayError(
2308
- "No publishable key found in session response. Provide a fallbackPublishableKey prop or ensure the session includes gatewayData.publishableKey.",
2309
- "validation_error"
2310
- );
2311
- }
2312
- const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2313
- const [instance, paypalInstanceOrError] = await Promise.all([
2314
- (0, import_js.loadFloPay)(publishableKey, {
2315
- billingApiUrl: resolvedBillingUrl,
2316
- locale
2317
- }),
2318
- needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
2319
- billingApiUrl: resolvedBillingUrl,
2320
- locale
2321
- }).catch((err) => {
2322
- console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
2323
- return null;
2324
- }) : Promise.resolve(null)
2325
- ]);
2838
+ const {
2839
+ publishableKey,
2840
+ paypalPublishableKey
2841
+ } = resolveSavedPaymentPublishableKeys(result, fallbackPublishableKey);
2842
+ const {
2843
+ flopay: instance,
2844
+ paypalFlopay: paypalInstance
2845
+ } = await loadSavedPaymentProviders({
2846
+ publishableKey,
2847
+ paypalPublishableKey,
2848
+ billingApiUrl: resolvedBillingUrl,
2849
+ locale
2850
+ });
2326
2851
  flopayRef.current = instance;
2327
2852
  setFloPay(instance);
2328
- if (paypalPublishableKey) {
2329
- const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
2330
- paypalFlopayRef.current = paypalInstance;
2331
- setPaypalFloPay(paypalInstance);
2332
- } else {
2333
- paypalFlopayRef.current = null;
2334
- setPaypalFloPay(null);
2335
- }
2853
+ paypalFlopayRef.current = paypalInstance;
2854
+ setPaypalFloPay(paypalInstance);
2336
2855
  }
2337
2856
  init();
2338
2857
  return () => {
2339
2858
  cancelled = true;
2340
2859
  };
2341
- }, [resolvedSessionId, createSessionHash, checkoutModeProp, bootstrapInlineSession]);
2342
- const handleConfirmCheckout = (0, import_react7.useCallback)(async () => {
2860
+ }, [
2861
+ bootstrapInlineSession,
2862
+ checkoutModeProp,
2863
+ createSessionHash,
2864
+ effectiveCreateSessionMode,
2865
+ initSessionDependency,
2866
+ runSavedPaymentFlow
2867
+ ]);
2868
+ const handleConfirmCheckout = (0, import_react8.useCallback)(async () => {
2343
2869
  if (confirmProcessing || !session) return;
2344
2870
  setConfirmProcessing(true);
2345
2871
  setModeError(null);
2346
2872
  try {
2347
- const redirectResult = await processPaymentForMode(session);
2348
- if (!redirectResult) {
2349
- return;
2350
- }
2351
- const handled = await handleRedirectResult(redirectResult, session);
2352
- if (!handled) {
2353
- setCurrentMode("full");
2354
- }
2355
- } catch (err) {
2356
- const floPayErr = err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(
2357
- err instanceof Error ? err.message : "Payment failed",
2358
- "api_error"
2359
- );
2360
- setModeError(floPayErr.message);
2361
- onError?.(floPayErr);
2362
- emitDecline("card", floPayErr);
2363
- setCurrentMode("full");
2873
+ await runSavedPaymentFlow(session, {
2874
+ fallbackToFull: true,
2875
+ sessionId: activeSessionId || session.id
2876
+ });
2364
2877
  } finally {
2365
2878
  setConfirmProcessing(false);
2366
2879
  }
2367
- }, [confirmProcessing, session, processPaymentForMode, handleRedirectResult, onError, emitDecline]);
2368
- const providerOptions = (0, import_react7.useMemo)(() => {
2880
+ }, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
2881
+ const providerOptions = (0, import_react8.useMemo)(() => {
2369
2882
  if (!unified || !session) return void 0;
2370
2883
  const opts = {
2371
2884
  appearance,
@@ -2375,16 +2888,16 @@ function FloPayCheckout({
2375
2888
  if (unified.provider === "stripe" && unified.data.stripe?.clientSecret) {
2376
2889
  opts.clientSecret = unified.data.stripe.clientSecret;
2377
2890
  } else {
2378
- const displayTotal = (0, import_shared6.buildCheckoutDisplayData)(session).total;
2891
+ const displayTotal = (0, import_shared7.buildCheckoutDisplayData)(session).total;
2379
2892
  opts.amount = Math.round(displayTotal * 100) || session.amount;
2380
2893
  opts.currency = session.currency?.toLowerCase();
2381
2894
  }
2382
2895
  return opts;
2383
2896
  }, [unified, session, appearance, resolvedBillingUrl]);
2384
2897
  const shouldHandleInlineSessionPatch = Boolean(
2385
- createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && (effectiveCreateSession?.checkoutMode ?? checkoutModeProp ?? "full") === "full"
2898
+ createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && effectiveCreateSessionMode === "full"
2386
2899
  );
2387
- const checkoutValue = (0, import_react7.useMemo)(
2900
+ const checkoutValue = (0, import_react8.useMemo)(
2388
2901
  () => ({
2389
2902
  session,
2390
2903
  loading: isLoading,
@@ -2406,37 +2919,55 @@ function FloPayCheckout({
2406
2919
  ]
2407
2920
  );
2408
2921
  const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
2922
+ const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2923
+ ProcessingOverlay,
2924
+ {
2925
+ status: modeOverlayStatus,
2926
+ errorMessage: modeOverlayError
2927
+ }
2928
+ ) : null;
2409
2929
  if (isLoading) {
2410
- if (loadingNode) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: loadingNode });
2930
+ if (loadingNode) {
2931
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2932
+ loadingNode,
2933
+ modeOverlay
2934
+ ] });
2935
+ }
2411
2936
  if (layout === "buttons") {
2412
- const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2937
+ const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2413
2938
  height: h,
2414
2939
  borderRadius: 8,
2415
2940
  background: "#e5e7eb",
2416
2941
  animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
2417
2942
  } });
2418
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2419
- showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2420
- (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2421
- skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2422
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2943
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2944
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2945
+ showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2946
+ (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2947
+ skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2948
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2949
+ ] }),
2950
+ modeOverlay
2423
2951
  ] });
2424
2952
  }
2425
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
2426
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2427
- width: 24,
2428
- height: 24,
2429
- border: "2px solid #e5e7eb",
2430
- borderTopColor: "#6b7280",
2431
- borderRadius: "50%",
2432
- animation: "spin 0.6s linear infinite"
2433
- } }),
2434
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
2953
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2954
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
2955
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2956
+ width: 24,
2957
+ height: 24,
2958
+ border: "2px solid #e5e7eb",
2959
+ borderTopColor: "#6b7280",
2960
+ borderRadius: "50%",
2961
+ animation: "spin 0.6s linear infinite"
2962
+ } }),
2963
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
2964
+ ] }),
2965
+ modeOverlay
2435
2966
  ] });
2436
2967
  }
2437
2968
  if (loadError) {
2438
- if (errorNode) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: errorNode(loadError) });
2439
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2969
+ if (errorNode) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: errorNode(loadError) });
2970
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2440
2971
  "div",
2441
2972
  {
2442
2973
  style: {
@@ -2450,99 +2981,111 @@ function FloPayCheckout({
2450
2981
  );
2451
2982
  }
2452
2983
  if (shouldShowInterimButtons) {
2453
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2454
- InterimButtonsView,
2455
- {
2456
- onButtonClick,
2457
- showPayPal,
2458
- showApplePay,
2459
- showGooglePay,
2460
- buttonsTheme,
2461
- buttonsStyles,
2462
- cardButtonContent,
2463
- cardBackButtonContent,
2464
- cardTitleContent
2465
- }
2466
- ) });
2984
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2985
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2986
+ InterimButtonsView,
2987
+ {
2988
+ onButtonClick,
2989
+ showPayPal,
2990
+ showApplePay,
2991
+ showGooglePay,
2992
+ buttonsTheme,
2993
+ buttonsStyles,
2994
+ cardButtonContent,
2995
+ cardBackButtonContent,
2996
+ cardTitleContent
2997
+ }
2998
+ ) }),
2999
+ modeOverlay
3000
+ ] });
3001
+ }
3002
+ if (!flopay || !providerOptions) {
3003
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: modeOverlay });
2467
3004
  }
2468
- if (!flopay || !providerOptions) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
2469
3005
  if (currentMode === "confirm") {
2470
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, children: [
2471
- modeError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3006
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3007
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, children: [
3008
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3009
+ "div",
3010
+ {
3011
+ style: {
3012
+ color: "#dc2626",
3013
+ fontSize: "0.875rem",
3014
+ marginBottom: "0.75rem",
3015
+ textAlign: "center"
3016
+ },
3017
+ children: modeError
3018
+ }
3019
+ ),
3020
+ renderConfirmButton ? renderConfirmButton({
3021
+ onConfirm: handleConfirmCheckout,
3022
+ isProcessing: confirmProcessing
3023
+ }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3024
+ "button",
3025
+ {
3026
+ type: "button",
3027
+ onClick: handleConfirmCheckout,
3028
+ disabled: confirmProcessing,
3029
+ style: {
3030
+ width: "100%",
3031
+ padding: "0.875rem",
3032
+ backgroundColor: "#4A49FF",
3033
+ color: "white",
3034
+ border: "none",
3035
+ borderRadius: "8px",
3036
+ fontSize: "1rem",
3037
+ fontWeight: 600,
3038
+ cursor: confirmProcessing ? "not-allowed" : "pointer",
3039
+ opacity: confirmProcessing ? 0.6 : 1
3040
+ },
3041
+ children: confirmProcessing ? "Processing..." : confirmLabel ?? "Confirm Purchase"
3042
+ }
3043
+ )
3044
+ ] }) }) }),
3045
+ modeOverlay
3046
+ ] });
3047
+ }
3048
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3049
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3050
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2472
3051
  "div",
2473
3052
  {
2474
3053
  style: {
2475
- color: "#dc2626",
2476
- fontSize: "0.875rem",
3054
+ padding: "0.75rem 1rem",
2477
3055
  marginBottom: "0.75rem",
2478
- textAlign: "center"
3056
+ backgroundColor: "#FEF3C7",
3057
+ border: "1px solid #F59E0B",
3058
+ borderRadius: "8px",
3059
+ color: "#92400E",
3060
+ fontSize: "0.875rem"
2479
3061
  },
2480
3062
  children: modeError
2481
3063
  }
2482
3064
  ),
2483
- renderConfirmButton ? renderConfirmButton({
2484
- onConfirm: handleConfirmCheckout,
2485
- isProcessing: confirmProcessing
2486
- }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2487
- "button",
3065
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3066
+ SessionInjector,
2488
3067
  {
2489
- type: "button",
2490
- onClick: handleConfirmCheckout,
2491
- disabled: confirmProcessing,
2492
- style: {
2493
- width: "100%",
2494
- padding: "0.875rem",
2495
- backgroundColor: "#4A49FF",
2496
- color: "white",
2497
- border: "none",
2498
- borderRadius: "8px",
2499
- fontSize: "1rem",
2500
- fontWeight: 600,
2501
- cursor: confirmProcessing ? "not-allowed" : "pointer",
2502
- opacity: confirmProcessing ? 0.6 : 1
2503
- },
2504
- children: confirmProcessing ? "Processing..." : confirmLabel ?? "Confirm Purchase"
3068
+ sessionId: activeSessionId,
3069
+ billingApiUrl: resolvedBillingUrl,
3070
+ session,
3071
+ children
2505
3072
  }
2506
3073
  )
2507
- ] }) }) });
2508
- }
2509
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(FloPayProvider, { flopay, options: providerOptions, children: [
2510
- modeError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2511
- "div",
2512
- {
2513
- style: {
2514
- padding: "0.75rem 1rem",
2515
- marginBottom: "0.75rem",
2516
- backgroundColor: "#FEF3C7",
2517
- border: "1px solid #F59E0B",
2518
- borderRadius: "8px",
2519
- color: "#92400E",
2520
- fontSize: "0.875rem"
2521
- },
2522
- children: modeError
2523
- }
2524
- ),
2525
- children ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2526
- SessionInjector,
2527
- {
2528
- sessionId: resolvedSessionId,
2529
- billingApiUrl: resolvedBillingUrl,
2530
- session,
2531
- children
2532
- }
2533
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3074
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2534
3075
  SplitCardForm,
2535
3076
  {
2536
- sessionId: resolvedSessionId,
3077
+ sessionId: activeSessionId,
2537
3078
  email: session?.customer?.email,
2538
3079
  userId: session?.customer?.id,
2539
3080
  firstName: session?.customer?.firstName,
2540
3081
  lastName: session?.customer?.lastName,
2541
- totalAmount: session ? Math.round((0, import_shared6.buildCheckoutDisplayData)(session).total * 100) : 0,
3082
+ totalAmount: session ? Math.round((0, import_shared7.buildCheckoutDisplayData)(session).total * 100) : 0,
2542
3083
  currency: session?.currency?.toLowerCase() ?? "usd",
2543
3084
  onComplete,
2544
3085
  onError,
2545
3086
  onDecline,
3087
+ error: modeError,
3088
+ onErrorChange: setModeError,
2546
3089
  onFullNameChange,
2547
3090
  showPayPal,
2548
3091
  showApplePay,
@@ -2553,6 +3096,7 @@ function FloPayCheckout({
2553
3096
  cardButtonContent,
2554
3097
  cardBackButtonContent,
2555
3098
  cardTitleContent,
3099
+ showSecurityFooter,
2556
3100
  onButtonClick,
2557
3101
  onBeforeButtonClick,
2558
3102
  enableAVS,
@@ -2563,8 +3107,9 @@ function FloPayCheckout({
2563
3107
  submitLabel,
2564
3108
  className
2565
3109
  }
2566
- )
2567
- ] }) });
3110
+ ) }) }),
3111
+ modeOverlay
3112
+ ] });
2568
3113
  }
2569
3114
  function SessionInjector({
2570
3115
  sessionId,
@@ -2572,8 +3117,8 @@ function SessionInjector({
2572
3117
  session,
2573
3118
  children
2574
3119
  }) {
2575
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: import_react7.default.Children.map(children, (child) => {
2576
- if (!import_react7.default.isValidElement(child)) return child;
3120
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: import_react8.default.Children.map(children, (child) => {
3121
+ if (!import_react8.default.isValidElement(child)) return child;
2577
3122
  const existing = child.props;
2578
3123
  const injected = {};
2579
3124
  if (!existing.sessionId) injected.sessionId = sessionId;
@@ -2587,7 +3132,7 @@ function SessionInjector({
2587
3132
  injected.lastName = session.customer.lastName;
2588
3133
  }
2589
3134
  if (Object.keys(injected).length === 0) return child;
2590
- return import_react7.default.cloneElement(child, injected);
3135
+ return import_react8.default.cloneElement(child, injected);
2591
3136
  }) });
2592
3137
  }
2593
3138
  function InterimButtonsView({
@@ -2605,15 +3150,15 @@ function InterimButtonsView({
2605
3150
  cardBackButtonContent,
2606
3151
  cardTitleContent
2607
3152
  }) {
2608
- const [showCardForm, setShowCardForm] = (0, import_react7.useState)(false);
3153
+ const [showCardForm, setShowCardForm] = (0, import_react8.useState)(false);
2609
3154
  const isCardOpenControlled = typeof cardOpen === "boolean";
2610
- (0, import_react7.useEffect)(() => {
3155
+ (0, import_react8.useEffect)(() => {
2611
3156
  if (isCardOpenControlled) {
2612
3157
  setShowCardForm(cardOpen);
2613
3158
  }
2614
3159
  }, [cardOpen, isCardOpenControlled]);
2615
- const bStyles = (0, import_react7.useMemo)(() => {
2616
- const base = (0, import_shared6.resolveButtonsLayoutTheme)(buttonsTheme);
3160
+ const bStyles = (0, import_react8.useMemo)(() => {
3161
+ const base = (0, import_shared7.resolveButtonsLayoutTheme)(buttonsTheme);
2617
3162
  if (!stylesOverride) return base;
2618
3163
  return {
2619
3164
  ...base,
@@ -2626,7 +3171,7 @@ function InterimButtonsView({
2626
3171
  title: { ...base.title, ...stylesOverride.title }
2627
3172
  };
2628
3173
  }, [buttonsTheme, stylesOverride]);
2629
- const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
3174
+ const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2630
3175
  height: h,
2631
3176
  borderRadius: 8,
2632
3177
  background: "#e5e7eb",
@@ -2638,15 +3183,15 @@ function InterimButtonsView({
2638
3183
  const inputBg = bStyles.cardInputBackground ?? "white";
2639
3184
  const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
2640
3185
  const hideTitle = isEmptySlotContent(cardTitleContent);
2641
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
3186
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2642
3187
  backgroundColor: bStyles.cardFormContainer?.backgroundColor ?? "white",
2643
3188
  borderRadius: "8px",
2644
3189
  animation: "flopay-interim-expand 0.35s cubic-bezier(0.4, 0, 0.2, 1) both",
2645
3190
  overflow: "hidden",
2646
3191
  ...bStyles.cardFormContainer
2647
3192
  }, children: [
2648
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
2649
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3193
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
3194
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2650
3195
  "button",
2651
3196
  {
2652
3197
  type: "button",
@@ -2673,7 +3218,7 @@ function InterimButtonsView({
2673
3218
  ...bStyles.backButton
2674
3219
  },
2675
3220
  children: [
2676
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: {
3221
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
2677
3222
  display: "inline-flex",
2678
3223
  alignItems: "center",
2679
3224
  justifyContent: "center",
@@ -2682,12 +3227,12 @@ function InterimButtonsView({
2682
3227
  borderRadius: "50%",
2683
3228
  backgroundColor: "#f3f4f6",
2684
3229
  ...bStyles.backButtonIcon
2685
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
2686
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
3230
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
3231
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
2687
3232
  ]
2688
3233
  }
2689
3234
  ),
2690
- hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
3235
+ hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2691
3236
  flex: 1,
2692
3237
  textAlign: "center",
2693
3238
  fontWeight: 600,
@@ -2695,15 +3240,15 @@ function InterimButtonsView({
2695
3240
  color: "#262833",
2696
3241
  paddingRight: 80,
2697
3242
  ...bStyles.title
2698
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) })
3243
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
2699
3244
  ] }),
2700
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
2701
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex" }, children: [
2702
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderRight: "none", borderBottomLeftRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
2703
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderBottomRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
3245
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3246
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
3247
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderRight: "none", borderBottomLeftRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3248
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderBottomRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
2704
3249
  ] }),
2705
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
2706
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
3250
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3251
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2707
3252
  height: 50,
2708
3253
  borderRadius: 8,
2709
3254
  marginTop: 16,
@@ -2712,7 +3257,7 @@ function InterimButtonsView({
2712
3257
  ...bStyles.submitButton,
2713
3258
  opacity: 0.5
2714
3259
  } }),
2715
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
3260
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
2716
3261
  @keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
2717
3262
  @keyframes flopay-interim-expand {
2718
3263
  0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
@@ -2722,10 +3267,10 @@ function InterimButtonsView({
2722
3267
  ` })
2723
3268
  ] });
2724
3269
  }
2725
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
3270
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2726
3271
  showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2727
3272
  (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2728
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3273
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2729
3274
  "button",
2730
3275
  {
2731
3276
  type: "button",
@@ -2765,10 +3310,10 @@ function InterimButtonsView({
2765
3310
  onMouseUp: (e) => {
2766
3311
  e.currentTarget.style.transform = "scale(1)";
2767
3312
  },
2768
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardButtonContentSlot, { content: cardButtonContent })
3313
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
2769
3314
  }
2770
3315
  ),
2771
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
3316
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2772
3317
  margin: "0.25rem 0",
2773
3318
  padding: "0.625rem 0.875rem",
2774
3319
  background: "#FEF2F2",
@@ -2782,21 +3327,21 @@ function InterimButtonsView({
2782
3327
  gap: "0.5rem",
2783
3328
  ...bStyles.errorBanner
2784
3329
  }, children: [
2785
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.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" }) }),
3330
+ /* @__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" }) }),
2786
3331
  errorMessage
2787
3332
  ] }),
2788
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
3333
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2789
3334
  ] });
2790
3335
  }
2791
3336
 
2792
3337
  // src/checkout-form.tsx
2793
- var import_shared7 = require("@flopay/shared");
2794
- var import_react8 = require("react");
2795
- var import_jsx_runtime6 = require("react/jsx-runtime");
3338
+ var import_shared8 = require("@flopay/shared");
3339
+ var import_react9 = require("react");
3340
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2796
3341
  var WALLET_RESUME_KEY2 = "flopay_wallet_resume";
2797
- var CheckoutForm = (0, import_react8.forwardRef)(
3342
+ var CheckoutForm = (0, import_react9.forwardRef)(
2798
3343
  function CheckoutForm2(props, ref) {
2799
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
3344
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
2800
3345
  }
2801
3346
  );
2802
3347
  function CheckoutFormInner({
@@ -2822,29 +3367,30 @@ function CheckoutFormInner({
2822
3367
  innerRef
2823
3368
  }) {
2824
3369
  const flopay = useFloPay();
3370
+ const paypalFlopay = usePayPalFloPay();
2825
3371
  const elements = useElements();
2826
3372
  const contextBillingUrl = useBillingApiUrl();
2827
- const [processing, setProcessing] = (0, import_react8.useState)(false);
2828
- const [error, setError] = (0, import_react8.useState)(null);
2829
- const [is3DSActive, setIs3DSActive] = (0, import_react8.useState)(false);
3373
+ const [processing, setProcessing] = (0, import_react9.useState)(false);
3374
+ const [error, setError] = (0, import_react9.useState)(null);
3375
+ const [is3DSActive, setIs3DSActive] = (0, import_react9.useState)(false);
2830
3376
  const displayError = externalError ?? error;
2831
3377
  const isSubmitting = externalProcessing ?? processing;
2832
3378
  const isSelfContained = !onTokenizedBody;
2833
3379
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
2834
- const updateError = (0, import_react8.useCallback)(
3380
+ const updateError = (0, import_react9.useCallback)(
2835
3381
  (err) => {
2836
3382
  setError(err);
2837
3383
  onErrorChange?.(err);
2838
3384
  },
2839
3385
  [onErrorChange]
2840
3386
  );
2841
- const emitDecline = (0, import_react8.useCallback)(
3387
+ const emitDecline = (0, import_react9.useCallback)(
2842
3388
  (input, overrides) => {
2843
3389
  onDecline?.(buildDeclineEvent("card", input, overrides));
2844
3390
  },
2845
3391
  [onDecline]
2846
3392
  );
2847
- const processPaymentInternal = (0, import_react8.useCallback)(
3393
+ const processPaymentInternal = (0, import_react9.useCallback)(
2848
3394
  async (tokenizedBody) => {
2849
3395
  setProcessing(true);
2850
3396
  updateError(null);
@@ -2870,7 +3416,8 @@ function CheckoutFormInner({
2870
3416
  if (response.ok) {
2871
3417
  onComplete?.({
2872
3418
  status: "succeeded",
2873
- paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId
3419
+ paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
3420
+ paymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
2874
3421
  });
2875
3422
  return;
2876
3423
  }
@@ -2897,7 +3444,8 @@ function CheckoutFormInner({
2897
3444
  await processPaymentInternal({
2898
3445
  id: result.paymentIntentId,
2899
3446
  type: "card",
2900
- threeDSecureActionResultTokenId: result.paymentIntentId
3447
+ threeDSecureActionResultTokenId: result.paymentIntentId,
3448
+ originalPaymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
2901
3449
  });
2902
3450
  }
2903
3451
  } finally {
@@ -2906,20 +3454,35 @@ function CheckoutFormInner({
2906
3454
  return;
2907
3455
  }
2908
3456
  if (json?.type === "paypal_redirect_required") {
2909
- const secret = json["clientSecret"];
3457
+ const secret = json["threeDSecureToken"] ?? json["clientSecret"];
2910
3458
  const pmId = json["paymentMethodId"];
2911
- if (flopay && secret) {
2912
- localStorage.setItem(WALLET_RESUME_KEY2, JSON.stringify({
2913
- sessionId,
2914
- paymentIntentId: "",
2915
- tokenType: "card",
2916
- tokenId: pmId,
2917
- status: "pending_redirect"
2918
- }));
2919
- await flopay.confirmPayment({
2920
- clientSecret: secret,
2921
- returnUrl: window.location.href
2922
- });
3459
+ const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
3460
+ if (!paypalStripe || !secret) {
3461
+ const message = "PayPal is not available.";
3462
+ updateError(message);
3463
+ onDecline?.(buildDeclineEvent("paypal", message));
3464
+ return;
3465
+ }
3466
+ localStorage.setItem(WALLET_RESUME_KEY2, JSON.stringify({
3467
+ sessionId,
3468
+ paymentIntentId: "",
3469
+ tokenType: "card",
3470
+ tokenId: pmId ?? "",
3471
+ status: "pending_redirect"
3472
+ }));
3473
+ const confirmParams = {
3474
+ return_url: window.location.href
3475
+ };
3476
+ if (pmId) confirmParams["payment_method"] = pmId;
3477
+ const { error: confirmError } = await paypalStripe.confirmPayment({
3478
+ clientSecret: secret,
3479
+ confirmParams,
3480
+ redirect: "if_required"
3481
+ });
3482
+ if (confirmError) {
3483
+ const message = confirmError.message ?? "PayPal payment failed.";
3484
+ updateError(message);
3485
+ onDecline?.(buildDeclineEvent("paypal", message, { code: confirmError.code }));
2923
3486
  }
2924
3487
  return;
2925
3488
  }
@@ -2935,9 +3498,9 @@ function CheckoutFormInner({
2935
3498
  setProcessing(false);
2936
3499
  }
2937
3500
  },
2938
- [baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, onComplete, onError, updateError, emitDecline]
3501
+ [baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
2939
3502
  );
2940
- const dispatchTokenizedBody = (0, import_react8.useCallback)(
3503
+ const dispatchTokenizedBody = (0, import_react9.useCallback)(
2941
3504
  (tokenizedBody) => {
2942
3505
  if (onTokenizedBody) {
2943
3506
  onTokenizedBody(tokenizedBody);
@@ -2947,7 +3510,7 @@ function CheckoutFormInner({
2947
3510
  },
2948
3511
  [onTokenizedBody, processPaymentInternal]
2949
3512
  );
2950
- (0, import_react8.useImperativeHandle)(innerRef, () => ({
3513
+ (0, import_react9.useImperativeHandle)(innerRef, () => ({
2951
3514
  async handleNextAction(secret) {
2952
3515
  if (!flopay) return;
2953
3516
  setIs3DSActive(true);
@@ -2974,7 +3537,7 @@ function CheckoutFormInner({
2974
3537
  }
2975
3538
  }
2976
3539
  }), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
2977
- (0, import_react8.useEffect)(() => {
3540
+ (0, import_react9.useEffect)(() => {
2978
3541
  if (typeof window === "undefined") return;
2979
3542
  const stored = localStorage.getItem(WALLET_RESUME_KEY2);
2980
3543
  if (!stored) return;
@@ -2992,7 +3555,7 @@ function CheckoutFormInner({
2992
3555
  localStorage.removeItem(WALLET_RESUME_KEY2);
2993
3556
  }
2994
3557
  }, [sessionId, dispatchTokenizedBody]);
2995
- const handleSubmit = (0, import_react8.useCallback)(
3558
+ const handleSubmit = (0, import_react9.useCallback)(
2996
3559
  async (e) => {
2997
3560
  e.preventDefault();
2998
3561
  if (!flopay || !elements || isSubmitting) return;
@@ -3011,7 +3574,7 @@ function CheckoutFormInner({
3011
3574
  return;
3012
3575
  }
3013
3576
  if (!sessionId || !email) {
3014
- throw new import_shared7.FloPayError("Missing sessionId or email", "validation_error");
3577
+ throw new import_shared8.FloPayError("Missing sessionId or email", "validation_error");
3015
3578
  }
3016
3579
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
3017
3580
  method: "POST",
@@ -3023,10 +3586,10 @@ function CheckoutFormInner({
3023
3586
  isPaypal: false
3024
3587
  })
3025
3588
  });
3026
- if (!intentResponse.ok) throw new import_shared7.FloPayError("Failed to create payment intent", "api_error");
3589
+ if (!intentResponse.ok) throw new import_shared8.FloPayError("Failed to create payment intent", "api_error");
3027
3590
  const intentJson = await intentResponse.json();
3028
3591
  const intentClientSecret = intentJson.data?.id;
3029
- if (!intentClientSecret) throw new import_shared7.FloPayError("No client_secret in payment intent response", "api_error");
3592
+ if (!intentClientSecret) throw new import_shared8.FloPayError("No client_secret in payment intent response", "api_error");
3030
3593
  const confirmResult = await flopay.confirmCardPayment({
3031
3594
  clientSecret: intentClientSecret,
3032
3595
  paymentMethodId: pmResult.paymentMethodId
@@ -3040,7 +3603,8 @@ function CheckoutFormInner({
3040
3603
  dispatchTokenizedBody({
3041
3604
  id: pmResult.paymentMethodId,
3042
3605
  type: "card",
3043
- threeDSecureActionResultTokenId: confirmResult.paymentIntentId
3606
+ threeDSecureActionResultTokenId: confirmResult.paymentIntentId,
3607
+ originalPaymentMethodId: pmResult.paymentMethodId
3044
3608
  });
3045
3609
  } catch (err) {
3046
3610
  updateError(err instanceof Error ? err.message : "An unexpected error occurred");
@@ -3054,8 +3618,8 @@ function CheckoutFormInner({
3054
3618
  [flopay, elements, isSubmitting, sessionId, email, baseUrl, isSelfContained, dispatchTokenizedBody, onError, updateError, emitDecline]
3055
3619
  );
3056
3620
  const isReady = flopay !== null && elements !== null;
3057
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
3058
- (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-overlay", style: {
3621
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
3622
+ (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-overlay", style: {
3059
3623
  position: "absolute",
3060
3624
  inset: 0,
3061
3625
  background: "rgba(255,255,255,0.7)",
@@ -3064,12 +3628,12 @@ function CheckoutFormInner({
3064
3628
  justifyContent: "center",
3065
3629
  zIndex: 10
3066
3630
  }, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
3067
- !isReady && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
3068
- isReady && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3069
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaymentElement, { options: { layout } }),
3070
- showAddress && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
3071
- displayError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
3072
- children ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3631
+ !isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
3632
+ isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3633
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PaymentElement, { options: { layout } }),
3634
+ showAddress && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
3635
+ displayError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
3636
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3073
3637
  "button",
3074
3638
  {
3075
3639
  type: "submit",
@@ -3083,9 +3647,9 @@ function CheckoutFormInner({
3083
3647
  }
3084
3648
 
3085
3649
  // src/paypal-button.tsx
3086
- var import_shared8 = require("@flopay/shared");
3087
- var import_react9 = require("react");
3088
- var import_jsx_runtime7 = require("react/jsx-runtime");
3650
+ var import_shared9 = require("@flopay/shared");
3651
+ var import_react10 = require("react");
3652
+ var import_jsx_runtime8 = require("react/jsx-runtime");
3089
3653
  function PayPalButton({
3090
3654
  sessionId,
3091
3655
  billingApiUrl,
@@ -3102,11 +3666,11 @@ function PayPalButton({
3102
3666
  const flopay = useFloPay();
3103
3667
  const elements = useElements();
3104
3668
  const contextBillingUrl = useBillingApiUrl();
3105
- const [ready, setReady] = (0, import_react9.useState)(false);
3106
- const [submitting, setSubmitting] = (0, import_react9.useState)(false);
3107
- const paypalResumeAttempted = (0, import_react9.useRef)(false);
3669
+ const [ready, setReady] = (0, import_react10.useState)(false);
3670
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
3671
+ const paypalResumeAttempted = (0, import_react10.useRef)(false);
3108
3672
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
3109
- const processPaymentInternal = (0, import_react9.useCallback)(
3673
+ const processPaymentInternal = (0, import_react10.useCallback)(
3110
3674
  async (tokenizedBody) => {
3111
3675
  try {
3112
3676
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
@@ -3139,7 +3703,7 @@ function PayPalButton({
3139
3703
  },
3140
3704
  [baseUrl, sessionId, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
3141
3705
  );
3142
- const dispatchTokenizedBody = (0, import_react9.useCallback)(
3706
+ const dispatchTokenizedBody = (0, import_react10.useCallback)(
3143
3707
  (body) => {
3144
3708
  if (onTokenizedBody) {
3145
3709
  onTokenizedBody(body);
@@ -3149,7 +3713,7 @@ function PayPalButton({
3149
3713
  },
3150
3714
  [onTokenizedBody, processPaymentInternal]
3151
3715
  );
3152
- (0, import_react9.useEffect)(() => {
3716
+ (0, import_react10.useEffect)(() => {
3153
3717
  if (!flopay || paypalResumeAttempted.current) return;
3154
3718
  const params = new URLSearchParams(window.location.search);
3155
3719
  const paymentIntentId = params.get("payment_intent");
@@ -3197,13 +3761,13 @@ function PayPalButton({
3197
3761
  }
3198
3762
  })();
3199
3763
  }, [flopay, dispatchTokenizedBody, onErrorChange]);
3200
- const handlePayPalConfirm = (0, import_react9.useCallback)(async () => {
3764
+ const handlePayPalConfirm = (0, import_react10.useCallback)(async () => {
3201
3765
  if (!flopay || !elements) return;
3202
3766
  try {
3203
3767
  setSubmitting(true);
3204
3768
  onErrorChange?.(null);
3205
3769
  if (!sessionId || !email) {
3206
- throw new import_shared8.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
3770
+ throw new import_shared9.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
3207
3771
  }
3208
3772
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
3209
3773
  method: "POST",
@@ -3215,10 +3779,10 @@ function PayPalButton({
3215
3779
  isPaypal: "true"
3216
3780
  })
3217
3781
  });
3218
- if (!intentResponse.ok) throw new import_shared8.FloPayError("Failed to create payment intent", "api_error");
3782
+ if (!intentResponse.ok) throw new import_shared9.FloPayError("Failed to create payment intent", "api_error");
3219
3783
  const intentJson = await intentResponse.json();
3220
3784
  const intentClientSecret = intentJson.data?.id;
3221
- if (!intentClientSecret) throw new import_shared8.FloPayError("No client_secret in response", "api_error");
3785
+ if (!intentClientSecret) throw new import_shared9.FloPayError("No client_secret in response", "api_error");
3222
3786
  const result = await flopay.confirmPayment({
3223
3787
  clientSecret: intentClientSecret,
3224
3788
  returnUrl: window.location.href
@@ -3240,11 +3804,11 @@ function PayPalButton({
3240
3804
  }
3241
3805
  }, [flopay, elements, sessionId, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
3242
3806
  if (!flopay || !elements) {
3243
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
3807
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
3244
3808
  }
3245
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3246
- !ready && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
3247
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3809
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
3810
+ !ready && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
3811
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3248
3812
  "button",
3249
3813
  {
3250
3814
  type: "button",
@@ -3266,7 +3830,7 @@ function PayPalButton({
3266
3830
  children: submitting ? "Processing..." : "PayPal"
3267
3831
  }
3268
3832
  ) }),
3269
- (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3833
+ (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
3270
3834
  position: "fixed",
3271
3835
  inset: 0,
3272
3836
  background: "rgba(0,0,0,0.4)",
@@ -3274,7 +3838,7 @@ function PayPalButton({
3274
3838
  alignItems: "center",
3275
3839
  justifyContent: "center",
3276
3840
  zIndex: 1e3
3277
- }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3841
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
3278
3842
  background: "white",
3279
3843
  borderRadius: 8,
3280
3844
  padding: "1.5rem",
@@ -3284,6 +3848,676 @@ function PayPalButton({
3284
3848
  }, children: "Processing PayPal payment..." }) })
3285
3849
  ] });
3286
3850
  }
3851
+
3852
+ // src/automatic-payment-button.tsx
3853
+ var import_react11 = require("react");
3854
+ var import_js3 = require("@flopay/js");
3855
+ var import_shared10 = require("@flopay/shared");
3856
+ var import_jsx_runtime9 = require("react/jsx-runtime");
3857
+ var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
3858
+ var PAYPAL_RESUME_STORAGE_KEY = "flopay_automatic_payment_button_resume";
3859
+ function sleep2(ms) {
3860
+ return new Promise((resolve) => setTimeout(resolve, ms));
3861
+ }
3862
+ function coerceError(err, fallbackMessage) {
3863
+ if (err instanceof import_shared10.FloPayError) {
3864
+ return err;
3865
+ }
3866
+ return new import_shared10.FloPayError(
3867
+ err instanceof Error ? err.message : fallbackMessage,
3868
+ "api_error"
3869
+ );
3870
+ }
3871
+ function canUseStorage() {
3872
+ return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
3873
+ }
3874
+ function shouldShowFallbackCheckout(error, sessionId) {
3875
+ if (!sessionId) return false;
3876
+ if (error.type === "validation_error") return false;
3877
+ if (error.checkoutMethod && error.checkoutMethod !== "card") return false;
3878
+ return true;
3879
+ }
3880
+ function readPayPalResumeState() {
3881
+ if (!canUseStorage()) return null;
3882
+ try {
3883
+ const raw = window.sessionStorage.getItem(PAYPAL_RESUME_STORAGE_KEY);
3884
+ if (!raw) return null;
3885
+ return JSON.parse(raw);
3886
+ } catch {
3887
+ return null;
3888
+ }
3889
+ }
3890
+ function persistPayPalResumeState(state) {
3891
+ if (!canUseStorage()) return;
3892
+ try {
3893
+ window.sessionStorage.setItem(PAYPAL_RESUME_STORAGE_KEY, JSON.stringify(state));
3894
+ } catch (error) {
3895
+ console.warn("[FloPayAutomaticPaymentButton] Failed to persist PayPal resume state.", error);
3896
+ }
3897
+ }
3898
+ function clearPayPalResumeState() {
3899
+ if (!canUseStorage()) return;
3900
+ try {
3901
+ window.sessionStorage.removeItem(PAYPAL_RESUME_STORAGE_KEY);
3902
+ } catch (error) {
3903
+ console.warn("[FloPayAutomaticPaymentButton] Failed to clear PayPal resume state.", error);
3904
+ }
3905
+ }
3906
+ function clearPayPalRedirectParams() {
3907
+ if (typeof window === "undefined") return;
3908
+ const url = new URL(window.location.href);
3909
+ const keys = ["payment_intent", "payment_intent_client_secret", "redirect_status"];
3910
+ let changed = false;
3911
+ for (const key of keys) {
3912
+ if (url.searchParams.has(key)) {
3913
+ url.searchParams.delete(key);
3914
+ changed = true;
3915
+ }
3916
+ }
3917
+ if (changed) {
3918
+ window.history.replaceState({}, "", url.toString());
3919
+ }
3920
+ }
3921
+ function resolveCreateSessionDraft(props) {
3922
+ if (props.createSession) {
3923
+ return {
3924
+ ...props.createSession,
3925
+ checkoutMode: "auto"
3926
+ };
3927
+ }
3928
+ if (!props.clientId || !props.account || !props.successUrl || !props.cancelUrl) {
3929
+ return null;
3930
+ }
3931
+ return {
3932
+ clientId: props.clientId,
3933
+ items: props.items,
3934
+ subscriptions: props.subscriptions,
3935
+ account: props.account,
3936
+ successUrl: props.successUrl,
3937
+ cancelUrl: props.cancelUrl,
3938
+ couponCodes: props.couponCodes,
3939
+ tagsData: props.tagsData,
3940
+ utmMetadata: props.utmMetadata,
3941
+ checkoutMode: "auto"
3942
+ };
3943
+ }
3944
+ function FloPayAutomaticPaymentButton({
3945
+ sessionId,
3946
+ createSession,
3947
+ paymentMethodId,
3948
+ clientId,
3949
+ items,
3950
+ subscriptions,
3951
+ account,
3952
+ successUrl,
3953
+ cancelUrl,
3954
+ couponCodes,
3955
+ tagsData,
3956
+ utmMetadata,
3957
+ billingApiUrl,
3958
+ locale,
3959
+ fallbackPublishableKey,
3960
+ buttonsTheme,
3961
+ buttonsStyles: stylesOverride,
3962
+ onSuccess,
3963
+ onError,
3964
+ onDecline,
3965
+ children,
3966
+ disabled = false,
3967
+ type = "button",
3968
+ style,
3969
+ ...buttonProps
3970
+ }) {
3971
+ const resolvedBillingUrl = (0, import_react11.useMemo)(
3972
+ () => (0, import_shared10.resolveBillingApiUrl)(billingApiUrl),
3973
+ [billingApiUrl]
3974
+ );
3975
+ const createSessionDraft = (0, import_react11.useMemo)(
3976
+ () => resolveCreateSessionDraft({
3977
+ createSession,
3978
+ clientId,
3979
+ items,
3980
+ subscriptions,
3981
+ account,
3982
+ successUrl,
3983
+ cancelUrl,
3984
+ couponCodes,
3985
+ tagsData,
3986
+ utmMetadata
3987
+ }),
3988
+ [
3989
+ account,
3990
+ cancelUrl,
3991
+ clientId,
3992
+ couponCodes,
3993
+ createSession,
3994
+ items,
3995
+ subscriptions,
3996
+ successUrl,
3997
+ tagsData,
3998
+ utmMetadata
3999
+ ]
4000
+ );
4001
+ const [isProcessing, setIsProcessing] = (0, import_react11.useState)(false);
4002
+ const [overlayStatus, setOverlayStatus] = (0, import_react11.useState)(null);
4003
+ const [overlayError, setOverlayError] = (0, import_react11.useState)(null);
4004
+ const [fallbackSession, setFallbackSession] = (0, import_react11.useState)(null);
4005
+ const automaticPaymentToken = (0, import_react11.useMemo)(
4006
+ () => paymentMethodId ? {
4007
+ id: paymentMethodId,
4008
+ type: "card"
4009
+ } : void 0,
4010
+ [paymentMethodId]
4011
+ );
4012
+ const isMountedRef = (0, import_react11.useRef)(true);
4013
+ const resumeAttemptedRef = (0, import_react11.useRef)(false);
4014
+ const fallbackSessionRef = (0, import_react11.useRef)(fallbackSession);
4015
+ const onSuccessRef = (0, import_react11.useRef)(onSuccess);
4016
+ const onErrorRef = (0, import_react11.useRef)(onError);
4017
+ const onDeclineRef = (0, import_react11.useRef)(onDecline);
4018
+ (0, import_react11.useEffect)(() => {
4019
+ fallbackSessionRef.current = fallbackSession;
4020
+ }, [fallbackSession]);
4021
+ (0, import_react11.useEffect)(() => {
4022
+ onSuccessRef.current = onSuccess;
4023
+ }, [onSuccess]);
4024
+ (0, import_react11.useEffect)(() => {
4025
+ onErrorRef.current = onError;
4026
+ }, [onError]);
4027
+ (0, import_react11.useEffect)(() => {
4028
+ onDeclineRef.current = onDecline;
4029
+ }, [onDecline]);
4030
+ (0, import_react11.useEffect)(() => {
4031
+ isMountedRef.current = true;
4032
+ return () => {
4033
+ isMountedRef.current = false;
4034
+ };
4035
+ }, []);
4036
+ (0, import_react11.useEffect)(() => {
4037
+ if (!fallbackSession || typeof window === "undefined") {
4038
+ return;
4039
+ }
4040
+ const handleKeyDown = (event) => {
4041
+ if (event.key === "Escape") {
4042
+ setFallbackSession(null);
4043
+ }
4044
+ };
4045
+ window.addEventListener("keydown", handleKeyDown);
4046
+ return () => {
4047
+ window.removeEventListener("keydown", handleKeyDown);
4048
+ };
4049
+ }, [fallbackSession]);
4050
+ const emitDecline = (0, import_react11.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
4051
+ onDeclineRef.current?.(buildDeclineEvent(method, error, {
4052
+ code: error.code,
4053
+ declineCode: error.declineCode
4054
+ }));
4055
+ }, []);
4056
+ const showSuccess = (0, import_react11.useCallback)(async (event) => {
4057
+ if (!isMountedRef.current) return;
4058
+ setOverlayError(null);
4059
+ setOverlayStatus("success");
4060
+ await sleep2(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
4061
+ if (!isMountedRef.current) return;
4062
+ onSuccessRef.current?.(event);
4063
+ }, []);
4064
+ const showError = (0, import_react11.useCallback)(async (error, options) => {
4065
+ if (!isMountedRef.current) return;
4066
+ onErrorRef.current?.(error);
4067
+ if (options?.emitDecline) {
4068
+ emitDecline(error, options.method);
4069
+ }
4070
+ setOverlayError(error.message);
4071
+ setOverlayStatus("error");
4072
+ await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
4073
+ }, [emitDecline]);
4074
+ const processResolvedSession = (0, import_react11.useCallback)(async (apiResult, resolvedSessionId) => {
4075
+ const session = apiResult.data.session ?? null;
4076
+ if (!session) {
4077
+ throw new import_shared10.FloPayError("No session data returned", "api_error");
4078
+ }
4079
+ if (session.status === "complete") {
4080
+ await showSuccess({
4081
+ result: { status: "succeeded" },
4082
+ session,
4083
+ sessionId: session.id || resolvedSessionId,
4084
+ autoCompleted: false
4085
+ });
4086
+ return;
4087
+ }
4088
+ try {
4089
+ const result = await processSavedPaymentForMode({
4090
+ billingApiUrl: resolvedBillingUrl,
4091
+ sessionId: resolvedSessionId ?? session.id,
4092
+ session,
4093
+ tokenizedData: automaticPaymentToken
4094
+ });
4095
+ let paymentResult = result.type === "success" ? result.result : null;
4096
+ if (result.type !== "success") {
4097
+ const {
4098
+ publishableKey,
4099
+ paypalPublishableKey
4100
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4101
+ if (result.type === "paypal_redirect_required") {
4102
+ persistPayPalResumeState({
4103
+ sessionId: session.id || resolvedSessionId,
4104
+ publishableKey,
4105
+ paypalPublishableKey
4106
+ });
4107
+ }
4108
+ const {
4109
+ flopay,
4110
+ paypalFlopay
4111
+ } = await loadSavedPaymentProviders({
4112
+ publishableKey,
4113
+ paypalPublishableKey,
4114
+ billingApiUrl: resolvedBillingUrl,
4115
+ locale
4116
+ });
4117
+ paymentResult = await handleSavedPaymentRedirectResult(result, {
4118
+ flopay,
4119
+ paypalFlopay,
4120
+ attempt3DS: true,
4121
+ billingApiUrl: resolvedBillingUrl,
4122
+ sessionId: session.id || resolvedSessionId,
4123
+ session
4124
+ });
4125
+ if (result.type === "paypal_redirect_required") {
4126
+ clearPayPalResumeState();
4127
+ }
4128
+ }
4129
+ await showSuccess({
4130
+ result: paymentResult ? {
4131
+ ...paymentResult,
4132
+ paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId
4133
+ } : {
4134
+ status: "succeeded",
4135
+ paymentMethodId: paymentMethodId ?? void 0
4136
+ },
4137
+ session,
4138
+ sessionId: session.id || resolvedSessionId,
4139
+ autoCompleted: false
4140
+ });
4141
+ } catch (err) {
4142
+ let floPayErr = normalizeSavedPaymentError(err);
4143
+ const fallbackSessionId = session.id || resolvedSessionId;
4144
+ if (floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4145
+ try {
4146
+ const {
4147
+ publishableKey,
4148
+ paypalPublishableKey
4149
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4150
+ const {
4151
+ flopay
4152
+ } = await loadSavedPaymentProviders({
4153
+ publishableKey,
4154
+ paypalPublishableKey,
4155
+ billingApiUrl: resolvedBillingUrl,
4156
+ locale
4157
+ });
4158
+ const paymentResult = await processSavedPaymentWithIntent({
4159
+ billingApiUrl: resolvedBillingUrl,
4160
+ sessionId: fallbackSessionId,
4161
+ session,
4162
+ paymentMethodId: automaticPaymentToken.id,
4163
+ flopay
4164
+ });
4165
+ await showSuccess({
4166
+ result: {
4167
+ ...paymentResult,
4168
+ paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId
4169
+ },
4170
+ session,
4171
+ sessionId: fallbackSessionId,
4172
+ autoCompleted: false
4173
+ });
4174
+ return;
4175
+ } catch (intentRecoveryErr) {
4176
+ floPayErr = normalizeSavedPaymentError(intentRecoveryErr);
4177
+ }
4178
+ }
4179
+ await showError(floPayErr, {
4180
+ emitDecline: true,
4181
+ method: floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD
4182
+ });
4183
+ if (shouldShowFallbackCheckout(floPayErr, fallbackSessionId) && fallbackSessionId && isMountedRef.current) {
4184
+ setFallbackSession({
4185
+ sessionId: fallbackSessionId,
4186
+ errorMessage: floPayErr.message
4187
+ });
4188
+ }
4189
+ }
4190
+ }, [
4191
+ fallbackPublishableKey,
4192
+ locale,
4193
+ automaticPaymentToken,
4194
+ paymentMethodId,
4195
+ resolvedBillingUrl,
4196
+ showError,
4197
+ showSuccess
4198
+ ]);
4199
+ const handleButtonClick = (0, import_react11.useCallback)(async (event) => {
4200
+ buttonProps.onClick?.(event);
4201
+ if (event.defaultPrevented || disabled || isProcessing) {
4202
+ return;
4203
+ }
4204
+ setFallbackSession(null);
4205
+ if (sessionId && createSessionDraft) {
4206
+ const error = new import_shared10.FloPayError(
4207
+ "Provide either sessionId or create-session props, not both.",
4208
+ "validation_error"
4209
+ );
4210
+ await showError(error);
4211
+ if (isMountedRef.current) {
4212
+ setOverlayStatus(null);
4213
+ setOverlayError(null);
4214
+ }
4215
+ return;
4216
+ }
4217
+ if (!sessionId && !createSessionDraft) {
4218
+ const error = new import_shared10.FloPayError(
4219
+ "Provide a sessionId or the props required to create an automatic payment session.",
4220
+ "validation_error"
4221
+ );
4222
+ await showError(error);
4223
+ if (isMountedRef.current) {
4224
+ setOverlayStatus(null);
4225
+ setOverlayError(null);
4226
+ }
4227
+ return;
4228
+ }
4229
+ setIsProcessing(true);
4230
+ setOverlayError(null);
4231
+ setOverlayStatus("processing");
4232
+ try {
4233
+ const api = new import_js3.PaymentAPI(resolvedBillingUrl);
4234
+ if (sessionId) {
4235
+ const result = await api.getUnifiedCheckoutSession(sessionId);
4236
+ await processResolvedSession(result, sessionId);
4237
+ return;
4238
+ }
4239
+ try {
4240
+ const result = await api.createAndFetchSession(createSessionDraft);
4241
+ await processResolvedSession(result, result.data.session?.id ?? null);
4242
+ } catch (err) {
4243
+ if (err instanceof import_shared10.FloPayError && err.code === "session_auto_completed") {
4244
+ await showSuccess({
4245
+ result: { status: "succeeded" },
4246
+ session: null,
4247
+ sessionId: null,
4248
+ autoCompleted: true
4249
+ });
4250
+ return;
4251
+ }
4252
+ throw err;
4253
+ }
4254
+ } catch (err) {
4255
+ await showError(
4256
+ coerceError(err, "Automatic payment failed. Please try again.")
4257
+ );
4258
+ } finally {
4259
+ if (isMountedRef.current) {
4260
+ setOverlayStatus(null);
4261
+ setOverlayError(null);
4262
+ setIsProcessing(false);
4263
+ }
4264
+ }
4265
+ }, [
4266
+ buttonProps,
4267
+ createSessionDraft,
4268
+ disabled,
4269
+ isProcessing,
4270
+ processResolvedSession,
4271
+ resolvedBillingUrl,
4272
+ sessionId,
4273
+ showError,
4274
+ showSuccess
4275
+ ]);
4276
+ const handleFallbackComplete = (0, import_react11.useCallback)((result) => {
4277
+ const activeFallback = fallbackSessionRef.current;
4278
+ setFallbackSession(null);
4279
+ onSuccessRef.current?.({
4280
+ result,
4281
+ session: null,
4282
+ sessionId: activeFallback?.sessionId ?? null,
4283
+ autoCompleted: false
4284
+ });
4285
+ }, []);
4286
+ const handleFallbackError = (0, import_react11.useCallback)((error) => {
4287
+ onErrorRef.current?.(error);
4288
+ }, []);
4289
+ const handleFallbackDecline = (0, import_react11.useCallback)((decline) => {
4290
+ onDeclineRef.current?.(decline);
4291
+ }, []);
4292
+ (0, import_react11.useEffect)(() => {
4293
+ if (typeof window === "undefined" || resumeAttemptedRef.current) {
4294
+ return;
4295
+ }
4296
+ const params = new URLSearchParams(window.location.search);
4297
+ const clientSecret = params.get("payment_intent_client_secret");
4298
+ if (!clientSecret) {
4299
+ return;
4300
+ }
4301
+ const resumeState = readPayPalResumeState();
4302
+ if (!resumeState) {
4303
+ return;
4304
+ }
4305
+ resumeAttemptedRef.current = true;
4306
+ void (async () => {
4307
+ setIsProcessing(true);
4308
+ setOverlayError(null);
4309
+ setOverlayStatus("processing");
4310
+ try {
4311
+ if (params.get("redirect_status") === "failed") {
4312
+ throw Object.assign(
4313
+ new import_shared10.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
4314
+ { checkoutMethod: "paypal" }
4315
+ );
4316
+ }
4317
+ const {
4318
+ flopay,
4319
+ paypalFlopay
4320
+ } = await loadSavedPaymentProviders({
4321
+ publishableKey: resumeState.publishableKey,
4322
+ paypalPublishableKey: resumeState.paypalPublishableKey,
4323
+ billingApiUrl: resolvedBillingUrl,
4324
+ locale
4325
+ });
4326
+ const paypalStripe = (paypalFlopay ?? flopay).getRawProvider();
4327
+ if (!paypalStripe) {
4328
+ throw Object.assign(
4329
+ new import_shared10.FloPayError("PayPal is not available.", "api_error"),
4330
+ { checkoutMethod: "paypal" }
4331
+ );
4332
+ }
4333
+ const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
4334
+ if (error) {
4335
+ throw Object.assign(
4336
+ new import_shared10.FloPayError(
4337
+ error.message ?? "Failed to retrieve PayPal payment status.",
4338
+ "api_error",
4339
+ { code: error.code }
4340
+ ),
4341
+ { checkoutMethod: "paypal" }
4342
+ );
4343
+ }
4344
+ if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded" || paymentIntent.status === "processing")) {
4345
+ await showSuccess({
4346
+ result: { status: "succeeded", paymentIntentId: paymentIntent.id },
4347
+ session: null,
4348
+ sessionId: resumeState.sessionId,
4349
+ autoCompleted: false
4350
+ });
4351
+ } else {
4352
+ throw Object.assign(
4353
+ new import_shared10.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
4354
+ { checkoutMethod: "paypal" }
4355
+ );
4356
+ }
4357
+ } catch (err) {
4358
+ const floPayErr = normalizeSavedPaymentError(err);
4359
+ await showError(floPayErr, {
4360
+ emitDecline: true,
4361
+ method: floPayErr.checkoutMethod ?? "paypal"
4362
+ });
4363
+ } finally {
4364
+ clearPayPalResumeState();
4365
+ clearPayPalRedirectParams();
4366
+ if (isMountedRef.current) {
4367
+ setOverlayStatus(null);
4368
+ setOverlayError(null);
4369
+ setIsProcessing(false);
4370
+ }
4371
+ }
4372
+ })();
4373
+ }, [locale, resolvedBillingUrl, showError, showSuccess]);
4374
+ const bStyles = (0, import_react11.useMemo)(() => {
4375
+ const base = (0, import_shared10.resolveButtonsLayoutTheme)(buttonsTheme);
4376
+ if (!stylesOverride) return base;
4377
+ return {
4378
+ ...base,
4379
+ ...stylesOverride,
4380
+ cardButton: { ...base.cardButton, ...stylesOverride.cardButton }
4381
+ };
4382
+ }, [buttonsTheme, stylesOverride]);
4383
+ const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
4384
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
4385
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4386
+ "button",
4387
+ {
4388
+ ...buttonProps,
4389
+ type,
4390
+ onClick: handleButtonClick,
4391
+ disabled: disabled || isProcessing,
4392
+ "aria-busy": isProcessing,
4393
+ style: {
4394
+ width: "100%",
4395
+ ...cardButtonSizing,
4396
+ backgroundColor: "white",
4397
+ color: "#262833",
4398
+ border: "1px solid #d1d5db",
4399
+ borderRadius: "8px",
4400
+ fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
4401
+ fontWeight: 600,
4402
+ cursor: disabled || isProcessing ? "not-allowed" : "pointer",
4403
+ display: "flex",
4404
+ alignItems: "center",
4405
+ justifyContent: "center",
4406
+ gap: "0.625rem",
4407
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
4408
+ transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
4409
+ position: "relative",
4410
+ opacity: disabled || isProcessing ? 0.6 : 1,
4411
+ ...bStyles.cardButton,
4412
+ ...style
4413
+ },
4414
+ onMouseDown: (e) => {
4415
+ buttonProps.onMouseDown?.(e);
4416
+ if (!e.defaultPrevented) {
4417
+ e.currentTarget.style.transform = "scale(0.985)";
4418
+ }
4419
+ },
4420
+ onMouseUp: (e) => {
4421
+ buttonProps.onMouseUp?.(e);
4422
+ if (!e.defaultPrevented) {
4423
+ e.currentTarget.style.transform = "scale(1)";
4424
+ }
4425
+ },
4426
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CardButtonContentSlot, { content: children })
4427
+ }
4428
+ ),
4429
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4430
+ ProcessingOverlay,
4431
+ {
4432
+ status: overlayStatus,
4433
+ errorMessage: overlayError
4434
+ }
4435
+ ),
4436
+ fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4437
+ "div",
4438
+ {
4439
+ "data-testid": "flopay-automatic-payment-fallback",
4440
+ role: "dialog",
4441
+ "aria-modal": "true",
4442
+ onClick: (event) => {
4443
+ if (event.target === event.currentTarget) {
4444
+ setFallbackSession(null);
4445
+ }
4446
+ },
4447
+ style: {
4448
+ position: "fixed",
4449
+ inset: 0,
4450
+ background: "rgba(0, 0, 0, 0.45)",
4451
+ display: "flex",
4452
+ alignItems: "center",
4453
+ justifyContent: "center",
4454
+ padding: "1.5rem",
4455
+ zIndex: 1100
4456
+ },
4457
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4458
+ "div",
4459
+ {
4460
+ style: {
4461
+ width: "100%",
4462
+ maxWidth: 520,
4463
+ maxHeight: "90vh",
4464
+ overflowY: "auto",
4465
+ background: "white",
4466
+ borderRadius: 20,
4467
+ padding: "1.5rem",
4468
+ boxShadow: "0 24px 80px rgba(15, 23, 42, 0.28)",
4469
+ display: "flex",
4470
+ flexDirection: "column",
4471
+ gap: "1rem"
4472
+ },
4473
+ children: [
4474
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4475
+ "div",
4476
+ {
4477
+ style: {
4478
+ display: "flex",
4479
+ gap: "1rem",
4480
+ alignItems: "flex-start"
4481
+ },
4482
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4483
+ "div",
4484
+ {
4485
+ style: {
4486
+ flex: 1,
4487
+ background: "#fef2f2",
4488
+ color: "#b91c1c",
4489
+ border: "1px solid #fecaca",
4490
+ borderRadius: "12px",
4491
+ padding: "0.75rem 1rem",
4492
+ fontSize: "0.9rem",
4493
+ lineHeight: 1.5
4494
+ },
4495
+ children: fallbackSession.errorMessage
4496
+ }
4497
+ )
4498
+ }
4499
+ ),
4500
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4501
+ FloPayCheckout,
4502
+ {
4503
+ sessionId: fallbackSession.sessionId,
4504
+ checkoutMode: "full",
4505
+ billingApiUrl: resolvedBillingUrl,
4506
+ fallbackPublishableKey,
4507
+ cardTitleContent: null,
4508
+ showSecurityFooter: false,
4509
+ onComplete: handleFallbackComplete,
4510
+ onError: handleFallbackError,
4511
+ onDecline: handleFallbackDecline
4512
+ }
4513
+ )
4514
+ ]
4515
+ }
4516
+ )
4517
+ }
4518
+ )
4519
+ ] });
4520
+ }
3287
4521
  // Annotate the CommonJS export names for ESM import in node:
3288
4522
  0 && (module.exports = {
3289
4523
  AddressElement,
@@ -3292,6 +4526,7 @@ function PayPalButton({
3292
4526
  CardExpiryElement,
3293
4527
  CardNumberElement,
3294
4528
  CheckoutForm,
4529
+ FloPayAutomaticPaymentButton,
3295
4530
  FloPayCheckout,
3296
4531
  FloPayProvider,
3297
4532
  PayPalButton,