@flopay/react 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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,183 +2438,148 @@ function FloPayCheckout({
1884
2438
  cardButtonContent,
1885
2439
  cardBackButtonContent,
1886
2440
  cardTitleContent,
2441
+ showSecurityFooter = true,
1887
2442
  onButtonClick,
1888
2443
  onBeforeButtonClick,
1889
2444
  enableAVS,
1890
2445
  avsLayout,
1891
2446
  submitLabel,
1892
2447
  className,
2448
+ initialErrorMessage = null,
1893
2449
  children,
1894
2450
  checkoutMode: checkoutModeProp,
1895
2451
  confirmLabel,
1896
2452
  renderConfirmButton,
1897
2453
  onSessionCompleted
1898
2454
  }) {
1899
- const resolvedBillingUrl = (0, import_shared6.resolveBillingApiUrl)(billingApiUrl);
2455
+ const resolvedBillingUrl = (0, import_shared7.resolveBillingApiUrl)(billingApiUrl);
1900
2456
  const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
1901
2457
  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);
2458
+ const [unified, setUnified] = (0, import_react8.useState)(null);
2459
+ const [flopay, setFloPay] = (0, import_react8.useState)(null);
2460
+ const flopayRef = (0, import_react8.useRef)(null);
2461
+ const [paypalFlopay, setPaypalFloPay] = (0, import_react8.useState)(null);
2462
+ const paypalFlopayRef = (0, import_react8.useRef)(null);
2463
+ const [session, setSession] = (0, import_react8.useState)(null);
2464
+ const [resolvedSessionId, setResolvedSessionId] = (0, import_react8.useState)(sessionIdProp ?? "");
2465
+ const activeSessionId = sessionIdProp ?? resolvedSessionId;
2466
+ const initSessionDependency = createSessionParams ? "" : activeSessionId;
2467
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(true);
2468
+ const [loadError, setLoadError] = (0, import_react8.useState)(null);
2469
+ const [currentMode, setCurrentMode] = (0, import_react8.useState)("full");
2470
+ const [confirmProcessing, setConfirmProcessing] = (0, import_react8.useState)(false);
2471
+ const [modeError, setModeError] = (0, import_react8.useState)(initialErrorMessage);
2472
+ const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react8.useState)(null);
2473
+ const [modeOverlayError, setModeOverlayError] = (0, import_react8.useState)(null);
2474
+ const [createSessionPatch, setCreateSessionPatch] = (0, import_react8.useState)(void 0);
2475
+ const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react8.useState)("");
2476
+ const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react8.useState)(false);
2477
+ const autoCheckoutAttempted = (0, import_react8.useRef)(false);
2478
+ const onCompleteRef = (0, import_react8.useRef)(onComplete);
1919
2479
  onCompleteRef.current = onComplete;
1920
- const onErrorRef = (0, import_react7.useRef)(onError);
2480
+ const onErrorRef = (0, import_react8.useRef)(onError);
1921
2481
  onErrorRef.current = onError;
1922
- const onDeclineRef = (0, import_react7.useRef)(onDecline);
2482
+ const onDeclineRef = (0, import_react8.useRef)(onDecline);
1923
2483
  onDeclineRef.current = onDecline;
1924
- const onSessionCompletedRef = (0, import_react7.useRef)(onSessionCompleted);
2484
+ const onSessionCompletedRef = (0, import_react8.useRef)(onSessionCompleted);
1925
2485
  onSessionCompletedRef.current = onSessionCompleted;
1926
- (0, import_react7.useEffect)(() => {
2486
+ (0, import_react8.useEffect)(() => {
1927
2487
  console.info("[FloPay] Checkout initialized", {
1928
- sdk_version: import_shared6.SDK_VERSION,
2488
+ sdk_version: import_shared7.SDK_VERSION,
1929
2489
  checkout_type: checkoutType,
1930
2490
  checkout_layout: checkoutLayout,
1931
2491
  billing_api_url: resolvedBillingUrl
1932
2492
  });
1933
2493
  }, [checkoutLayout, checkoutType, resolvedBillingUrl]);
1934
- const baseCreateSessionHash = (0, import_react7.useMemo)(
2494
+ const baseCreateSessionHash = (0, import_react8.useMemo)(
1935
2495
  () => createSessionParams ? hashCreateParams(createSessionParams) : "",
1936
2496
  [createSessionParams]
1937
2497
  );
1938
- const activeCreateSessionPatch = (0, import_react7.useMemo)(
2498
+ const activeCreateSessionPatch = (0, import_react8.useMemo)(
1939
2499
  () => createSessionPatchBaseHash === baseCreateSessionHash ? createSessionPatch : void 0,
1940
2500
  [createSessionPatch, createSessionPatchBaseHash, baseCreateSessionHash]
1941
2501
  );
1942
- const effectiveCreateSession = (0, import_react7.useMemo)(
2502
+ const effectiveCreateSessionBase = (0, import_react8.useMemo)(
1943
2503
  () => createSessionParams ? mergeInlineSessionPatch(createSessionParams, activeCreateSessionPatch) : void 0,
1944
2504
  [createSessionParams, activeCreateSessionPatch]
1945
2505
  );
1946
- (0, import_react7.useEffect)(() => {
2506
+ const effectiveCreateSessionMode = checkoutModeProp ?? effectiveCreateSessionBase?.checkoutMode ?? "full";
2507
+ const effectiveCreateSession = (0, import_react8.useMemo)(
2508
+ () => effectiveCreateSessionBase ? {
2509
+ ...effectiveCreateSessionBase,
2510
+ checkoutMode: effectiveCreateSessionMode
2511
+ } : void 0,
2512
+ [effectiveCreateSessionBase, effectiveCreateSessionMode]
2513
+ );
2514
+ (0, import_react8.useEffect)(() => {
1947
2515
  setCreateSessionPatch(void 0);
1948
2516
  setCreateSessionPatchBaseHash(baseCreateSessionHash);
1949
2517
  }, [baseCreateSessionHash]);
1950
- const emitDecline = (0, import_react7.useCallback)(
2518
+ (0, import_react8.useEffect)(() => {
2519
+ setModeError(initialErrorMessage);
2520
+ }, [initialErrorMessage]);
2521
+ const emitDecline = (0, import_react8.useCallback)(
1951
2522
  (method, input, overrides) => {
1952
2523
  onDeclineRef.current?.(buildDeclineEvent(method, input, overrides));
1953
2524
  },
1954
2525
  []
1955
2526
  );
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
2527
+ const runSavedPaymentFlow = (0, import_react8.useCallback)(
2528
+ async (sess, options) => {
2529
+ setModeError(null);
2530
+ setModeOverlayError(null);
2531
+ setModeOverlayStatus("processing");
2532
+ const activeSessionId2 = options?.sessionId ?? sess.id;
2533
+ try {
2534
+ const result = await processSavedPaymentForMode({
2535
+ billingApiUrl: resolvedBillingUrl,
2536
+ sessionId: activeSessionId2,
2537
+ session: sess
2017
2538
  });
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"
2539
+ const paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2540
+ flopay: flopayRef.current,
2541
+ paypalFlopay: paypalFlopayRef.current,
2542
+ attempt3DS: options?.attempt3DS,
2543
+ billingApiUrl: resolvedBillingUrl,
2544
+ sessionId: activeSessionId2,
2545
+ session: sess
2047
2546
  });
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" });
2547
+ setModeOverlayStatus("success");
2548
+ await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2549
+ onCompleteRef.current?.(paymentResult);
2056
2550
  return true;
2551
+ } catch (err) {
2552
+ const floPayErr = normalizeSavedPaymentError(err);
2553
+ const method = floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD;
2554
+ setModeError(floPayErr.message);
2555
+ setModeOverlayError(floPayErr.message);
2556
+ if (options?.fallbackToFull) {
2557
+ setCurrentMode("full");
2558
+ }
2559
+ onErrorRef.current?.(floPayErr);
2560
+ emitDecline(method, floPayErr, {
2561
+ code: floPayErr.code,
2562
+ declineCode: floPayErr.declineCode
2563
+ });
2564
+ setModeOverlayStatus("error");
2565
+ await Promise.allSettled([
2566
+ sleep(PROCESSING_OVERLAY_ERROR_DELAY_MS),
2567
+ options?.ensureProvidersReady ? options.ensureProvidersReady() : Promise.resolve()
2568
+ ]);
2569
+ return false;
2570
+ } finally {
2571
+ setModeOverlayStatus(null);
2572
+ setModeOverlayError(null);
2057
2573
  }
2058
- return false;
2059
2574
  },
2060
- [resolvedBillingUrl, resolvedSessionId, emitDecline]
2575
+ [
2576
+ emitDecline,
2577
+ normalizeSavedPaymentError,
2578
+ resolvedBillingUrl
2579
+ ]
2061
2580
  );
2062
- const inflightRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2063
- const initializedHashRef = (0, import_react7.useRef)(null);
2581
+ const inflightRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
2582
+ const initializedHashRef = (0, import_react8.useRef)(null);
2064
2583
  function hashCreateParams(params) {
2065
2584
  const key = JSON.stringify({
2066
2585
  c: params?.clientId,
@@ -2080,17 +2599,23 @@ function FloPayCheckout({
2080
2599
  }
2081
2600
  return `flopay_session_${Math.abs(h).toString(36)}`;
2082
2601
  }
2083
- const createSessionHash = (0, import_react7.useMemo)(
2602
+ const createSessionHash = (0, import_react8.useMemo)(
2084
2603
  () => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
2085
2604
  [effectiveCreateSession]
2086
2605
  );
2087
- const createSessionParamsRef = (0, import_react7.useRef)(effectiveCreateSession);
2606
+ const createSessionParamsRef = (0, import_react8.useRef)(effectiveCreateSession);
2088
2607
  createSessionParamsRef.current = effectiveCreateSession;
2089
- (0, import_react7.useEffect)(() => {
2608
+ (0, import_react8.useEffect)(() => {
2090
2609
  setResolvedSessionId(sessionIdProp ?? "");
2091
2610
  }, [sessionIdProp]);
2611
+ (0, import_react8.useEffect)(() => {
2612
+ autoCheckoutAttempted.current = false;
2613
+ setModeError(initialErrorMessage);
2614
+ setModeOverlayError(null);
2615
+ setModeOverlayStatus(null);
2616
+ }, [createSessionHash, initialErrorMessage, sessionIdProp]);
2092
2617
  async function resolveInlineSession(params, cacheKey) {
2093
- const api = new import_js.PaymentAPI(resolvedBillingUrl);
2618
+ const api = new import_js2.PaymentAPI(resolvedBillingUrl);
2094
2619
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
2095
2620
  let realResult = null;
2096
2621
  if (sid) {
@@ -2115,11 +2640,11 @@ function FloPayCheckout({
2115
2640
  }
2116
2641
  return { sid: sid ?? "", result: realResult };
2117
2642
  }
2118
- const bootstrapInlineSession = (0, import_react7.useCallback)(
2643
+ const bootstrapInlineSession = (0, import_react8.useCallback)(
2119
2644
  async (patch) => {
2120
2645
  const baseParams = createSessionParamsRef.current;
2121
2646
  if (!baseParams) {
2122
- throw new import_shared6.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
2647
+ throw new import_shared7.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
2123
2648
  }
2124
2649
  const mergedParams = mergeInlineSessionPatch(baseParams, patch);
2125
2650
  const cacheKey = hashCreateParams(mergedParams);
@@ -2148,43 +2673,23 @@ function FloPayCheckout({
2148
2673
  if (sid) {
2149
2674
  setResolvedSessionId(sid);
2150
2675
  }
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
- ]);
2676
+ const {
2677
+ publishableKey,
2678
+ paypalPublishableKey
2679
+ } = resolveSavedPaymentPublishableKeys(realResult, fallbackPublishableKey);
2680
+ const {
2681
+ flopay: instance,
2682
+ paypalFlopay: paypalInstance
2683
+ } = await loadSavedPaymentProviders({
2684
+ publishableKey,
2685
+ paypalPublishableKey,
2686
+ billingApiUrl: resolvedBillingUrl,
2687
+ locale
2688
+ });
2178
2689
  flopayRef.current = instance;
2179
2690
  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
- }
2691
+ paypalFlopayRef.current = paypalInstance;
2692
+ setPaypalFloPay(paypalInstance);
2188
2693
  setIsLoading(false);
2189
2694
  } catch (err) {
2190
2695
  if (initializedHashRef.current === cacheKey) {
@@ -2196,7 +2701,7 @@ function FloPayCheckout({
2196
2701
  },
2197
2702
  [fallbackPublishableKey, locale, resolvedBillingUrl]
2198
2703
  );
2199
- const handleInlineSessionPatch = (0, import_react7.useCallback)(async (patch) => {
2704
+ const handleInlineSessionPatch = (0, import_react8.useCallback)(async (patch) => {
2200
2705
  if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
2201
2706
  return {
2202
2707
  sessionId: resolvedSessionId,
@@ -2219,21 +2724,61 @@ function FloPayCheckout({
2219
2724
  resolvedSessionId,
2220
2725
  session
2221
2726
  ]);
2222
- (0, import_react7.useEffect)(() => {
2727
+ (0, import_react8.useEffect)(() => {
2223
2728
  let cancelled = false;
2224
2729
  setLoadError(null);
2225
2730
  if (createSessionHash) {
2226
- if (initializedHashRef.current === createSessionHash) return;
2227
2731
  const params = createSessionParamsRef.current;
2228
2732
  setSession(buildSyntheticSession(params, checkoutModeProp));
2229
- setCurrentMode(params.checkoutMode ?? checkoutModeProp ?? "full");
2733
+ setCurrentMode(effectiveCreateSessionMode);
2230
2734
  setIsLoading(false);
2735
+ if (initializedHashRef.current === createSessionHash) {
2736
+ return () => {
2737
+ cancelled = true;
2738
+ };
2739
+ }
2231
2740
  (async () => {
2741
+ const shouldAutoProcessInlineSession = effectiveCreateSessionMode === "auto" && !autoCheckoutAttempted.current;
2742
+ if (shouldAutoProcessInlineSession) {
2743
+ setModeError(null);
2744
+ setModeOverlayError(null);
2745
+ setModeOverlayStatus("processing");
2746
+ }
2232
2747
  try {
2233
- await bootstrapInlineSession();
2748
+ const resolved = await bootstrapInlineSession();
2749
+ const resolvedSession = resolved.result.data.session ?? null;
2750
+ if (!cancelled && shouldAutoProcessInlineSession && resolvedSession) {
2751
+ autoCheckoutAttempted.current = true;
2752
+ await runSavedPaymentFlow(resolvedSession, {
2753
+ attempt3DS: true,
2754
+ fallbackToFull: true,
2755
+ sessionId: resolved.sid || resolvedSession.id
2756
+ });
2757
+ return;
2758
+ }
2759
+ if (!cancelled && shouldAutoProcessInlineSession) {
2760
+ setModeOverlayStatus(null);
2761
+ setModeOverlayError(null);
2762
+ }
2234
2763
  } catch (err) {
2235
2764
  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");
2765
+ const errorCode = err instanceof import_shared7.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
2766
+ if (shouldAutoProcessInlineSession && errorCode === "session_auto_completed") {
2767
+ autoCheckoutAttempted.current = true;
2768
+ setModeOverlayStatus("success");
2769
+ await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2770
+ if (!cancelled) {
2771
+ onCompleteRef.current?.({ status: "succeeded" });
2772
+ setModeOverlayStatus(null);
2773
+ setModeOverlayError(null);
2774
+ }
2775
+ return;
2776
+ }
2777
+ if (shouldAutoProcessInlineSession) {
2778
+ setModeOverlayStatus(null);
2779
+ setModeOverlayError(null);
2780
+ }
2781
+ const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
2237
2782
  setLoadError(floPayErr);
2238
2783
  }
2239
2784
  })();
@@ -2244,14 +2789,14 @@ function FloPayCheckout({
2244
2789
  setIsLoading(true);
2245
2790
  async function init() {
2246
2791
  try {
2247
- const api = new import_js.PaymentAPI(resolvedBillingUrl);
2248
- const result = await api.getUnifiedCheckoutSession(resolvedSessionId);
2792
+ const api = new import_js2.PaymentAPI(resolvedBillingUrl);
2793
+ const result = await api.getUnifiedCheckoutSession(activeSessionId);
2249
2794
  if (cancelled) return;
2250
2795
  setUnified(result);
2251
2796
  const sess = result.data.session ?? null;
2252
2797
  setSession(sess);
2253
2798
  if (!sess) {
2254
- throw new import_shared6.FloPayError("No session data returned", "api_error");
2799
+ throw new import_shared7.FloPayError("No session data returned", "api_error");
2255
2800
  }
2256
2801
  if (sess.status === "complete") {
2257
2802
  setIsLoading(false);
@@ -2265,22 +2810,20 @@ function FloPayCheckout({
2265
2810
  autoCheckoutAttempted.current = true;
2266
2811
  const stripeInitPromise = initStripe(result);
2267
2812
  try {
2268
- const redirectResult = await processPaymentForMode(sess);
2269
- if (!redirectResult) {
2270
- if (!cancelled) setIsLoading(false);
2271
- return;
2272
- }
2813
+ await runSavedPaymentFlow(sess, {
2814
+ attempt3DS: true,
2815
+ fallbackToFull: true,
2816
+ ensureProvidersReady: () => stripeInitPromise,
2817
+ sessionId: activeSessionId || sess.id
2818
+ });
2273
2819
  if (cancelled) return;
2274
2820
  await stripeInitPromise;
2275
- const handled = await handleRedirectResult(redirectResult, sess, { attempt3DS: true });
2276
2821
  if (!cancelled) {
2277
- if (!handled) setCurrentMode("full");
2278
2822
  setIsLoading(false);
2279
2823
  }
2280
2824
  return;
2281
2825
  } catch {
2282
2826
  if (cancelled) return;
2283
- setCurrentMode("full");
2284
2827
  await stripeInitPromise;
2285
2828
  if (!cancelled) setIsLoading(false);
2286
2829
  return;
@@ -2290,82 +2833,56 @@ function FloPayCheckout({
2290
2833
  if (!cancelled) setIsLoading(false);
2291
2834
  } catch (err) {
2292
2835
  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");
2836
+ const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
2294
2837
  setLoadError(floPayErr);
2295
2838
  setIsLoading(false);
2296
2839
  }
2297
2840
  }
2298
2841
  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
- ]);
2842
+ const {
2843
+ publishableKey,
2844
+ paypalPublishableKey
2845
+ } = resolveSavedPaymentPublishableKeys(result, fallbackPublishableKey);
2846
+ const {
2847
+ flopay: instance,
2848
+ paypalFlopay: paypalInstance
2849
+ } = await loadSavedPaymentProviders({
2850
+ publishableKey,
2851
+ paypalPublishableKey,
2852
+ billingApiUrl: resolvedBillingUrl,
2853
+ locale
2854
+ });
2326
2855
  flopayRef.current = instance;
2327
2856
  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
- }
2857
+ paypalFlopayRef.current = paypalInstance;
2858
+ setPaypalFloPay(paypalInstance);
2336
2859
  }
2337
2860
  init();
2338
2861
  return () => {
2339
2862
  cancelled = true;
2340
2863
  };
2341
- }, [resolvedSessionId, createSessionHash, checkoutModeProp, bootstrapInlineSession]);
2342
- const handleConfirmCheckout = (0, import_react7.useCallback)(async () => {
2864
+ }, [
2865
+ bootstrapInlineSession,
2866
+ checkoutModeProp,
2867
+ createSessionHash,
2868
+ effectiveCreateSessionMode,
2869
+ initSessionDependency,
2870
+ runSavedPaymentFlow
2871
+ ]);
2872
+ const handleConfirmCheckout = (0, import_react8.useCallback)(async () => {
2343
2873
  if (confirmProcessing || !session) return;
2344
2874
  setConfirmProcessing(true);
2345
2875
  setModeError(null);
2346
2876
  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");
2877
+ await runSavedPaymentFlow(session, {
2878
+ fallbackToFull: true,
2879
+ sessionId: activeSessionId || session.id
2880
+ });
2364
2881
  } finally {
2365
2882
  setConfirmProcessing(false);
2366
2883
  }
2367
- }, [confirmProcessing, session, processPaymentForMode, handleRedirectResult, onError, emitDecline]);
2368
- const providerOptions = (0, import_react7.useMemo)(() => {
2884
+ }, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
2885
+ const providerOptions = (0, import_react8.useMemo)(() => {
2369
2886
  if (!unified || !session) return void 0;
2370
2887
  const opts = {
2371
2888
  appearance,
@@ -2375,16 +2892,16 @@ function FloPayCheckout({
2375
2892
  if (unified.provider === "stripe" && unified.data.stripe?.clientSecret) {
2376
2893
  opts.clientSecret = unified.data.stripe.clientSecret;
2377
2894
  } else {
2378
- const displayTotal = (0, import_shared6.buildCheckoutDisplayData)(session).total;
2895
+ const displayTotal = (0, import_shared7.buildCheckoutDisplayData)(session).total;
2379
2896
  opts.amount = Math.round(displayTotal * 100) || session.amount;
2380
2897
  opts.currency = session.currency?.toLowerCase();
2381
2898
  }
2382
2899
  return opts;
2383
2900
  }, [unified, session, appearance, resolvedBillingUrl]);
2384
2901
  const shouldHandleInlineSessionPatch = Boolean(
2385
- createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && (effectiveCreateSession?.checkoutMode ?? checkoutModeProp ?? "full") === "full"
2902
+ createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && effectiveCreateSessionMode === "full"
2386
2903
  );
2387
- const checkoutValue = (0, import_react7.useMemo)(
2904
+ const checkoutValue = (0, import_react8.useMemo)(
2388
2905
  () => ({
2389
2906
  session,
2390
2907
  loading: isLoading,
@@ -2406,37 +2923,55 @@ function FloPayCheckout({
2406
2923
  ]
2407
2924
  );
2408
2925
  const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
2926
+ const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2927
+ ProcessingOverlay,
2928
+ {
2929
+ status: modeOverlayStatus,
2930
+ errorMessage: modeOverlayError
2931
+ }
2932
+ ) : null;
2409
2933
  if (isLoading) {
2410
- if (loadingNode) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: loadingNode });
2934
+ if (loadingNode) {
2935
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2936
+ loadingNode,
2937
+ modeOverlay
2938
+ ] });
2939
+ }
2411
2940
  if (layout === "buttons") {
2412
- const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2941
+ const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2413
2942
  height: h,
2414
2943
  borderRadius: 8,
2415
2944
  background: "#e5e7eb",
2416
2945
  animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
2417
2946
  } });
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; } }` })
2947
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2948
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2949
+ showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2950
+ (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2951
+ skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2952
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2953
+ ] }),
2954
+ modeOverlay
2423
2955
  ] });
2424
2956
  }
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); } }` })
2957
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2958
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
2959
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2960
+ width: 24,
2961
+ height: 24,
2962
+ border: "2px solid #e5e7eb",
2963
+ borderTopColor: "#6b7280",
2964
+ borderRadius: "50%",
2965
+ animation: "spin 0.6s linear infinite"
2966
+ } }),
2967
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
2968
+ ] }),
2969
+ modeOverlay
2435
2970
  ] });
2436
2971
  }
2437
2972
  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)(
2973
+ if (errorNode) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: errorNode(loadError) });
2974
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2440
2975
  "div",
2441
2976
  {
2442
2977
  style: {
@@ -2450,99 +2985,111 @@ function FloPayCheckout({
2450
2985
  );
2451
2986
  }
2452
2987
  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
- ) });
2988
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2989
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2990
+ InterimButtonsView,
2991
+ {
2992
+ onButtonClick,
2993
+ showPayPal,
2994
+ showApplePay,
2995
+ showGooglePay,
2996
+ buttonsTheme,
2997
+ buttonsStyles,
2998
+ cardButtonContent,
2999
+ cardBackButtonContent,
3000
+ cardTitleContent
3001
+ }
3002
+ ) }),
3003
+ modeOverlay
3004
+ ] });
3005
+ }
3006
+ if (!flopay || !providerOptions) {
3007
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: modeOverlay });
2467
3008
  }
2468
- if (!flopay || !providerOptions) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
2469
3009
  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)(
3010
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3011
+ /* @__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: [
3012
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3013
+ "div",
3014
+ {
3015
+ style: {
3016
+ color: "#dc2626",
3017
+ fontSize: "0.875rem",
3018
+ marginBottom: "0.75rem",
3019
+ textAlign: "center"
3020
+ },
3021
+ children: modeError
3022
+ }
3023
+ ),
3024
+ renderConfirmButton ? renderConfirmButton({
3025
+ onConfirm: handleConfirmCheckout,
3026
+ isProcessing: confirmProcessing
3027
+ }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3028
+ "button",
3029
+ {
3030
+ type: "button",
3031
+ onClick: handleConfirmCheckout,
3032
+ disabled: confirmProcessing,
3033
+ style: {
3034
+ width: "100%",
3035
+ padding: "0.875rem",
3036
+ backgroundColor: "#4A49FF",
3037
+ color: "white",
3038
+ border: "none",
3039
+ borderRadius: "8px",
3040
+ fontSize: "1rem",
3041
+ fontWeight: 600,
3042
+ cursor: confirmProcessing ? "not-allowed" : "pointer",
3043
+ opacity: confirmProcessing ? 0.6 : 1
3044
+ },
3045
+ children: confirmProcessing ? "Processing..." : confirmLabel ?? "Confirm Purchase"
3046
+ }
3047
+ )
3048
+ ] }) }) }),
3049
+ modeOverlay
3050
+ ] });
3051
+ }
3052
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3053
+ /* @__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: [
3054
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2472
3055
  "div",
2473
3056
  {
2474
3057
  style: {
2475
- color: "#dc2626",
2476
- fontSize: "0.875rem",
3058
+ padding: "0.75rem 1rem",
2477
3059
  marginBottom: "0.75rem",
2478
- textAlign: "center"
3060
+ backgroundColor: "#FEF3C7",
3061
+ border: "1px solid #F59E0B",
3062
+ borderRadius: "8px",
3063
+ color: "#92400E",
3064
+ fontSize: "0.875rem"
2479
3065
  },
2480
3066
  children: modeError
2481
3067
  }
2482
3068
  ),
2483
- renderConfirmButton ? renderConfirmButton({
2484
- onConfirm: handleConfirmCheckout,
2485
- isProcessing: confirmProcessing
2486
- }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2487
- "button",
3069
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3070
+ SessionInjector,
2488
3071
  {
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"
3072
+ sessionId: activeSessionId,
3073
+ billingApiUrl: resolvedBillingUrl,
3074
+ session,
3075
+ children
2505
3076
  }
2506
3077
  )
2507
- ] }) }) });
2508
- }
2509
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(FloPayProvider, { flopay, paypalFlopay, 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)(
3078
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2534
3079
  SplitCardForm,
2535
3080
  {
2536
- sessionId: resolvedSessionId,
3081
+ sessionId: activeSessionId,
2537
3082
  email: session?.customer?.email,
2538
3083
  userId: session?.customer?.id,
2539
3084
  firstName: session?.customer?.firstName,
2540
3085
  lastName: session?.customer?.lastName,
2541
- totalAmount: session ? Math.round((0, import_shared6.buildCheckoutDisplayData)(session).total * 100) : 0,
3086
+ totalAmount: session ? Math.round((0, import_shared7.buildCheckoutDisplayData)(session).total * 100) : 0,
2542
3087
  currency: session?.currency?.toLowerCase() ?? "usd",
2543
3088
  onComplete,
2544
3089
  onError,
2545
3090
  onDecline,
3091
+ error: modeError,
3092
+ onErrorChange: setModeError,
2546
3093
  onFullNameChange,
2547
3094
  showPayPal,
2548
3095
  showApplePay,
@@ -2553,6 +3100,7 @@ function FloPayCheckout({
2553
3100
  cardButtonContent,
2554
3101
  cardBackButtonContent,
2555
3102
  cardTitleContent,
3103
+ showSecurityFooter,
2556
3104
  onButtonClick,
2557
3105
  onBeforeButtonClick,
2558
3106
  enableAVS,
@@ -2563,8 +3111,9 @@ function FloPayCheckout({
2563
3111
  submitLabel,
2564
3112
  className
2565
3113
  }
2566
- )
2567
- ] }) });
3114
+ ) }) }),
3115
+ modeOverlay
3116
+ ] });
2568
3117
  }
2569
3118
  function SessionInjector({
2570
3119
  sessionId,
@@ -2572,8 +3121,8 @@ function SessionInjector({
2572
3121
  session,
2573
3122
  children
2574
3123
  }) {
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;
3124
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: import_react8.default.Children.map(children, (child) => {
3125
+ if (!import_react8.default.isValidElement(child)) return child;
2577
3126
  const existing = child.props;
2578
3127
  const injected = {};
2579
3128
  if (!existing.sessionId) injected.sessionId = sessionId;
@@ -2587,7 +3136,7 @@ function SessionInjector({
2587
3136
  injected.lastName = session.customer.lastName;
2588
3137
  }
2589
3138
  if (Object.keys(injected).length === 0) return child;
2590
- return import_react7.default.cloneElement(child, injected);
3139
+ return import_react8.default.cloneElement(child, injected);
2591
3140
  }) });
2592
3141
  }
2593
3142
  function InterimButtonsView({
@@ -2605,15 +3154,15 @@ function InterimButtonsView({
2605
3154
  cardBackButtonContent,
2606
3155
  cardTitleContent
2607
3156
  }) {
2608
- const [showCardForm, setShowCardForm] = (0, import_react7.useState)(false);
3157
+ const [showCardForm, setShowCardForm] = (0, import_react8.useState)(false);
2609
3158
  const isCardOpenControlled = typeof cardOpen === "boolean";
2610
- (0, import_react7.useEffect)(() => {
3159
+ (0, import_react8.useEffect)(() => {
2611
3160
  if (isCardOpenControlled) {
2612
3161
  setShowCardForm(cardOpen);
2613
3162
  }
2614
3163
  }, [cardOpen, isCardOpenControlled]);
2615
- const bStyles = (0, import_react7.useMemo)(() => {
2616
- const base = (0, import_shared6.resolveButtonsLayoutTheme)(buttonsTheme);
3164
+ const bStyles = (0, import_react8.useMemo)(() => {
3165
+ const base = (0, import_shared7.resolveButtonsLayoutTheme)(buttonsTheme);
2617
3166
  if (!stylesOverride) return base;
2618
3167
  return {
2619
3168
  ...base,
@@ -2626,7 +3175,7 @@ function InterimButtonsView({
2626
3175
  title: { ...base.title, ...stylesOverride.title }
2627
3176
  };
2628
3177
  }, [buttonsTheme, stylesOverride]);
2629
- const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
3178
+ const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2630
3179
  height: h,
2631
3180
  borderRadius: 8,
2632
3181
  background: "#e5e7eb",
@@ -2638,15 +3187,15 @@ function InterimButtonsView({
2638
3187
  const inputBg = bStyles.cardInputBackground ?? "white";
2639
3188
  const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
2640
3189
  const hideTitle = isEmptySlotContent(cardTitleContent);
2641
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
3190
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2642
3191
  backgroundColor: bStyles.cardFormContainer?.backgroundColor ?? "white",
2643
3192
  borderRadius: "8px",
2644
3193
  animation: "flopay-interim-expand 0.35s cubic-bezier(0.4, 0, 0.2, 1) both",
2645
3194
  overflow: "hidden",
2646
3195
  ...bStyles.cardFormContainer
2647
3196
  }, 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)(
3197
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
3198
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2650
3199
  "button",
2651
3200
  {
2652
3201
  type: "button",
@@ -2673,7 +3222,7 @@ function InterimButtonsView({
2673
3222
  ...bStyles.backButton
2674
3223
  },
2675
3224
  children: [
2676
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: {
3225
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
2677
3226
  display: "inline-flex",
2678
3227
  alignItems: "center",
2679
3228
  justifyContent: "center",
@@ -2682,12 +3231,12 @@ function InterimButtonsView({
2682
3231
  borderRadius: "50%",
2683
3232
  backgroundColor: "#f3f4f6",
2684
3233
  ...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 })
3234
+ }, 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" }) }) }),
3235
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
2687
3236
  ]
2688
3237
  }
2689
3238
  ),
2690
- hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
3239
+ hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2691
3240
  flex: 1,
2692
3241
  textAlign: "center",
2693
3242
  fontWeight: 600,
@@ -2695,15 +3244,15 @@ function InterimButtonsView({
2695
3244
  color: "#262833",
2696
3245
  paddingRight: 80,
2697
3246
  ...bStyles.title
2698
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) })
3247
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
2699
3248
  ] }),
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" } }) })
3249
+ /* @__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" } }) }),
3250
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
3251
+ /* @__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" } }) }),
3252
+ /* @__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
3253
  ] }),
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: {
3254
+ /* @__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" } }) }),
3255
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2707
3256
  height: 50,
2708
3257
  borderRadius: 8,
2709
3258
  marginTop: 16,
@@ -2712,7 +3261,7 @@ function InterimButtonsView({
2712
3261
  ...bStyles.submitButton,
2713
3262
  opacity: 0.5
2714
3263
  } }),
2715
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
3264
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
2716
3265
  @keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
2717
3266
  @keyframes flopay-interim-expand {
2718
3267
  0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
@@ -2722,10 +3271,10 @@ function InterimButtonsView({
2722
3271
  ` })
2723
3272
  ] });
2724
3273
  }
2725
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
3274
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2726
3275
  showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2727
3276
  (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2728
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3277
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2729
3278
  "button",
2730
3279
  {
2731
3280
  type: "button",
@@ -2765,10 +3314,10 @@ function InterimButtonsView({
2765
3314
  onMouseUp: (e) => {
2766
3315
  e.currentTarget.style.transform = "scale(1)";
2767
3316
  },
2768
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardButtonContentSlot, { content: cardButtonContent })
3317
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
2769
3318
  }
2770
3319
  ),
2771
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
3320
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2772
3321
  margin: "0.25rem 0",
2773
3322
  padding: "0.625rem 0.875rem",
2774
3323
  background: "#FEF2F2",
@@ -2782,21 +3331,21 @@ function InterimButtonsView({
2782
3331
  gap: "0.5rem",
2783
3332
  ...bStyles.errorBanner
2784
3333
  }, 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" }) }),
3334
+ /* @__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
3335
  errorMessage
2787
3336
  ] }),
2788
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
3337
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2789
3338
  ] });
2790
3339
  }
2791
3340
 
2792
3341
  // 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");
3342
+ var import_shared8 = require("@flopay/shared");
3343
+ var import_react9 = require("react");
3344
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2796
3345
  var WALLET_RESUME_KEY2 = "flopay_wallet_resume";
2797
- var CheckoutForm = (0, import_react8.forwardRef)(
3346
+ var CheckoutForm = (0, import_react9.forwardRef)(
2798
3347
  function CheckoutForm2(props, ref) {
2799
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
3348
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
2800
3349
  }
2801
3350
  );
2802
3351
  function CheckoutFormInner({
@@ -2825,27 +3374,27 @@ function CheckoutFormInner({
2825
3374
  const paypalFlopay = usePayPalFloPay();
2826
3375
  const elements = useElements();
2827
3376
  const contextBillingUrl = useBillingApiUrl();
2828
- const [processing, setProcessing] = (0, import_react8.useState)(false);
2829
- const [error, setError] = (0, import_react8.useState)(null);
2830
- const [is3DSActive, setIs3DSActive] = (0, import_react8.useState)(false);
3377
+ const [processing, setProcessing] = (0, import_react9.useState)(false);
3378
+ const [error, setError] = (0, import_react9.useState)(null);
3379
+ const [is3DSActive, setIs3DSActive] = (0, import_react9.useState)(false);
2831
3380
  const displayError = externalError ?? error;
2832
3381
  const isSubmitting = externalProcessing ?? processing;
2833
3382
  const isSelfContained = !onTokenizedBody;
2834
3383
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
2835
- const updateError = (0, import_react8.useCallback)(
3384
+ const updateError = (0, import_react9.useCallback)(
2836
3385
  (err) => {
2837
3386
  setError(err);
2838
3387
  onErrorChange?.(err);
2839
3388
  },
2840
3389
  [onErrorChange]
2841
3390
  );
2842
- const emitDecline = (0, import_react8.useCallback)(
3391
+ const emitDecline = (0, import_react9.useCallback)(
2843
3392
  (input, overrides) => {
2844
3393
  onDecline?.(buildDeclineEvent("card", input, overrides));
2845
3394
  },
2846
3395
  [onDecline]
2847
3396
  );
2848
- const processPaymentInternal = (0, import_react8.useCallback)(
3397
+ const processPaymentInternal = (0, import_react9.useCallback)(
2849
3398
  async (tokenizedBody) => {
2850
3399
  setProcessing(true);
2851
3400
  updateError(null);
@@ -2871,7 +3420,8 @@ function CheckoutFormInner({
2871
3420
  if (response.ok) {
2872
3421
  onComplete?.({
2873
3422
  status: "succeeded",
2874
- paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId
3423
+ paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
3424
+ paymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
2875
3425
  });
2876
3426
  return;
2877
3427
  }
@@ -2898,7 +3448,8 @@ function CheckoutFormInner({
2898
3448
  await processPaymentInternal({
2899
3449
  id: result.paymentIntentId,
2900
3450
  type: "card",
2901
- threeDSecureActionResultTokenId: result.paymentIntentId
3451
+ threeDSecureActionResultTokenId: result.paymentIntentId,
3452
+ originalPaymentMethodId: resolveTokenizedPaymentMethodId(tokenizedBody)
2902
3453
  });
2903
3454
  }
2904
3455
  } finally {
@@ -2953,7 +3504,7 @@ function CheckoutFormInner({
2953
3504
  },
2954
3505
  [baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
2955
3506
  );
2956
- const dispatchTokenizedBody = (0, import_react8.useCallback)(
3507
+ const dispatchTokenizedBody = (0, import_react9.useCallback)(
2957
3508
  (tokenizedBody) => {
2958
3509
  if (onTokenizedBody) {
2959
3510
  onTokenizedBody(tokenizedBody);
@@ -2963,7 +3514,7 @@ function CheckoutFormInner({
2963
3514
  },
2964
3515
  [onTokenizedBody, processPaymentInternal]
2965
3516
  );
2966
- (0, import_react8.useImperativeHandle)(innerRef, () => ({
3517
+ (0, import_react9.useImperativeHandle)(innerRef, () => ({
2967
3518
  async handleNextAction(secret) {
2968
3519
  if (!flopay) return;
2969
3520
  setIs3DSActive(true);
@@ -2990,7 +3541,7 @@ function CheckoutFormInner({
2990
3541
  }
2991
3542
  }
2992
3543
  }), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
2993
- (0, import_react8.useEffect)(() => {
3544
+ (0, import_react9.useEffect)(() => {
2994
3545
  if (typeof window === "undefined") return;
2995
3546
  const stored = localStorage.getItem(WALLET_RESUME_KEY2);
2996
3547
  if (!stored) return;
@@ -3008,7 +3559,7 @@ function CheckoutFormInner({
3008
3559
  localStorage.removeItem(WALLET_RESUME_KEY2);
3009
3560
  }
3010
3561
  }, [sessionId, dispatchTokenizedBody]);
3011
- const handleSubmit = (0, import_react8.useCallback)(
3562
+ const handleSubmit = (0, import_react9.useCallback)(
3012
3563
  async (e) => {
3013
3564
  e.preventDefault();
3014
3565
  if (!flopay || !elements || isSubmitting) return;
@@ -3027,7 +3578,7 @@ function CheckoutFormInner({
3027
3578
  return;
3028
3579
  }
3029
3580
  if (!sessionId || !email) {
3030
- throw new import_shared7.FloPayError("Missing sessionId or email", "validation_error");
3581
+ throw new import_shared8.FloPayError("Missing sessionId or email", "validation_error");
3031
3582
  }
3032
3583
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
3033
3584
  method: "POST",
@@ -3039,10 +3590,10 @@ function CheckoutFormInner({
3039
3590
  isPaypal: false
3040
3591
  })
3041
3592
  });
3042
- if (!intentResponse.ok) throw new import_shared7.FloPayError("Failed to create payment intent", "api_error");
3593
+ if (!intentResponse.ok) throw new import_shared8.FloPayError("Failed to create payment intent", "api_error");
3043
3594
  const intentJson = await intentResponse.json();
3044
3595
  const intentClientSecret = intentJson.data?.id;
3045
- if (!intentClientSecret) throw new import_shared7.FloPayError("No client_secret in payment intent response", "api_error");
3596
+ if (!intentClientSecret) throw new import_shared8.FloPayError("No client_secret in payment intent response", "api_error");
3046
3597
  const confirmResult = await flopay.confirmCardPayment({
3047
3598
  clientSecret: intentClientSecret,
3048
3599
  paymentMethodId: pmResult.paymentMethodId
@@ -3056,7 +3607,8 @@ function CheckoutFormInner({
3056
3607
  dispatchTokenizedBody({
3057
3608
  id: pmResult.paymentMethodId,
3058
3609
  type: "card",
3059
- threeDSecureActionResultTokenId: confirmResult.paymentIntentId
3610
+ threeDSecureActionResultTokenId: confirmResult.paymentIntentId,
3611
+ originalPaymentMethodId: pmResult.paymentMethodId
3060
3612
  });
3061
3613
  } catch (err) {
3062
3614
  updateError(err instanceof Error ? err.message : "An unexpected error occurred");
@@ -3070,8 +3622,8 @@ function CheckoutFormInner({
3070
3622
  [flopay, elements, isSubmitting, sessionId, email, baseUrl, isSelfContained, dispatchTokenizedBody, onError, updateError, emitDecline]
3071
3623
  );
3072
3624
  const isReady = flopay !== null && elements !== null;
3073
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
3074
- (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-overlay", style: {
3625
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
3626
+ (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-overlay", style: {
3075
3627
  position: "absolute",
3076
3628
  inset: 0,
3077
3629
  background: "rgba(255,255,255,0.7)",
@@ -3080,12 +3632,12 @@ function CheckoutFormInner({
3080
3632
  justifyContent: "center",
3081
3633
  zIndex: 10
3082
3634
  }, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
3083
- !isReady && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
3084
- isReady && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3085
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaymentElement, { options: { layout } }),
3086
- showAddress && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
3087
- displayError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
3088
- children ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3635
+ !isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
3636
+ isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3637
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PaymentElement, { options: { layout } }),
3638
+ showAddress && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
3639
+ displayError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
3640
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3089
3641
  "button",
3090
3642
  {
3091
3643
  type: "submit",
@@ -3099,9 +3651,9 @@ function CheckoutFormInner({
3099
3651
  }
3100
3652
 
3101
3653
  // src/paypal-button.tsx
3102
- var import_shared8 = require("@flopay/shared");
3103
- var import_react9 = require("react");
3104
- var import_jsx_runtime7 = require("react/jsx-runtime");
3654
+ var import_shared9 = require("@flopay/shared");
3655
+ var import_react10 = require("react");
3656
+ var import_jsx_runtime8 = require("react/jsx-runtime");
3105
3657
  function PayPalButton({
3106
3658
  sessionId,
3107
3659
  billingApiUrl,
@@ -3118,11 +3670,11 @@ function PayPalButton({
3118
3670
  const flopay = useFloPay();
3119
3671
  const elements = useElements();
3120
3672
  const contextBillingUrl = useBillingApiUrl();
3121
- const [ready, setReady] = (0, import_react9.useState)(false);
3122
- const [submitting, setSubmitting] = (0, import_react9.useState)(false);
3123
- const paypalResumeAttempted = (0, import_react9.useRef)(false);
3673
+ const [ready, setReady] = (0, import_react10.useState)(false);
3674
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
3675
+ const paypalResumeAttempted = (0, import_react10.useRef)(false);
3124
3676
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
3125
- const processPaymentInternal = (0, import_react9.useCallback)(
3677
+ const processPaymentInternal = (0, import_react10.useCallback)(
3126
3678
  async (tokenizedBody) => {
3127
3679
  try {
3128
3680
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
@@ -3155,7 +3707,7 @@ function PayPalButton({
3155
3707
  },
3156
3708
  [baseUrl, sessionId, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
3157
3709
  );
3158
- const dispatchTokenizedBody = (0, import_react9.useCallback)(
3710
+ const dispatchTokenizedBody = (0, import_react10.useCallback)(
3159
3711
  (body) => {
3160
3712
  if (onTokenizedBody) {
3161
3713
  onTokenizedBody(body);
@@ -3165,7 +3717,7 @@ function PayPalButton({
3165
3717
  },
3166
3718
  [onTokenizedBody, processPaymentInternal]
3167
3719
  );
3168
- (0, import_react9.useEffect)(() => {
3720
+ (0, import_react10.useEffect)(() => {
3169
3721
  if (!flopay || paypalResumeAttempted.current) return;
3170
3722
  const params = new URLSearchParams(window.location.search);
3171
3723
  const paymentIntentId = params.get("payment_intent");
@@ -3213,13 +3765,13 @@ function PayPalButton({
3213
3765
  }
3214
3766
  })();
3215
3767
  }, [flopay, dispatchTokenizedBody, onErrorChange]);
3216
- const handlePayPalConfirm = (0, import_react9.useCallback)(async () => {
3768
+ const handlePayPalConfirm = (0, import_react10.useCallback)(async () => {
3217
3769
  if (!flopay || !elements) return;
3218
3770
  try {
3219
3771
  setSubmitting(true);
3220
3772
  onErrorChange?.(null);
3221
3773
  if (!sessionId || !email) {
3222
- throw new import_shared8.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
3774
+ throw new import_shared9.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
3223
3775
  }
3224
3776
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
3225
3777
  method: "POST",
@@ -3231,10 +3783,10 @@ function PayPalButton({
3231
3783
  isPaypal: "true"
3232
3784
  })
3233
3785
  });
3234
- if (!intentResponse.ok) throw new import_shared8.FloPayError("Failed to create payment intent", "api_error");
3786
+ if (!intentResponse.ok) throw new import_shared9.FloPayError("Failed to create payment intent", "api_error");
3235
3787
  const intentJson = await intentResponse.json();
3236
3788
  const intentClientSecret = intentJson.data?.id;
3237
- if (!intentClientSecret) throw new import_shared8.FloPayError("No client_secret in response", "api_error");
3789
+ if (!intentClientSecret) throw new import_shared9.FloPayError("No client_secret in response", "api_error");
3238
3790
  const result = await flopay.confirmPayment({
3239
3791
  clientSecret: intentClientSecret,
3240
3792
  returnUrl: window.location.href
@@ -3256,11 +3808,11 @@ function PayPalButton({
3256
3808
  }
3257
3809
  }, [flopay, elements, sessionId, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
3258
3810
  if (!flopay || !elements) {
3259
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
3811
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
3260
3812
  }
3261
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3262
- !ready && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
3263
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3813
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
3814
+ !ready && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
3815
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3264
3816
  "button",
3265
3817
  {
3266
3818
  type: "button",
@@ -3282,7 +3834,7 @@ function PayPalButton({
3282
3834
  children: submitting ? "Processing..." : "PayPal"
3283
3835
  }
3284
3836
  ) }),
3285
- (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3837
+ (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
3286
3838
  position: "fixed",
3287
3839
  inset: 0,
3288
3840
  background: "rgba(0,0,0,0.4)",
@@ -3290,7 +3842,7 @@ function PayPalButton({
3290
3842
  alignItems: "center",
3291
3843
  justifyContent: "center",
3292
3844
  zIndex: 1e3
3293
- }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3845
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
3294
3846
  background: "white",
3295
3847
  borderRadius: 8,
3296
3848
  padding: "1.5rem",
@@ -3300,6 +3852,649 @@ function PayPalButton({
3300
3852
  }, children: "Processing PayPal payment..." }) })
3301
3853
  ] });
3302
3854
  }
3855
+
3856
+ // src/automatic-payment-button.tsx
3857
+ var import_react11 = require("react");
3858
+ var import_js3 = require("@flopay/js");
3859
+ var import_shared10 = require("@flopay/shared");
3860
+ var import_jsx_runtime9 = require("react/jsx-runtime");
3861
+ var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
3862
+ var PAYPAL_RESUME_STORAGE_KEY = "flopay_automatic_payment_button_resume";
3863
+ function sleep2(ms) {
3864
+ return new Promise((resolve) => setTimeout(resolve, ms));
3865
+ }
3866
+ function coerceError(err, fallbackMessage) {
3867
+ if (err instanceof import_shared10.FloPayError) {
3868
+ return err;
3869
+ }
3870
+ return new import_shared10.FloPayError(
3871
+ err instanceof Error ? err.message : fallbackMessage,
3872
+ "api_error"
3873
+ );
3874
+ }
3875
+ function canUseStorage() {
3876
+ return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
3877
+ }
3878
+ function shouldShowFallbackCheckout(error, sessionId) {
3879
+ if (!sessionId) return false;
3880
+ if (error.type === "validation_error") return false;
3881
+ if (error.checkoutMethod && error.checkoutMethod !== "card") return false;
3882
+ return true;
3883
+ }
3884
+ function readPayPalResumeState() {
3885
+ if (!canUseStorage()) return null;
3886
+ try {
3887
+ const raw = window.sessionStorage.getItem(PAYPAL_RESUME_STORAGE_KEY);
3888
+ if (!raw) return null;
3889
+ return JSON.parse(raw);
3890
+ } catch {
3891
+ return null;
3892
+ }
3893
+ }
3894
+ function persistPayPalResumeState(state) {
3895
+ if (!canUseStorage()) return;
3896
+ try {
3897
+ window.sessionStorage.setItem(PAYPAL_RESUME_STORAGE_KEY, JSON.stringify(state));
3898
+ } catch (error) {
3899
+ console.warn("[FloPayAutomaticPaymentButton] Failed to persist PayPal resume state.", error);
3900
+ }
3901
+ }
3902
+ function clearPayPalResumeState() {
3903
+ if (!canUseStorage()) return;
3904
+ try {
3905
+ window.sessionStorage.removeItem(PAYPAL_RESUME_STORAGE_KEY);
3906
+ } catch (error) {
3907
+ console.warn("[FloPayAutomaticPaymentButton] Failed to clear PayPal resume state.", error);
3908
+ }
3909
+ }
3910
+ function clearPayPalRedirectParams() {
3911
+ if (typeof window === "undefined") return;
3912
+ const url = new URL(window.location.href);
3913
+ const keys = ["payment_intent", "payment_intent_client_secret", "redirect_status"];
3914
+ let changed = false;
3915
+ for (const key of keys) {
3916
+ if (url.searchParams.has(key)) {
3917
+ url.searchParams.delete(key);
3918
+ changed = true;
3919
+ }
3920
+ }
3921
+ if (changed) {
3922
+ window.history.replaceState({}, "", url.toString());
3923
+ }
3924
+ }
3925
+ function resolveCreateSessionDraft(props) {
3926
+ if (props.createSession) {
3927
+ return {
3928
+ ...props.createSession,
3929
+ checkoutMode: "auto"
3930
+ };
3931
+ }
3932
+ if (!props.clientId || !props.account || !props.successUrl || !props.cancelUrl) {
3933
+ return null;
3934
+ }
3935
+ return {
3936
+ clientId: props.clientId,
3937
+ items: props.items,
3938
+ subscriptions: props.subscriptions,
3939
+ account: props.account,
3940
+ successUrl: props.successUrl,
3941
+ cancelUrl: props.cancelUrl,
3942
+ couponCodes: props.couponCodes,
3943
+ tagsData: props.tagsData,
3944
+ utmMetadata: props.utmMetadata,
3945
+ checkoutMode: "auto"
3946
+ };
3947
+ }
3948
+ function FloPayAutomaticPaymentButton({
3949
+ sessionId,
3950
+ createSession,
3951
+ paymentMethodId,
3952
+ clientId,
3953
+ items,
3954
+ subscriptions,
3955
+ account,
3956
+ successUrl,
3957
+ cancelUrl,
3958
+ couponCodes,
3959
+ tagsData,
3960
+ utmMetadata,
3961
+ billingApiUrl,
3962
+ locale,
3963
+ fallbackPublishableKey,
3964
+ buttonsTheme,
3965
+ buttonsStyles: stylesOverride,
3966
+ onSuccess,
3967
+ onError,
3968
+ onDecline,
3969
+ children,
3970
+ disabled = false,
3971
+ type = "button",
3972
+ style,
3973
+ ...buttonProps
3974
+ }) {
3975
+ const resolvedBillingUrl = (0, import_react11.useMemo)(
3976
+ () => (0, import_shared10.resolveBillingApiUrl)(billingApiUrl),
3977
+ [billingApiUrl]
3978
+ );
3979
+ const createSessionDraft = (0, import_react11.useMemo)(
3980
+ () => resolveCreateSessionDraft({
3981
+ createSession,
3982
+ clientId,
3983
+ items,
3984
+ subscriptions,
3985
+ account,
3986
+ successUrl,
3987
+ cancelUrl,
3988
+ couponCodes,
3989
+ tagsData,
3990
+ utmMetadata
3991
+ }),
3992
+ [
3993
+ account,
3994
+ cancelUrl,
3995
+ clientId,
3996
+ couponCodes,
3997
+ createSession,
3998
+ items,
3999
+ subscriptions,
4000
+ successUrl,
4001
+ tagsData,
4002
+ utmMetadata
4003
+ ]
4004
+ );
4005
+ const [isProcessing, setIsProcessing] = (0, import_react11.useState)(false);
4006
+ const [overlayStatus, setOverlayStatus] = (0, import_react11.useState)(null);
4007
+ const [overlayError, setOverlayError] = (0, import_react11.useState)(null);
4008
+ const [fallbackSession, setFallbackSession] = (0, import_react11.useState)(null);
4009
+ const automaticPaymentToken = (0, import_react11.useMemo)(
4010
+ () => paymentMethodId ? {
4011
+ id: paymentMethodId,
4012
+ type: "card"
4013
+ } : void 0,
4014
+ [paymentMethodId]
4015
+ );
4016
+ const isMountedRef = (0, import_react11.useRef)(true);
4017
+ const resumeAttemptedRef = (0, import_react11.useRef)(false);
4018
+ const fallbackSessionRef = (0, import_react11.useRef)(fallbackSession);
4019
+ const onSuccessRef = (0, import_react11.useRef)(onSuccess);
4020
+ const onErrorRef = (0, import_react11.useRef)(onError);
4021
+ const onDeclineRef = (0, import_react11.useRef)(onDecline);
4022
+ (0, import_react11.useEffect)(() => {
4023
+ fallbackSessionRef.current = fallbackSession;
4024
+ }, [fallbackSession]);
4025
+ (0, import_react11.useEffect)(() => {
4026
+ onSuccessRef.current = onSuccess;
4027
+ }, [onSuccess]);
4028
+ (0, import_react11.useEffect)(() => {
4029
+ onErrorRef.current = onError;
4030
+ }, [onError]);
4031
+ (0, import_react11.useEffect)(() => {
4032
+ onDeclineRef.current = onDecline;
4033
+ }, [onDecline]);
4034
+ (0, import_react11.useEffect)(() => {
4035
+ isMountedRef.current = true;
4036
+ return () => {
4037
+ isMountedRef.current = false;
4038
+ };
4039
+ }, []);
4040
+ (0, import_react11.useEffect)(() => {
4041
+ if (!fallbackSession || typeof window === "undefined") {
4042
+ return;
4043
+ }
4044
+ const handleKeyDown = (event) => {
4045
+ if (event.key === "Escape") {
4046
+ setFallbackSession(null);
4047
+ }
4048
+ };
4049
+ window.addEventListener("keydown", handleKeyDown);
4050
+ return () => {
4051
+ window.removeEventListener("keydown", handleKeyDown);
4052
+ };
4053
+ }, [fallbackSession]);
4054
+ const emitDecline = (0, import_react11.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
4055
+ onDeclineRef.current?.(buildDeclineEvent(method, error, {
4056
+ code: error.code,
4057
+ declineCode: error.declineCode
4058
+ }));
4059
+ }, []);
4060
+ const showSuccess = (0, import_react11.useCallback)(async (event) => {
4061
+ if (!isMountedRef.current) return;
4062
+ setOverlayError(null);
4063
+ setOverlayStatus("success");
4064
+ await sleep2(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
4065
+ if (!isMountedRef.current) return;
4066
+ onSuccessRef.current?.(event);
4067
+ }, []);
4068
+ const showError = (0, import_react11.useCallback)(async (error, options) => {
4069
+ if (!isMountedRef.current) return;
4070
+ onErrorRef.current?.(error);
4071
+ if (options?.emitDecline) {
4072
+ emitDecline(error, options.method);
4073
+ }
4074
+ setOverlayError(error.message);
4075
+ setOverlayStatus("error");
4076
+ await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
4077
+ }, [emitDecline]);
4078
+ const processResolvedSession = (0, import_react11.useCallback)(async (apiResult, resolvedSessionId) => {
4079
+ const session = apiResult.data.session ?? null;
4080
+ if (!session) {
4081
+ throw new import_shared10.FloPayError("No session data returned", "api_error");
4082
+ }
4083
+ if (session.status === "complete") {
4084
+ await showSuccess({
4085
+ result: { status: "succeeded" },
4086
+ session,
4087
+ sessionId: session.id || resolvedSessionId,
4088
+ autoCompleted: false
4089
+ });
4090
+ return;
4091
+ }
4092
+ try {
4093
+ const result = await processSavedPaymentForMode({
4094
+ billingApiUrl: resolvedBillingUrl,
4095
+ sessionId: resolvedSessionId ?? session.id,
4096
+ session,
4097
+ tokenizedData: automaticPaymentToken
4098
+ });
4099
+ let paymentResult = result.type === "success" ? result.result : null;
4100
+ if (result.type !== "success") {
4101
+ const {
4102
+ publishableKey,
4103
+ paypalPublishableKey
4104
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4105
+ if (result.type === "paypal_redirect_required") {
4106
+ persistPayPalResumeState({
4107
+ sessionId: session.id || resolvedSessionId,
4108
+ publishableKey,
4109
+ paypalPublishableKey
4110
+ });
4111
+ }
4112
+ const {
4113
+ flopay,
4114
+ paypalFlopay
4115
+ } = await loadSavedPaymentProviders({
4116
+ publishableKey,
4117
+ paypalPublishableKey,
4118
+ billingApiUrl: resolvedBillingUrl,
4119
+ locale
4120
+ });
4121
+ paymentResult = await handleSavedPaymentRedirectResult(result, {
4122
+ flopay,
4123
+ paypalFlopay,
4124
+ attempt3DS: true,
4125
+ billingApiUrl: resolvedBillingUrl,
4126
+ sessionId: session.id || resolvedSessionId,
4127
+ session
4128
+ });
4129
+ if (result.type === "paypal_redirect_required") {
4130
+ clearPayPalResumeState();
4131
+ }
4132
+ }
4133
+ await showSuccess({
4134
+ result: paymentResult ? {
4135
+ ...paymentResult,
4136
+ paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId
4137
+ } : {
4138
+ status: "succeeded",
4139
+ paymentMethodId: paymentMethodId ?? void 0
4140
+ },
4141
+ session,
4142
+ sessionId: session.id || resolvedSessionId,
4143
+ autoCompleted: false
4144
+ });
4145
+ } catch (err) {
4146
+ let floPayErr = normalizeSavedPaymentError(err);
4147
+ const fallbackSessionId = session.id || resolvedSessionId;
4148
+ if (floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4149
+ try {
4150
+ const {
4151
+ publishableKey,
4152
+ paypalPublishableKey
4153
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4154
+ const {
4155
+ flopay
4156
+ } = await loadSavedPaymentProviders({
4157
+ publishableKey,
4158
+ paypalPublishableKey,
4159
+ billingApiUrl: resolvedBillingUrl,
4160
+ locale
4161
+ });
4162
+ const paymentResult = await processSavedPaymentWithIntent({
4163
+ billingApiUrl: resolvedBillingUrl,
4164
+ sessionId: fallbackSessionId,
4165
+ session,
4166
+ paymentMethodId: automaticPaymentToken.id,
4167
+ flopay
4168
+ });
4169
+ await showSuccess({
4170
+ result: {
4171
+ ...paymentResult,
4172
+ paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId
4173
+ },
4174
+ session,
4175
+ sessionId: fallbackSessionId,
4176
+ autoCompleted: false
4177
+ });
4178
+ return;
4179
+ } catch (intentRecoveryErr) {
4180
+ floPayErr = normalizeSavedPaymentError(intentRecoveryErr);
4181
+ }
4182
+ }
4183
+ await showError(floPayErr, {
4184
+ emitDecline: true,
4185
+ method: floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD
4186
+ });
4187
+ if (shouldShowFallbackCheckout(floPayErr, fallbackSessionId) && fallbackSessionId && isMountedRef.current) {
4188
+ setFallbackSession({
4189
+ sessionId: fallbackSessionId,
4190
+ errorMessage: floPayErr.message
4191
+ });
4192
+ }
4193
+ }
4194
+ }, [
4195
+ fallbackPublishableKey,
4196
+ locale,
4197
+ automaticPaymentToken,
4198
+ paymentMethodId,
4199
+ resolvedBillingUrl,
4200
+ showError,
4201
+ showSuccess
4202
+ ]);
4203
+ const handleButtonClick = (0, import_react11.useCallback)(async (event) => {
4204
+ buttonProps.onClick?.(event);
4205
+ if (event.defaultPrevented || disabled || isProcessing) {
4206
+ return;
4207
+ }
4208
+ setFallbackSession(null);
4209
+ if (sessionId && createSessionDraft) {
4210
+ const error = new import_shared10.FloPayError(
4211
+ "Provide either sessionId or create-session props, not both.",
4212
+ "validation_error"
4213
+ );
4214
+ await showError(error);
4215
+ if (isMountedRef.current) {
4216
+ setOverlayStatus(null);
4217
+ setOverlayError(null);
4218
+ }
4219
+ return;
4220
+ }
4221
+ if (!sessionId && !createSessionDraft) {
4222
+ const error = new import_shared10.FloPayError(
4223
+ "Provide a sessionId or the props required to create an automatic payment session.",
4224
+ "validation_error"
4225
+ );
4226
+ await showError(error);
4227
+ if (isMountedRef.current) {
4228
+ setOverlayStatus(null);
4229
+ setOverlayError(null);
4230
+ }
4231
+ return;
4232
+ }
4233
+ setIsProcessing(true);
4234
+ setOverlayError(null);
4235
+ setOverlayStatus("processing");
4236
+ try {
4237
+ const api = new import_js3.PaymentAPI(resolvedBillingUrl);
4238
+ if (sessionId) {
4239
+ const result = await api.getUnifiedCheckoutSession(sessionId);
4240
+ await processResolvedSession(result, sessionId);
4241
+ return;
4242
+ }
4243
+ try {
4244
+ const result = await api.createAndFetchSession(createSessionDraft);
4245
+ await processResolvedSession(result, result.data.session?.id ?? null);
4246
+ } catch (err) {
4247
+ if (err instanceof import_shared10.FloPayError && err.code === "session_auto_completed") {
4248
+ await showSuccess({
4249
+ result: { status: "succeeded" },
4250
+ session: null,
4251
+ sessionId: null,
4252
+ autoCompleted: true
4253
+ });
4254
+ return;
4255
+ }
4256
+ throw err;
4257
+ }
4258
+ } catch (err) {
4259
+ await showError(
4260
+ coerceError(err, "Automatic payment failed. Please try again.")
4261
+ );
4262
+ } finally {
4263
+ if (isMountedRef.current) {
4264
+ setOverlayStatus(null);
4265
+ setOverlayError(null);
4266
+ setIsProcessing(false);
4267
+ }
4268
+ }
4269
+ }, [
4270
+ buttonProps,
4271
+ createSessionDraft,
4272
+ disabled,
4273
+ isProcessing,
4274
+ processResolvedSession,
4275
+ resolvedBillingUrl,
4276
+ sessionId,
4277
+ showError,
4278
+ showSuccess
4279
+ ]);
4280
+ const handleFallbackComplete = (0, import_react11.useCallback)((result) => {
4281
+ const activeFallback = fallbackSessionRef.current;
4282
+ setFallbackSession(null);
4283
+ onSuccessRef.current?.({
4284
+ result,
4285
+ session: null,
4286
+ sessionId: activeFallback?.sessionId ?? null,
4287
+ autoCompleted: false
4288
+ });
4289
+ }, []);
4290
+ const handleFallbackError = (0, import_react11.useCallback)((error) => {
4291
+ onErrorRef.current?.(error);
4292
+ }, []);
4293
+ const handleFallbackDecline = (0, import_react11.useCallback)((decline) => {
4294
+ onDeclineRef.current?.(decline);
4295
+ }, []);
4296
+ (0, import_react11.useEffect)(() => {
4297
+ if (typeof window === "undefined" || resumeAttemptedRef.current) {
4298
+ return;
4299
+ }
4300
+ const params = new URLSearchParams(window.location.search);
4301
+ const clientSecret = params.get("payment_intent_client_secret");
4302
+ if (!clientSecret) {
4303
+ return;
4304
+ }
4305
+ const resumeState = readPayPalResumeState();
4306
+ if (!resumeState) {
4307
+ return;
4308
+ }
4309
+ resumeAttemptedRef.current = true;
4310
+ void (async () => {
4311
+ setIsProcessing(true);
4312
+ setOverlayError(null);
4313
+ setOverlayStatus("processing");
4314
+ try {
4315
+ if (params.get("redirect_status") === "failed") {
4316
+ throw Object.assign(
4317
+ new import_shared10.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
4318
+ { checkoutMethod: "paypal" }
4319
+ );
4320
+ }
4321
+ const {
4322
+ flopay,
4323
+ paypalFlopay
4324
+ } = await loadSavedPaymentProviders({
4325
+ publishableKey: resumeState.publishableKey,
4326
+ paypalPublishableKey: resumeState.paypalPublishableKey,
4327
+ billingApiUrl: resolvedBillingUrl,
4328
+ locale
4329
+ });
4330
+ const paypalStripe = (paypalFlopay ?? flopay).getRawProvider();
4331
+ if (!paypalStripe) {
4332
+ throw Object.assign(
4333
+ new import_shared10.FloPayError("PayPal is not available.", "api_error"),
4334
+ { checkoutMethod: "paypal" }
4335
+ );
4336
+ }
4337
+ const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
4338
+ if (error) {
4339
+ throw Object.assign(
4340
+ new import_shared10.FloPayError(
4341
+ error.message ?? "Failed to retrieve PayPal payment status.",
4342
+ "api_error",
4343
+ { code: error.code }
4344
+ ),
4345
+ { checkoutMethod: "paypal" }
4346
+ );
4347
+ }
4348
+ if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded" || paymentIntent.status === "processing")) {
4349
+ await showSuccess({
4350
+ result: { status: "succeeded", paymentIntentId: paymentIntent.id },
4351
+ session: null,
4352
+ sessionId: resumeState.sessionId,
4353
+ autoCompleted: false
4354
+ });
4355
+ } else {
4356
+ throw Object.assign(
4357
+ new import_shared10.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
4358
+ { checkoutMethod: "paypal" }
4359
+ );
4360
+ }
4361
+ } catch (err) {
4362
+ const floPayErr = normalizeSavedPaymentError(err);
4363
+ await showError(floPayErr, {
4364
+ emitDecline: true,
4365
+ method: floPayErr.checkoutMethod ?? "paypal"
4366
+ });
4367
+ } finally {
4368
+ clearPayPalResumeState();
4369
+ clearPayPalRedirectParams();
4370
+ if (isMountedRef.current) {
4371
+ setOverlayStatus(null);
4372
+ setOverlayError(null);
4373
+ setIsProcessing(false);
4374
+ }
4375
+ }
4376
+ })();
4377
+ }, [locale, resolvedBillingUrl, showError, showSuccess]);
4378
+ const bStyles = (0, import_react11.useMemo)(() => {
4379
+ const base = (0, import_shared10.resolveButtonsLayoutTheme)(buttonsTheme);
4380
+ if (!stylesOverride) return base;
4381
+ return {
4382
+ ...base,
4383
+ ...stylesOverride,
4384
+ cardButton: { ...base.cardButton, ...stylesOverride.cardButton }
4385
+ };
4386
+ }, [buttonsTheme, stylesOverride]);
4387
+ const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
4388
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
4389
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4390
+ "button",
4391
+ {
4392
+ ...buttonProps,
4393
+ type,
4394
+ onClick: handleButtonClick,
4395
+ disabled: disabled || isProcessing,
4396
+ "aria-busy": isProcessing,
4397
+ style: {
4398
+ width: "100%",
4399
+ ...cardButtonSizing,
4400
+ backgroundColor: "white",
4401
+ color: "#262833",
4402
+ border: "1px solid #d1d5db",
4403
+ borderRadius: "8px",
4404
+ fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
4405
+ fontWeight: 600,
4406
+ cursor: disabled || isProcessing ? "not-allowed" : "pointer",
4407
+ display: "flex",
4408
+ alignItems: "center",
4409
+ justifyContent: "center",
4410
+ gap: "0.625rem",
4411
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
4412
+ transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
4413
+ position: "relative",
4414
+ opacity: disabled || isProcessing ? 0.6 : 1,
4415
+ ...bStyles.cardButton,
4416
+ ...style
4417
+ },
4418
+ onMouseDown: (e) => {
4419
+ buttonProps.onMouseDown?.(e);
4420
+ if (!e.defaultPrevented) {
4421
+ e.currentTarget.style.transform = "scale(0.985)";
4422
+ }
4423
+ },
4424
+ onMouseUp: (e) => {
4425
+ buttonProps.onMouseUp?.(e);
4426
+ if (!e.defaultPrevented) {
4427
+ e.currentTarget.style.transform = "scale(1)";
4428
+ }
4429
+ },
4430
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CardButtonContentSlot, { content: children })
4431
+ }
4432
+ ),
4433
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4434
+ ProcessingOverlay,
4435
+ {
4436
+ status: overlayStatus,
4437
+ errorMessage: overlayError
4438
+ }
4439
+ ),
4440
+ fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4441
+ "div",
4442
+ {
4443
+ "data-testid": "flopay-automatic-payment-fallback",
4444
+ role: "dialog",
4445
+ "aria-modal": "true",
4446
+ onClick: (event) => {
4447
+ if (event.target === event.currentTarget) {
4448
+ setFallbackSession(null);
4449
+ }
4450
+ },
4451
+ style: {
4452
+ position: "fixed",
4453
+ inset: 0,
4454
+ background: "rgba(0, 0, 0, 0.45)",
4455
+ display: "flex",
4456
+ alignItems: "center",
4457
+ justifyContent: "center",
4458
+ padding: "1.5rem",
4459
+ zIndex: 1100
4460
+ },
4461
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4462
+ "div",
4463
+ {
4464
+ style: {
4465
+ width: "100%",
4466
+ maxWidth: 520,
4467
+ maxHeight: "90vh",
4468
+ overflowY: "auto",
4469
+ background: "white",
4470
+ borderRadius: 20,
4471
+ padding: "1.5rem",
4472
+ boxShadow: "0 24px 80px rgba(15, 23, 42, 0.28)",
4473
+ display: "flex",
4474
+ flexDirection: "column",
4475
+ gap: "1rem"
4476
+ },
4477
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4478
+ FloPayCheckout,
4479
+ {
4480
+ sessionId: fallbackSession.sessionId,
4481
+ checkoutMode: "full",
4482
+ billingApiUrl: resolvedBillingUrl,
4483
+ fallbackPublishableKey,
4484
+ initialErrorMessage: fallbackSession.errorMessage,
4485
+ cardTitleContent: null,
4486
+ showSecurityFooter: false,
4487
+ onComplete: handleFallbackComplete,
4488
+ onError: handleFallbackError,
4489
+ onDecline: handleFallbackDecline
4490
+ }
4491
+ )
4492
+ }
4493
+ )
4494
+ }
4495
+ )
4496
+ ] });
4497
+ }
3303
4498
  // Annotate the CommonJS export names for ESM import in node:
3304
4499
  0 && (module.exports = {
3305
4500
  AddressElement,
@@ -3308,6 +4503,7 @@ function PayPalButton({
3308
4503
  CardExpiryElement,
3309
4504
  CardNumberElement,
3310
4505
  CheckoutForm,
4506
+ FloPayAutomaticPaymentButton,
3311
4507
  FloPayCheckout,
3312
4508
  FloPayProvider,
3313
4509
  PayPalButton,