@flopay/react 1.0.3 → 1.1.3
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/README.md +19 -6
- package/dist/index.cjs +1400 -550
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -11
- package/dist/index.d.ts +141 -11
- package/dist/index.mjs +1310 -461
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
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
|
+
DirectPayPalButton: () => DirectPayPalButton,
|
|
39
40
|
FloPayAutomaticPaymentButton: () => FloPayAutomaticPaymentButton,
|
|
40
41
|
FloPayCheckout: () => FloPayCheckout,
|
|
41
42
|
FloPayProvider: () => FloPayProvider,
|
|
@@ -151,9 +152,9 @@ function FloPayProvider({
|
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
// src/flopay-checkout.tsx
|
|
154
|
-
var
|
|
155
|
-
var
|
|
156
|
-
var
|
|
155
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
156
|
+
var import_js4 = require("@flopay/js");
|
|
157
|
+
var import_shared8 = require("@flopay/shared");
|
|
157
158
|
|
|
158
159
|
// src/card-button-content.tsx
|
|
159
160
|
var import_react3 = require("react");
|
|
@@ -284,9 +285,9 @@ var AddressElement = createElementComponent("address", "AddressElement");
|
|
|
284
285
|
|
|
285
286
|
// src/split-card-form.tsx
|
|
286
287
|
var import_react_stripe_js = require("@stripe/react-stripe-js");
|
|
287
|
-
var
|
|
288
|
-
var
|
|
289
|
-
var
|
|
288
|
+
var import_shared5 = require("@flopay/shared");
|
|
289
|
+
var import_js2 = require("@flopay/js");
|
|
290
|
+
var import_react8 = require("react");
|
|
290
291
|
|
|
291
292
|
// src/hooks.ts
|
|
292
293
|
var import_react5 = require("react");
|
|
@@ -494,15 +495,37 @@ function mergeInlineSessionPatch(params, patch) {
|
|
|
494
495
|
};
|
|
495
496
|
}
|
|
496
497
|
function buildSyntheticSession(params, checkoutModeOverride) {
|
|
497
|
-
const
|
|
498
|
-
...(params.
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
498
|
+
const inputProducts = params.products ?? [
|
|
499
|
+
...(params.subscriptions ?? []).map((s) => ({
|
|
500
|
+
type: "subscription",
|
|
501
|
+
code: s.code ?? s.providerPlanId,
|
|
502
|
+
name: s.subscriptionName ?? s.providerPlanName ?? s.code ?? s.providerPlanId ?? null,
|
|
503
|
+
quantity: s.quantity ?? 1,
|
|
504
|
+
totalAmount: s.totalAmount,
|
|
505
|
+
overrideAmount: s.overrideAmount,
|
|
506
|
+
currency: s.currency,
|
|
507
|
+
metadata: s.metadata
|
|
508
|
+
})),
|
|
509
|
+
...(params.items ?? []).map((i) => ({
|
|
510
|
+
type: "item",
|
|
511
|
+
code: i.code ?? i.providerItemId,
|
|
512
|
+
name: i.itemName ?? i.providerItemName ?? i.code ?? i.providerItemId ?? null,
|
|
513
|
+
quantity: i.quantity ?? 1,
|
|
514
|
+
totalAmount: i.totalAmount,
|
|
515
|
+
overrideAmount: i.overrideAmount,
|
|
516
|
+
currency: i.currency,
|
|
517
|
+
metadata: i.metadata
|
|
518
|
+
}))
|
|
519
|
+
];
|
|
520
|
+
const totalAmount = inputProducts.reduce(
|
|
521
|
+
(sum, p) => sum + (p.overrideAmount ?? p.totalAmount ?? 0),
|
|
522
|
+
0
|
|
523
|
+
);
|
|
524
|
+
const currency = params.currency ?? inputProducts.find((p) => p.currency)?.currency ?? "USD";
|
|
502
525
|
return {
|
|
503
526
|
id: "",
|
|
504
527
|
clientSecret: "",
|
|
505
|
-
mode: "payment",
|
|
528
|
+
mode: inputProducts.some((p) => p.type === "subscription") ? "subscription" : "payment",
|
|
506
529
|
amount: Math.round(totalAmount * 100),
|
|
507
530
|
currency,
|
|
508
531
|
status: "open",
|
|
@@ -520,40 +543,18 @@ function buildSyntheticSession(params, checkoutModeOverride) {
|
|
|
520
543
|
successUrl: params.successUrl,
|
|
521
544
|
cancelUrl: params.cancelUrl,
|
|
522
545
|
checkoutMode: checkoutModeOverride ?? params.checkoutMode ?? "full",
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
overrideAmount: item.overrideAmount ?? null,
|
|
536
|
-
currency: item.currency ?? currency,
|
|
537
|
-
metadata: item.metadata ?? null
|
|
538
|
-
};
|
|
539
|
-
}),
|
|
540
|
-
subscriptions: (params.subscriptions ?? []).map((subscription, idx) => {
|
|
541
|
-
const code = subscription.code ?? subscription.providerPlanId;
|
|
542
|
-
const subscriptionName = subscription.subscriptionName ?? subscription.providerPlanName ?? code;
|
|
543
|
-
return {
|
|
544
|
-
uuid: `synthetic-sub-${idx}`,
|
|
545
|
-
checkoutSessionId: "",
|
|
546
|
-
code,
|
|
547
|
-
providerPlanId: code,
|
|
548
|
-
subscriptionName,
|
|
549
|
-
providerPlanName: subscriptionName,
|
|
550
|
-
quantity: subscription.quantity ?? 1,
|
|
551
|
-
totalAmount: subscription.totalAmount,
|
|
552
|
-
overrideAmount: subscription.overrideAmount ?? null,
|
|
553
|
-
currency: subscription.currency ?? currency,
|
|
554
|
-
metadata: subscription.metadata ?? null
|
|
555
|
-
};
|
|
556
|
-
})
|
|
546
|
+
products: inputProducts.map((p, idx) => ({
|
|
547
|
+
uuid: `synthetic-${p.type}-${idx}`,
|
|
548
|
+
checkoutSessionId: "",
|
|
549
|
+
type: p.type,
|
|
550
|
+
code: p.code,
|
|
551
|
+
name: p.name ?? null,
|
|
552
|
+
quantity: p.quantity ?? 1,
|
|
553
|
+
totalAmount: p.totalAmount,
|
|
554
|
+
overrideAmount: p.overrideAmount ?? null,
|
|
555
|
+
currency: p.currency ?? currency,
|
|
556
|
+
metadata: p.metadata ?? null
|
|
557
|
+
}))
|
|
557
558
|
};
|
|
558
559
|
}
|
|
559
560
|
function mergeAccountPatch(base, patch) {
|
|
@@ -581,9 +582,25 @@ function readString(payload, key) {
|
|
|
581
582
|
const value = payload?.[key];
|
|
582
583
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
583
584
|
}
|
|
585
|
+
var FRIENDLY_MESSAGE_OVERRIDES = [
|
|
586
|
+
{
|
|
587
|
+
match: /^paypal authorization required\.?$/i,
|
|
588
|
+
replacement: "For your additional security, please re-authenticate this payment via PayPal."
|
|
589
|
+
}
|
|
590
|
+
];
|
|
591
|
+
function applyFriendlyMessageOverride(message) {
|
|
592
|
+
if (typeof message !== "string") return message ?? void 0;
|
|
593
|
+
const trimmed = message.trim();
|
|
594
|
+
if (!trimmed) return message;
|
|
595
|
+
for (const { match, replacement } of FRIENDLY_MESSAGE_OVERRIDES) {
|
|
596
|
+
if (match.test(trimmed)) return replacement;
|
|
597
|
+
}
|
|
598
|
+
return message;
|
|
599
|
+
}
|
|
584
600
|
function buildFloPayApiError(payload, fallbackMessage) {
|
|
585
601
|
const nestedError = isRecord(payload?.error) ? payload.error : null;
|
|
586
|
-
const
|
|
602
|
+
const rawMessage = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
|
|
603
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
587
604
|
const code = readString(payload, "code") ?? readString(payload, "gatewayErrorCode") ?? readString(nestedError, "code");
|
|
588
605
|
const declineCode = readString(payload, "declineCode") ?? readString(payload, "gatewayDeclineReason") ?? readString(payload, "decline_code") ?? readString(nestedError, "decline_code");
|
|
589
606
|
return new import_shared3.FloPayError(message, "api_error", {
|
|
@@ -688,11 +705,565 @@ function isInAppBrowser(userAgent) {
|
|
|
688
705
|
return false;
|
|
689
706
|
}
|
|
690
707
|
|
|
691
|
-
// src/
|
|
692
|
-
var
|
|
708
|
+
// src/direct-paypal-button.tsx
|
|
709
|
+
var import_react7 = require("react");
|
|
710
|
+
var import_paypal_js = require("@paypal/paypal-js");
|
|
711
|
+
var import_js = require("@flopay/js");
|
|
712
|
+
var import_shared4 = require("@flopay/shared");
|
|
693
713
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
714
|
+
var DEFAULT_BUTTON_HEIGHT = 45;
|
|
715
|
+
function DirectPayPalButton({
|
|
716
|
+
sessionId,
|
|
717
|
+
billingApiUrl,
|
|
718
|
+
email,
|
|
719
|
+
clientId,
|
|
720
|
+
environment,
|
|
721
|
+
currency,
|
|
722
|
+
isSubscription,
|
|
723
|
+
onTokenizedBody,
|
|
724
|
+
onComplete,
|
|
725
|
+
onErrorChange,
|
|
726
|
+
onDecline,
|
|
727
|
+
isProcessing = false,
|
|
728
|
+
onLoadStateChange,
|
|
729
|
+
onButtonClick,
|
|
730
|
+
runBeforeButtonClick,
|
|
731
|
+
session,
|
|
732
|
+
existingOrderId,
|
|
733
|
+
debug = false
|
|
734
|
+
}) {
|
|
735
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
736
|
+
const [ready, setReady] = (0, import_react7.useState)(false);
|
|
737
|
+
const [failed, setFailed] = (0, import_react7.useState)(false);
|
|
738
|
+
const [submitting, setSubmitting] = (0, import_react7.useState)(false);
|
|
739
|
+
const baseUrl = (0, import_react7.useMemo)(() => billingApiUrl.replace(/\/+$/, ""), [billingApiUrl]);
|
|
740
|
+
const [debugLines, setDebugLines] = (0, import_react7.useState)([]);
|
|
741
|
+
const appendDebug = (line) => {
|
|
742
|
+
if (!debug) return;
|
|
743
|
+
setDebugLines((prev) => [...prev, `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 23)} ${line}`]);
|
|
744
|
+
};
|
|
745
|
+
const onTokenizedBodyRef = (0, import_react7.useRef)(onTokenizedBody);
|
|
746
|
+
const onCompleteRef = (0, import_react7.useRef)(onComplete);
|
|
747
|
+
const onErrorChangeRef = (0, import_react7.useRef)(onErrorChange);
|
|
748
|
+
const onDeclineRef = (0, import_react7.useRef)(onDecline);
|
|
749
|
+
const onButtonClickRef = (0, import_react7.useRef)(onButtonClick);
|
|
750
|
+
const onLoadStateChangeRef = (0, import_react7.useRef)(onLoadStateChange);
|
|
751
|
+
const runBeforeButtonClickRef = (0, import_react7.useRef)(runBeforeButtonClick);
|
|
752
|
+
const sessionRef = (0, import_react7.useRef)(session);
|
|
753
|
+
const emailRef = (0, import_react7.useRef)(email);
|
|
754
|
+
const beforeClickRef = (0, import_react7.useRef)(null);
|
|
755
|
+
(0, import_react7.useEffect)(() => {
|
|
756
|
+
onTokenizedBodyRef.current = onTokenizedBody;
|
|
757
|
+
}, [onTokenizedBody]);
|
|
758
|
+
(0, import_react7.useEffect)(() => {
|
|
759
|
+
onCompleteRef.current = onComplete;
|
|
760
|
+
}, [onComplete]);
|
|
761
|
+
(0, import_react7.useEffect)(() => {
|
|
762
|
+
onErrorChangeRef.current = onErrorChange;
|
|
763
|
+
}, [onErrorChange]);
|
|
764
|
+
(0, import_react7.useEffect)(() => {
|
|
765
|
+
onDeclineRef.current = onDecline;
|
|
766
|
+
}, [onDecline]);
|
|
767
|
+
(0, import_react7.useEffect)(() => {
|
|
768
|
+
onButtonClickRef.current = onButtonClick;
|
|
769
|
+
}, [onButtonClick]);
|
|
770
|
+
(0, import_react7.useEffect)(() => {
|
|
771
|
+
onLoadStateChangeRef.current = onLoadStateChange;
|
|
772
|
+
}, [onLoadStateChange]);
|
|
773
|
+
(0, import_react7.useEffect)(() => {
|
|
774
|
+
runBeforeButtonClickRef.current = runBeforeButtonClick;
|
|
775
|
+
}, [runBeforeButtonClick]);
|
|
776
|
+
(0, import_react7.useEffect)(() => {
|
|
777
|
+
sessionRef.current = session;
|
|
778
|
+
}, [session]);
|
|
779
|
+
(0, import_react7.useEffect)(() => {
|
|
780
|
+
emailRef.current = email;
|
|
781
|
+
}, [email]);
|
|
782
|
+
(0, import_react7.useEffect)(() => {
|
|
783
|
+
onLoadStateChangeRef.current?.(ready && !failed);
|
|
784
|
+
}, [ready, failed]);
|
|
785
|
+
const normalizedEnv = (0, import_shared4.normalizeGatewayEnvironment)(environment);
|
|
786
|
+
(0, import_react7.useEffect)(() => {
|
|
787
|
+
const maskedClient = clientId ? `${clientId.slice(0, 6)}\u2026(len ${clientId.length})` : "(empty)";
|
|
788
|
+
const ua = typeof navigator !== "undefined" ? navigator.userAgent : "(no navigator)";
|
|
789
|
+
appendDebug(`mount clientId=${maskedClient} env=${environment ?? "(unset)"}\u2192${normalizedEnv ?? "live"} ccy=${currency} sub=${isSubscription}`);
|
|
790
|
+
appendDebug(`ua=${ua.slice(0, 80)}${ua.length > 80 ? "\u2026" : ""}`);
|
|
791
|
+
if (!clientId) {
|
|
792
|
+
appendDebug("FAIL: clientId empty \u2014 gateway misconfigured");
|
|
793
|
+
setFailed(true);
|
|
794
|
+
onErrorChangeRef.current?.("Direct PayPal gateway is misconfigured.");
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (!containerRef.current) {
|
|
798
|
+
appendDebug("FAIL: containerRef not attached");
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
let cancelled = false;
|
|
802
|
+
let activeButtons = null;
|
|
803
|
+
let rendered = false;
|
|
804
|
+
const container = containerRef.current;
|
|
805
|
+
let containerObserver = null;
|
|
806
|
+
let perfObserver = null;
|
|
807
|
+
const watchdogTimers = [];
|
|
808
|
+
const formatDims = (el) => {
|
|
809
|
+
if (!el || typeof el.getBoundingClientRect !== "function") return "(no rect)";
|
|
810
|
+
const rect = el.getBoundingClientRect();
|
|
811
|
+
return `${Math.round(rect.width)}\xD7${Math.round(rect.height)}`;
|
|
812
|
+
};
|
|
813
|
+
const classifyIframeSrc = (raw) => {
|
|
814
|
+
if (!raw) return "(empty)";
|
|
815
|
+
try {
|
|
816
|
+
const url = new URL(raw, typeof window !== "undefined" ? window.location.href : "https://localhost");
|
|
817
|
+
const path = url.pathname.toLowerCase();
|
|
818
|
+
if (path.includes("checkcaptcha") || path.includes("captcha")) return `CAPTCHA(${url.host}${path})`;
|
|
819
|
+
if (path.includes("risk") || path.includes("challenge")) return `RISK(${url.host}${path})`;
|
|
820
|
+
if (path.includes("smart/buttons")) return `smart-buttons(${url.host})`;
|
|
821
|
+
return `${url.host}${path}`.slice(0, 100);
|
|
822
|
+
} catch {
|
|
823
|
+
return raw.slice(0, 80);
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
const describeIframe = (frame) => {
|
|
827
|
+
const src = frame.getAttribute("src");
|
|
828
|
+
const srcdoc = frame.getAttribute("srcdoc");
|
|
829
|
+
const name = frame.getAttribute("name");
|
|
830
|
+
const sandbox = frame.getAttribute("sandbox");
|
|
831
|
+
const parts = [];
|
|
832
|
+
if (src) parts.push(`src=${classifyIframeSrc(src)}`);
|
|
833
|
+
if (srcdoc) parts.push(`srcdoc[${srcdoc.length}ch]`);
|
|
834
|
+
if (!src && !srcdoc) parts.push("src=(empty) srcdoc=(empty)");
|
|
835
|
+
if (name) parts.push(`name=${name.slice(0, 40)}`);
|
|
836
|
+
if (sandbox !== null) parts.push(`sandbox="${sandbox.slice(0, 40)}"`);
|
|
837
|
+
return parts.join(" ");
|
|
838
|
+
};
|
|
839
|
+
const inspectFrameContent = (frame) => {
|
|
840
|
+
if (!(frame instanceof HTMLIFrameElement)) return "";
|
|
841
|
+
try {
|
|
842
|
+
const cd = frame.contentDocument;
|
|
843
|
+
if (!cd) return "cd=null";
|
|
844
|
+
const bodyChildren = cd.body?.children.length ?? 0;
|
|
845
|
+
const bodyLen = cd.body?.innerHTML.length ?? 0;
|
|
846
|
+
const headLen = cd.head?.innerHTML.length ?? 0;
|
|
847
|
+
return `cd=same-origin readyState=${cd.readyState} body[${bodyChildren}children,${bodyLen}ch] head[${headLen}ch]`;
|
|
848
|
+
} catch (err) {
|
|
849
|
+
return `cd=cross-origin(${err.message.slice(0, 30)})`;
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
const errorMessages = [];
|
|
853
|
+
const onWindowError = (ev) => {
|
|
854
|
+
const msg = ev.message ?? String(ev.error ?? "(no message)");
|
|
855
|
+
if (msg && (msg.toLowerCase().includes("paypal") || msg.toLowerCase().includes("zoid") || msg.toLowerCase().includes("postrobot") || msg.toLowerCase().includes("storage"))) {
|
|
856
|
+
appendDebug(`window:error ${msg.slice(0, 140)}`);
|
|
857
|
+
errorMessages.push(msg);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
const onUnhandledRejection = (ev) => {
|
|
861
|
+
const reason = ev.reason instanceof Error ? ev.reason.message : String(ev.reason ?? "(no reason)");
|
|
862
|
+
if (reason && (reason.toLowerCase().includes("paypal") || reason.toLowerCase().includes("zoid") || reason.toLowerCase().includes("postrobot") || reason.toLowerCase().includes("storage"))) {
|
|
863
|
+
appendDebug(`window:rejection ${reason.slice(0, 140)}`);
|
|
864
|
+
errorMessages.push(reason);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
if (debug && typeof window !== "undefined") {
|
|
868
|
+
window.addEventListener("error", onWindowError);
|
|
869
|
+
window.addEventListener("unhandledrejection", onUnhandledRejection);
|
|
870
|
+
}
|
|
871
|
+
const paypalRequestCount = { value: 0 };
|
|
872
|
+
if (debug && typeof PerformanceObserver !== "undefined") {
|
|
873
|
+
try {
|
|
874
|
+
perfObserver = new PerformanceObserver((list) => {
|
|
875
|
+
for (const entry of list.getEntries()) {
|
|
876
|
+
if (!entry.name.toLowerCase().includes("paypal")) continue;
|
|
877
|
+
paypalRequestCount.value += 1;
|
|
878
|
+
const dur = Math.round(entry.duration);
|
|
879
|
+
appendDebug(`net ${dur}ms ${entry.name.slice(0, 90)}`);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
perfObserver.observe({ type: "resource", buffered: true });
|
|
883
|
+
} catch {
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
const stopDiagnostics = () => {
|
|
887
|
+
containerObserver?.disconnect();
|
|
888
|
+
containerObserver = null;
|
|
889
|
+
perfObserver?.disconnect();
|
|
890
|
+
perfObserver = null;
|
|
891
|
+
while (watchdogTimers.length) clearTimeout(watchdogTimers.pop());
|
|
892
|
+
if (debug && typeof window !== "undefined") {
|
|
893
|
+
window.removeEventListener("error", onWindowError);
|
|
894
|
+
window.removeEventListener("unhandledrejection", onUnhandledRejection);
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
const isZoidLifecycleMessage = (message) => {
|
|
898
|
+
if (!message) return false;
|
|
899
|
+
const lower = message.toLowerCase();
|
|
900
|
+
return lower.includes("zoid destroyed") || lower.includes("destroyed all components") || lower.includes("window closed") || lower.includes("detected container element removed");
|
|
901
|
+
};
|
|
902
|
+
const forwardError = (message) => {
|
|
903
|
+
if (cancelled) return;
|
|
904
|
+
if (isZoidLifecycleMessage(message)) return;
|
|
905
|
+
const friendly = applyFriendlyMessageOverride(message) ?? message;
|
|
906
|
+
onErrorChangeRef.current?.(friendly);
|
|
907
|
+
};
|
|
908
|
+
const markRenderFailed = (message) => {
|
|
909
|
+
if (cancelled) return;
|
|
910
|
+
if (isZoidLifecycleMessage(message)) {
|
|
911
|
+
appendDebug(`markRenderFailed:skip-zoid msg=${message.slice(0, 80)}`);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
setFailed(true);
|
|
915
|
+
forwardError(message);
|
|
916
|
+
};
|
|
917
|
+
setFailed(false);
|
|
918
|
+
const dispatchTokenizedBody = async (body) => {
|
|
919
|
+
const prepared = beforeClickRef.current;
|
|
920
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
921
|
+
if (onTokenizedBodyRef.current) {
|
|
922
|
+
onTokenizedBodyRef.current(body, {
|
|
923
|
+
sessionId: effectiveSessionId,
|
|
924
|
+
accountPatch: prepared?.accountPatch
|
|
925
|
+
});
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
try {
|
|
929
|
+
const currentSession = sessionRef.current;
|
|
930
|
+
const currentEmail = prepared?.accountPatch?.email ?? emailRef.current;
|
|
931
|
+
const effectiveUserId = prepared?.accountPatch?.userId ?? currentSession?.customer?.id ?? currentSession?.accountData?.userId ?? "";
|
|
932
|
+
const api = new import_js.PaymentAPI(baseUrl);
|
|
933
|
+
const response = await api.processPayment(
|
|
934
|
+
effectiveUserId,
|
|
935
|
+
{
|
|
936
|
+
sessionId: effectiveSessionId,
|
|
937
|
+
tokenizedData: body,
|
|
938
|
+
accountData: {
|
|
939
|
+
userId: effectiveUserId,
|
|
940
|
+
email: currentEmail ?? currentSession?.customer?.email ?? "",
|
|
941
|
+
firstName: prepared?.accountPatch?.firstName ?? currentSession?.customer?.firstName ?? currentSession?.accountData?.firstName ?? "",
|
|
942
|
+
lastName: prepared?.accountPatch?.lastName ?? currentSession?.customer?.lastName ?? currentSession?.accountData?.lastName ?? "",
|
|
943
|
+
country: prepared?.accountPatch?.country ?? currentSession?.customer?.country ?? currentSession?.accountData?.country ?? void 0,
|
|
944
|
+
zip: prepared?.accountPatch?.zip ?? currentSession?.customer?.zip ?? currentSession?.accountData?.zip ?? void 0
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
);
|
|
948
|
+
if (response.ok) {
|
|
949
|
+
onCompleteRef.current?.({ status: "succeeded", checkoutMethod: "paypal" });
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
const json = await response.json().catch(() => null);
|
|
953
|
+
const rawMessage = json?.["message"] ?? "PayPal payment failed.";
|
|
954
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
955
|
+
forwardError(message);
|
|
956
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
|
|
957
|
+
code: json?.["code"],
|
|
958
|
+
declineCode: json?.["declineCode"]
|
|
959
|
+
}));
|
|
960
|
+
} catch (err) {
|
|
961
|
+
const rawMessage = err instanceof Error ? err.message : "PayPal payment failed.";
|
|
962
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
963
|
+
forwardError(message);
|
|
964
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message));
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
const createPaypalIntent = async (fallbackMessage) => {
|
|
968
|
+
const prepared = beforeClickRef.current;
|
|
969
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
970
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? emailRef.current;
|
|
971
|
+
const response = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
972
|
+
method: "POST",
|
|
973
|
+
headers: { "Content-Type": "application/json" },
|
|
974
|
+
body: JSON.stringify({
|
|
975
|
+
sessionId: effectiveSessionId,
|
|
976
|
+
email: effectiveEmail,
|
|
977
|
+
paymentMethodType: "paypal",
|
|
978
|
+
isPaypal: "true"
|
|
979
|
+
})
|
|
980
|
+
});
|
|
981
|
+
const json = await response.json().catch(() => null);
|
|
982
|
+
if (!response.ok) {
|
|
983
|
+
throw new Error(json?.message ?? fallbackMessage);
|
|
984
|
+
}
|
|
985
|
+
const id = json?.data?.id;
|
|
986
|
+
if (!id) {
|
|
987
|
+
throw new Error(fallbackMessage);
|
|
988
|
+
}
|
|
989
|
+
return id;
|
|
990
|
+
};
|
|
991
|
+
appendDebug("loadScript:scheduled (deferred 1 tick)");
|
|
992
|
+
let loadPromise = null;
|
|
993
|
+
const startTimer = setTimeout(() => {
|
|
994
|
+
if (cancelled) {
|
|
995
|
+
appendDebug("loadScript:skipped (cancelled before defer ran)");
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
appendDebug("loadScript:start");
|
|
999
|
+
const paypalSdkEnv = normalizedEnv === "live" ? "production" : normalizedEnv;
|
|
1000
|
+
loadPromise = (0, import_paypal_js.loadScript)({
|
|
1001
|
+
clientId,
|
|
1002
|
+
currency,
|
|
1003
|
+
// Subscriptions need the `subscription` vault intent; one-time payments
|
|
1004
|
+
// use a standard order capture.
|
|
1005
|
+
intent: isSubscription ? "subscription" : "capture",
|
|
1006
|
+
vault: isSubscription ? true : void 0,
|
|
1007
|
+
// Tell PayPal which environment the clientId belongs to. Without
|
|
1008
|
+
// this, PayPal defaults to live endpoints — and a sandbox clientId
|
|
1009
|
+
// sent to live silently stalls in zoid's prerender forever (no
|
|
1010
|
+
// error, no rejection).
|
|
1011
|
+
...paypalSdkEnv ? { environment: paypalSdkEnv } : {},
|
|
1012
|
+
// Namespace the sandbox SDK so it can coexist with a production SDK on
|
|
1013
|
+
// the same page without clobbering `window.paypal`.
|
|
1014
|
+
...paypalSdkEnv === "sandbox" ? { dataNamespace: "paypal_sandbox" } : {}
|
|
1015
|
+
});
|
|
1016
|
+
loadPromise.then((paypal) => {
|
|
1017
|
+
appendDebug(`loadScript:resolved cancelled=${cancelled} ns=${!!paypal} buttons=${!!paypal?.Buttons}`);
|
|
1018
|
+
if (cancelled || !paypal?.Buttons) {
|
|
1019
|
+
if (!cancelled && !paypal?.Buttons) appendDebug("FAIL: namespace missing Buttons factory");
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const handleApprove = async (data) => {
|
|
1023
|
+
try {
|
|
1024
|
+
setSubmitting(true);
|
|
1025
|
+
onErrorChangeRef.current?.(null);
|
|
1026
|
+
const token = data.subscriptionID ?? data.orderID ?? "";
|
|
1027
|
+
if (!token) {
|
|
1028
|
+
throw new import_shared4.FloPayError(
|
|
1029
|
+
"PayPal did not return an approval token.",
|
|
1030
|
+
"api_error",
|
|
1031
|
+
{ code: "paypal_missing_token" }
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
await dispatchTokenizedBody({
|
|
1035
|
+
id: token,
|
|
1036
|
+
isPaypal: true
|
|
1037
|
+
});
|
|
1038
|
+
} catch (err) {
|
|
1039
|
+
forwardError(err instanceof Error ? err.message : "PayPal capture failed.");
|
|
1040
|
+
} finally {
|
|
1041
|
+
setSubmitting(false);
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
const buttons = paypal.Buttons({
|
|
1045
|
+
style: { layout: "horizontal", height: DEFAULT_BUTTON_HEIGHT, tagline: false },
|
|
1046
|
+
// PayPal's SDK awaits a Promise returned from `onClick` and aborts
|
|
1047
|
+
// the create-order/create-subscription step when `actions.reject()`
|
|
1048
|
+
// is invoked. Run the consumer's `runBeforeButtonClick` here so
|
|
1049
|
+
// inline-session/account patches land before the order is created,
|
|
1050
|
+
// matching the Stripe-rendered PayPal flow.
|
|
1051
|
+
onClick: async (_data, actions) => {
|
|
1052
|
+
const runner = runBeforeButtonClickRef.current;
|
|
1053
|
+
if (runner) {
|
|
1054
|
+
try {
|
|
1055
|
+
const beforeClick = await runner("paypal");
|
|
1056
|
+
if (!beforeClick.proceed) {
|
|
1057
|
+
beforeClickRef.current = null;
|
|
1058
|
+
await actions.reject();
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
beforeClickRef.current = {
|
|
1062
|
+
sessionId: beforeClick.sessionId,
|
|
1063
|
+
accountPatch: beforeClick.accountPatch
|
|
1064
|
+
};
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
appendDebug(`onClick:runBeforeButtonClick rejected msg=${(err instanceof Error ? err.message : String(err)).slice(0, 120)}`);
|
|
1067
|
+
beforeClickRef.current = null;
|
|
1068
|
+
await actions.reject();
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
} else {
|
|
1072
|
+
beforeClickRef.current = null;
|
|
1073
|
+
}
|
|
1074
|
+
onButtonClickRef.current?.("paypal");
|
|
1075
|
+
await actions.resolve();
|
|
1076
|
+
},
|
|
1077
|
+
// When the SDK is already holding an order/subscription id from a
|
|
1078
|
+
// prior backend round-trip (the `paypal_direct_required` retry
|
|
1079
|
+
// path), feed it straight to PayPal instead of creating a new one.
|
|
1080
|
+
// Otherwise fall back to the normal create-intent call.
|
|
1081
|
+
createOrder: isSubscription ? void 0 : existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal order."),
|
|
1082
|
+
createSubscription: isSubscription ? existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal subscription.") : void 0,
|
|
1083
|
+
onApprove: handleApprove,
|
|
1084
|
+
onCancel: () => {
|
|
1085
|
+
beforeClickRef.current = null;
|
|
1086
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
1087
|
+
},
|
|
1088
|
+
onError: (err) => {
|
|
1089
|
+
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1090
|
+
appendDebug(`onError rendered=${rendered} msg=${message.slice(0, 120)}`);
|
|
1091
|
+
if (rendered) {
|
|
1092
|
+
forwardError(message);
|
|
1093
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message));
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
markRenderFailed(message);
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
const eligible = buttons.isEligible();
|
|
1100
|
+
appendDebug(`isEligible=${eligible}`);
|
|
1101
|
+
if (!eligible) {
|
|
1102
|
+
setReady(false);
|
|
1103
|
+
markRenderFailed(
|
|
1104
|
+
"PayPal buttons are not eligible to render in this context (paypal_ineligible)."
|
|
1105
|
+
);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
const typedButtons = buttons;
|
|
1109
|
+
if (debug) {
|
|
1110
|
+
appendDebug(`container:dims ${formatDims(container)} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"}`);
|
|
1111
|
+
}
|
|
1112
|
+
if (debug && typeof MutationObserver !== "undefined") {
|
|
1113
|
+
containerObserver = new MutationObserver((mutations) => {
|
|
1114
|
+
for (const mutation of mutations) {
|
|
1115
|
+
if (mutation.type === "childList") {
|
|
1116
|
+
mutation.addedNodes.forEach((node) => {
|
|
1117
|
+
if (!(node instanceof Element)) return;
|
|
1118
|
+
const tag = node.tagName.toLowerCase();
|
|
1119
|
+
const title = (node.getAttribute("title") ?? "").slice(0, 40);
|
|
1120
|
+
const detail = tag === "iframe" ? ` ${describeIframe(node)}` : "";
|
|
1121
|
+
appendDebug(`child+ ${tag}${title ? ` title="${title}"` : ""}${detail} dims=${formatDims(node)}`);
|
|
1122
|
+
});
|
|
1123
|
+
} else if (mutation.type === "attributes" && mutation.target instanceof Element) {
|
|
1124
|
+
const target = mutation.target;
|
|
1125
|
+
if (target.tagName.toLowerCase() !== "iframe") continue;
|
|
1126
|
+
const attr = mutation.attributeName;
|
|
1127
|
+
if (attr === "src" || attr === "srcdoc") {
|
|
1128
|
+
appendDebug(`attr~ iframe ${attr}=${attr === "srcdoc" ? `[${(target.getAttribute("srcdoc") ?? "").length}ch]` : classifyIframeSrc(target.getAttribute("src"))} dims=${formatDims(target)}`);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
containerObserver.observe(container, {
|
|
1134
|
+
childList: true,
|
|
1135
|
+
subtree: true,
|
|
1136
|
+
attributes: true,
|
|
1137
|
+
attributeFilter: ["src", "srcdoc"]
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
const snapshotContainer = (when) => {
|
|
1141
|
+
if (cancelled || rendered) return;
|
|
1142
|
+
const iframes = container.querySelectorAll("iframe");
|
|
1143
|
+
const hasStorageAccess = typeof document !== "undefined" && "hasStorageAccess" in document;
|
|
1144
|
+
appendDebug(`watchdog:${when} container=${formatDims(container)} children=${container.childElementCount} iframes=${iframes.length} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"} cookies=${typeof navigator !== "undefined" ? navigator.cookieEnabled : "?"} hasStorageAccessApi=${hasStorageAccess} paypalNetRequests=${paypalRequestCount.value}`);
|
|
1145
|
+
iframes.forEach((frame, i) => {
|
|
1146
|
+
const title = (frame.getAttribute("title") ?? "").slice(0, 40);
|
|
1147
|
+
appendDebug(` iframe[${i}] ${formatDims(frame)}${title ? ` title="${title}"` : ""} ${describeIframe(frame)}`);
|
|
1148
|
+
const content = inspectFrameContent(frame);
|
|
1149
|
+
if (content) appendDebug(` ${content}`);
|
|
1150
|
+
});
|
|
1151
|
+
if (errorMessages.length === 0) {
|
|
1152
|
+
appendDebug(` (no PayPal/zoid window errors captured)`);
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
if (debug) {
|
|
1156
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("3s"), 3e3));
|
|
1157
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("8s"), 8e3));
|
|
1158
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("15s"), 15e3));
|
|
1159
|
+
}
|
|
1160
|
+
appendDebug("render:start");
|
|
1161
|
+
buttons.render(container).then(() => {
|
|
1162
|
+
appendDebug(`render:resolved cancelled=${cancelled}`);
|
|
1163
|
+
stopDiagnostics();
|
|
1164
|
+
if (cancelled) {
|
|
1165
|
+
typedButtons.close().catch(() => {
|
|
1166
|
+
});
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
activeButtons = typedButtons;
|
|
1170
|
+
rendered = true;
|
|
1171
|
+
setReady(true);
|
|
1172
|
+
}).catch((err) => {
|
|
1173
|
+
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1174
|
+
appendDebug(`render:rejected msg=${message.slice(0, 120)}`);
|
|
1175
|
+
stopDiagnostics();
|
|
1176
|
+
markRenderFailed(message);
|
|
1177
|
+
});
|
|
1178
|
+
}).catch((err) => {
|
|
1179
|
+
const message = err instanceof Error ? err.message : "PayPal SDK failed to load.";
|
|
1180
|
+
appendDebug(`loadScript:rejected msg=${message.slice(0, 120)}`);
|
|
1181
|
+
markRenderFailed(message);
|
|
1182
|
+
});
|
|
1183
|
+
}, 0);
|
|
1184
|
+
return () => {
|
|
1185
|
+
cancelled = true;
|
|
1186
|
+
clearTimeout(startTimer);
|
|
1187
|
+
stopDiagnostics();
|
|
1188
|
+
if (activeButtons) {
|
|
1189
|
+
activeButtons.close().catch(() => {
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
}, [baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId]);
|
|
1194
|
+
const debugPanel = debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1195
|
+
"pre",
|
|
1196
|
+
{
|
|
1197
|
+
"data-testid": "flopay-direct-paypal-debug",
|
|
1198
|
+
style: {
|
|
1199
|
+
margin: "0 0 8px 0",
|
|
1200
|
+
padding: "6px 8px",
|
|
1201
|
+
background: failed ? "#fef2f2" : "#f3f4f6",
|
|
1202
|
+
border: `1px solid ${failed ? "#fca5a5" : "#d1d5db"}`,
|
|
1203
|
+
borderRadius: 6,
|
|
1204
|
+
color: "#111827",
|
|
1205
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
1206
|
+
whiteSpace: "pre-wrap",
|
|
1207
|
+
wordBreak: "break-word",
|
|
1208
|
+
maxHeight: 220,
|
|
1209
|
+
overflowY: "auto"
|
|
1210
|
+
},
|
|
1211
|
+
children: [
|
|
1212
|
+
`FloPay/DirectPayPal-debug (ready=${ready} failed=${failed})`,
|
|
1213
|
+
debugLines.length === 0 ? "\n(waiting for first lifecycle event\u2026)" : `
|
|
1214
|
+
${debugLines.join("\n")}`
|
|
1215
|
+
]
|
|
1216
|
+
}
|
|
1217
|
+
) : null;
|
|
1218
|
+
if (failed) {
|
|
1219
|
+
return debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: debugPanel }) : null;
|
|
1220
|
+
}
|
|
1221
|
+
return (
|
|
1222
|
+
// Single wrapper so the parent flex container sees exactly one flex item
|
|
1223
|
+
// (otherwise the fragment's placeholder + container become two siblings
|
|
1224
|
+
// and any spacing-sensitive layout has to reason about both). The wrapper
|
|
1225
|
+
// intentionally has no margin/padding so the parent owns all spacing.
|
|
1226
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1227
|
+
debugPanel,
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT }, children: [
|
|
1229
|
+
!ready && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1230
|
+
"div",
|
|
1231
|
+
{
|
|
1232
|
+
"data-testid": "flopay-direct-paypal-placeholder",
|
|
1233
|
+
style: {
|
|
1234
|
+
position: "absolute",
|
|
1235
|
+
inset: 0,
|
|
1236
|
+
borderRadius: 8,
|
|
1237
|
+
background: "#e5e7eb",
|
|
1238
|
+
animation: "flopay-pulse 1.5s ease-in-out infinite",
|
|
1239
|
+
pointerEvents: "none"
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
),
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1244
|
+
"div",
|
|
1245
|
+
{
|
|
1246
|
+
ref: containerRef,
|
|
1247
|
+
"data-testid": "flopay-direct-paypal-container",
|
|
1248
|
+
style: {
|
|
1249
|
+
minHeight: DEFAULT_BUTTON_HEIGHT,
|
|
1250
|
+
display: "flex",
|
|
1251
|
+
opacity: ready ? 1 : 0
|
|
1252
|
+
},
|
|
1253
|
+
"aria-busy": submitting || isProcessing
|
|
1254
|
+
}
|
|
1255
|
+
)
|
|
1256
|
+
] })
|
|
1257
|
+
] })
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/split-card-form.tsx
|
|
1262
|
+
var import_shared6 = require("@flopay/shared");
|
|
1263
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
694
1264
|
var WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
695
1265
|
var FLOPAY_KEYFRAMES = `
|
|
1266
|
+
.paypal-buttons { margin: 0 !important; vertical-align: top !important; }
|
|
696
1267
|
@keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
697
1268
|
@keyframes flopay-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
|
|
698
1269
|
@keyframes flopay-buttons-enter {
|
|
@@ -726,13 +1297,13 @@ function getButtonMethodLabel(method) {
|
|
|
726
1297
|
}
|
|
727
1298
|
}
|
|
728
1299
|
function normalizeBeforeButtonClickError(method, err) {
|
|
729
|
-
return err instanceof
|
|
1300
|
+
return err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(
|
|
730
1301
|
err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
|
|
731
1302
|
"validation_error"
|
|
732
1303
|
);
|
|
733
1304
|
}
|
|
734
1305
|
function FloPayKeyframes() {
|
|
735
|
-
return /* @__PURE__ */ (0,
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: FLOPAY_KEYFRAMES });
|
|
736
1307
|
}
|
|
737
1308
|
function toCssSize(value) {
|
|
738
1309
|
if (typeof value === "number") return `${value}px`;
|
|
@@ -753,8 +1324,8 @@ function ExpressCheckoutReadySwap({
|
|
|
753
1324
|
children
|
|
754
1325
|
}) {
|
|
755
1326
|
if (state === "unavailable" || state === "load_error") return null;
|
|
756
|
-
return /* @__PURE__ */ (0,
|
|
757
|
-
/* @__PURE__ */ (0,
|
|
1327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
1328
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
758
1329
|
"div",
|
|
759
1330
|
{
|
|
760
1331
|
"data-testid": placeholderTestId,
|
|
@@ -773,7 +1344,7 @@ function ExpressCheckoutReadySwap({
|
|
|
773
1344
|
}
|
|
774
1345
|
}
|
|
775
1346
|
),
|
|
776
|
-
/* @__PURE__ */ (0,
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
777
1348
|
"div",
|
|
778
1349
|
{
|
|
779
1350
|
style: {
|
|
@@ -791,9 +1362,9 @@ function ExpressCheckoutReadySwap({
|
|
|
791
1362
|
function isExpressCheckoutRowVisible(state) {
|
|
792
1363
|
return state !== "unavailable" && state !== "load_error";
|
|
793
1364
|
}
|
|
794
|
-
var SplitCardForm = (0,
|
|
1365
|
+
var SplitCardForm = (0, import_react8.forwardRef)(
|
|
795
1366
|
function SplitCardForm2(props, ref) {
|
|
796
|
-
return /* @__PURE__ */ (0,
|
|
1367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
|
|
797
1368
|
}
|
|
798
1369
|
);
|
|
799
1370
|
function PayPalButtonInner({
|
|
@@ -810,15 +1381,15 @@ function PayPalButtonInner({
|
|
|
810
1381
|
}) {
|
|
811
1382
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
812
1383
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
813
|
-
const [loadState, setLoadState] = (0,
|
|
814
|
-
(0,
|
|
1384
|
+
const [loadState, setLoadState] = (0, import_react8.useState)("loading");
|
|
1385
|
+
(0, import_react8.useEffect)(() => {
|
|
815
1386
|
onLoadStateChange?.(loadState);
|
|
816
1387
|
}, [loadState, onLoadStateChange]);
|
|
817
|
-
const [submitting, setSubmitting] = (0,
|
|
818
|
-
const paypalResumeAttempted = (0,
|
|
819
|
-
const beforeClickRef = (0,
|
|
1388
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1389
|
+
const paypalResumeAttempted = (0, import_react8.useRef)(false);
|
|
1390
|
+
const beforeClickRef = (0, import_react8.useRef)(null);
|
|
820
1391
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
821
|
-
(0,
|
|
1392
|
+
(0, import_react8.useEffect)(() => {
|
|
822
1393
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
823
1394
|
const params = new URLSearchParams(window.location.search);
|
|
824
1395
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -865,7 +1436,7 @@ function PayPalButtonInner({
|
|
|
865
1436
|
}
|
|
866
1437
|
})();
|
|
867
1438
|
}, [stripe, onTokenizedBody, onErrorChange, onDecline]);
|
|
868
|
-
const handlePayPalClick = (0,
|
|
1439
|
+
const handlePayPalClick = (0, import_react8.useCallback)(async (event) => {
|
|
869
1440
|
if (isProcessing || submitting) {
|
|
870
1441
|
event.reject();
|
|
871
1442
|
return;
|
|
@@ -883,7 +1454,7 @@ function PayPalButtonInner({
|
|
|
883
1454
|
onButtonClick?.("paypal");
|
|
884
1455
|
event.resolve();
|
|
885
1456
|
}, [isProcessing, onButtonClick, runBeforeButtonClick, submitting]);
|
|
886
|
-
const handlePayPalConfirm = (0,
|
|
1457
|
+
const handlePayPalConfirm = (0, import_react8.useCallback)(async (event) => {
|
|
887
1458
|
if (!stripe || !elements) return;
|
|
888
1459
|
let prepared = beforeClickRef.current;
|
|
889
1460
|
beforeClickRef.current = null;
|
|
@@ -975,8 +1546,8 @@ function PayPalButtonInner({
|
|
|
975
1546
|
setSubmitting(false);
|
|
976
1547
|
}
|
|
977
1548
|
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
|
|
978
|
-
return /* @__PURE__ */ (0,
|
|
979
|
-
/* @__PURE__ */ (0,
|
|
1549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
980
1551
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
981
1552
|
{
|
|
982
1553
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
@@ -1001,7 +1572,7 @@ function PayPalButtonInner({
|
|
|
1001
1572
|
}
|
|
1002
1573
|
}
|
|
1003
1574
|
) }),
|
|
1004
|
-
submitting && /* @__PURE__ */ (0,
|
|
1575
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1005
1576
|
] });
|
|
1006
1577
|
}
|
|
1007
1578
|
function WalletButtonInner({
|
|
@@ -1019,15 +1590,15 @@ function WalletButtonInner({
|
|
|
1019
1590
|
}) {
|
|
1020
1591
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
1021
1592
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
1022
|
-
const [loadState, setLoadState] = (0,
|
|
1023
|
-
(0,
|
|
1593
|
+
const [loadState, setLoadState] = (0, import_react8.useState)("loading");
|
|
1594
|
+
(0, import_react8.useEffect)(() => {
|
|
1024
1595
|
onLoadStateChange?.(loadState);
|
|
1025
1596
|
}, [loadState, onLoadStateChange]);
|
|
1026
|
-
const [submitting, setSubmitting] = (0,
|
|
1597
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1027
1598
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1028
|
-
const lastWalletMethodRef = (0,
|
|
1029
|
-
const beforeClickRef = (0,
|
|
1030
|
-
const handleWalletConfirm = (0,
|
|
1599
|
+
const lastWalletMethodRef = (0, import_react8.useRef)("card");
|
|
1600
|
+
const beforeClickRef = (0, import_react8.useRef)(null);
|
|
1601
|
+
const handleWalletConfirm = (0, import_react8.useCallback)(
|
|
1031
1602
|
async (event) => {
|
|
1032
1603
|
if (!stripe || !elements) return;
|
|
1033
1604
|
const walletType = event.expressPaymentType;
|
|
@@ -1116,12 +1687,16 @@ function WalletButtonInner({
|
|
|
1116
1687
|
},
|
|
1117
1688
|
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
|
|
1118
1689
|
);
|
|
1119
|
-
return /* @__PURE__ */ (0,
|
|
1120
|
-
/* @__PURE__ */ (0,
|
|
1690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1121
1692
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
1122
1693
|
{
|
|
1123
|
-
onReady: (event) =>
|
|
1124
|
-
|
|
1694
|
+
onReady: (event) => {
|
|
1695
|
+
setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"]));
|
|
1696
|
+
},
|
|
1697
|
+
onLoadError: (e) => {
|
|
1698
|
+
setLoadState("load_error");
|
|
1699
|
+
},
|
|
1125
1700
|
onClick: async (event) => {
|
|
1126
1701
|
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1127
1702
|
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
|
|
@@ -1156,7 +1731,7 @@ function WalletButtonInner({
|
|
|
1156
1731
|
}
|
|
1157
1732
|
}
|
|
1158
1733
|
) }),
|
|
1159
|
-
submitting && /* @__PURE__ */ (0,
|
|
1734
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1160
1735
|
] });
|
|
1161
1736
|
}
|
|
1162
1737
|
function SplitCardFormInner({
|
|
@@ -1208,55 +1783,64 @@ function SplitCardFormInner({
|
|
|
1208
1783
|
totalAmount = 0,
|
|
1209
1784
|
currency = "usd",
|
|
1210
1785
|
initialCardOpen = false,
|
|
1786
|
+
directPaypal,
|
|
1787
|
+
isSubscription = false,
|
|
1788
|
+
session,
|
|
1789
|
+
debug = false,
|
|
1211
1790
|
innerRef
|
|
1212
1791
|
}) {
|
|
1213
1792
|
const flopay = useFloPay();
|
|
1214
1793
|
const paypalFlopay = usePayPalFloPay();
|
|
1215
1794
|
const elements = useElements();
|
|
1216
|
-
const checkout = (0,
|
|
1795
|
+
const checkout = (0, import_react8.useContext)(CheckoutContext);
|
|
1217
1796
|
const contextBillingUrl = useBillingApiUrl();
|
|
1218
|
-
const [processing, setProcessing] = (0,
|
|
1219
|
-
const [error, setError] = (0,
|
|
1220
|
-
const [is3DSActive, setIs3DSActive] = (0,
|
|
1221
|
-
const [selectedCountry, setSelectedCountry] = (0,
|
|
1222
|
-
const [zipCode, setZipCode] = (0,
|
|
1223
|
-
const [addressLine1, setAddressLine1] = (0,
|
|
1224
|
-
const [addressLine2, setAddressLine2] = (0,
|
|
1225
|
-
const [city, setCity] = (0,
|
|
1226
|
-
const [stateValue, setStateValue] = (0,
|
|
1227
|
-
const [accountPatch, setAccountPatch] = (0,
|
|
1228
|
-
const zipCodeRef = (0,
|
|
1229
|
-
const selectedCountryRef = (0,
|
|
1230
|
-
const addressLine1Ref = (0,
|
|
1231
|
-
const addressLine2Ref = (0,
|
|
1232
|
-
const cityRef = (0,
|
|
1233
|
-
const stateRef = (0,
|
|
1234
|
-
const avsConfig = (0,
|
|
1797
|
+
const [processing, setProcessing] = (0, import_react8.useState)(false);
|
|
1798
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1799
|
+
const [is3DSActive, setIs3DSActive] = (0, import_react8.useState)(false);
|
|
1800
|
+
const [selectedCountry, setSelectedCountry] = (0, import_react8.useState)(countryProp ?? "US");
|
|
1801
|
+
const [zipCode, setZipCode] = (0, import_react8.useState)(zipProp ?? "");
|
|
1802
|
+
const [addressLine1, setAddressLine1] = (0, import_react8.useState)(addressLine1Prop ?? "");
|
|
1803
|
+
const [addressLine2, setAddressLine2] = (0, import_react8.useState)(addressLine2Prop ?? "");
|
|
1804
|
+
const [city, setCity] = (0, import_react8.useState)(cityProp ?? "");
|
|
1805
|
+
const [stateValue, setStateValue] = (0, import_react8.useState)(stateProp ?? "");
|
|
1806
|
+
const [accountPatch, setAccountPatch] = (0, import_react8.useState)({});
|
|
1807
|
+
const zipCodeRef = (0, import_react8.useRef)(zipProp ?? "");
|
|
1808
|
+
const selectedCountryRef = (0, import_react8.useRef)(countryProp ?? "US");
|
|
1809
|
+
const addressLine1Ref = (0, import_react8.useRef)(addressLine1Prop ?? "");
|
|
1810
|
+
const addressLine2Ref = (0, import_react8.useRef)(addressLine2Prop ?? "");
|
|
1811
|
+
const cityRef = (0, import_react8.useRef)(cityProp ?? "");
|
|
1812
|
+
const stateRef = (0, import_react8.useRef)(stateProp ?? "");
|
|
1813
|
+
const avsConfig = (0, import_react8.useMemo)(() => (0, import_shared5.resolveAVSConfig)(enableAVSProp), [enableAVSProp]);
|
|
1235
1814
|
const enableAVS = avsConfig !== null;
|
|
1236
|
-
const [viewState, setViewState] = (0,
|
|
1815
|
+
const [viewState, setViewState] = (0, import_react8.useState)(initialCardOpen ? "card" : "buttons");
|
|
1237
1816
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
1238
1817
|
const TRANSITION_MS = 280;
|
|
1239
|
-
const expandToCard = (0,
|
|
1818
|
+
const expandToCard = (0, import_react8.useCallback)(() => {
|
|
1240
1819
|
setViewState("expanding");
|
|
1241
1820
|
setTimeout(() => setViewState("card"), TRANSITION_MS);
|
|
1242
1821
|
}, []);
|
|
1243
|
-
const collapseToButtons = (0,
|
|
1822
|
+
const collapseToButtons = (0, import_react8.useCallback)(() => {
|
|
1244
1823
|
setViewState("collapsing");
|
|
1245
1824
|
setTimeout(() => setViewState("buttons"), TRANSITION_MS);
|
|
1246
1825
|
}, []);
|
|
1247
|
-
(0,
|
|
1826
|
+
(0, import_react8.useEffect)(() => {
|
|
1248
1827
|
if (layout === "buttons" && initialCardOpen) {
|
|
1249
1828
|
setViewState("card");
|
|
1250
1829
|
}
|
|
1251
1830
|
}, [layout, initialCardOpen]);
|
|
1252
|
-
const [fullName, setFullName] = (0,
|
|
1253
|
-
const [formReady, setFormReady] = (0,
|
|
1254
|
-
const [overlayStatus, setOverlayStatus] = (0,
|
|
1255
|
-
const processingRef = (0,
|
|
1831
|
+
const [fullName, setFullName] = (0, import_react8.useState)("");
|
|
1832
|
+
const [formReady, setFormReady] = (0, import_react8.useState)(false);
|
|
1833
|
+
const [overlayStatus, setOverlayStatus] = (0, import_react8.useState)(null);
|
|
1834
|
+
const processingRef = (0, import_react8.useRef)(false);
|
|
1835
|
+
const [paypalDirectRetry, setPaypalDirectRetry] = (0, import_react8.useState)(null);
|
|
1836
|
+
const paypalDirectRetryRef = (0, import_react8.useRef)(paypalDirectRetry);
|
|
1837
|
+
(0, import_react8.useEffect)(() => {
|
|
1838
|
+
paypalDirectRetryRef.current = paypalDirectRetry;
|
|
1839
|
+
}, [paypalDirectRetry]);
|
|
1256
1840
|
const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
|
|
1257
1841
|
const displayError = externalError ?? error;
|
|
1258
|
-
const bStyles = (0,
|
|
1259
|
-
const base = (0,
|
|
1842
|
+
const bStyles = (0, import_react8.useMemo)(() => {
|
|
1843
|
+
const base = (0, import_shared5.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
1260
1844
|
if (!buttonsStylesOverride) return base;
|
|
1261
1845
|
return {
|
|
1262
1846
|
...base,
|
|
@@ -1273,7 +1857,7 @@ function SplitCardFormInner({
|
|
|
1273
1857
|
const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
|
|
1274
1858
|
const isSelfContained = !onTokenizedBody;
|
|
1275
1859
|
const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
|
|
1276
|
-
const resolvedAccount = (0,
|
|
1860
|
+
const resolvedAccount = (0, import_react8.useMemo)(() => mergeAccountPatch({
|
|
1277
1861
|
userId,
|
|
1278
1862
|
email,
|
|
1279
1863
|
firstName,
|
|
@@ -1281,63 +1865,66 @@ function SplitCardFormInner({
|
|
|
1281
1865
|
country: countryProp,
|
|
1282
1866
|
zip: zipProp
|
|
1283
1867
|
}, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
|
|
1284
|
-
const stripeInstance = (0,
|
|
1868
|
+
const stripeInstance = (0, import_react8.useMemo)(() => {
|
|
1285
1869
|
if (!flopay) return null;
|
|
1286
1870
|
return flopay.getRawProvider();
|
|
1287
1871
|
}, [flopay]);
|
|
1288
|
-
const paypalStripeInstance = (0,
|
|
1872
|
+
const paypalStripeInstance = (0, import_react8.useMemo)(() => {
|
|
1289
1873
|
if (!paypalFlopay) return null;
|
|
1290
1874
|
return paypalFlopay.getRawProvider();
|
|
1291
1875
|
}, [paypalFlopay]);
|
|
1292
1876
|
const amountInCents = totalAmount || 100;
|
|
1293
|
-
const walletOptions = (0,
|
|
1877
|
+
const walletOptions = (0, import_react8.useMemo)(() => ({
|
|
1294
1878
|
mode: "payment",
|
|
1295
1879
|
amount: amountInCents,
|
|
1296
1880
|
currency: currency.toLowerCase(),
|
|
1297
1881
|
paymentMethodCreation: "manual",
|
|
1298
1882
|
captureMethod: "manual"
|
|
1299
1883
|
}), [amountInCents, currency]);
|
|
1300
|
-
const paypalOptions = (0,
|
|
1884
|
+
const paypalOptions = (0, import_react8.useMemo)(() => ({
|
|
1301
1885
|
mode: "payment",
|
|
1302
1886
|
amount: amountInCents,
|
|
1303
1887
|
currency: currency.toLowerCase(),
|
|
1304
1888
|
captureMethod: "manual",
|
|
1305
1889
|
setupFutureUsage: "off_session"
|
|
1306
1890
|
}), [amountInCents, currency]);
|
|
1307
|
-
const updateError = (0,
|
|
1891
|
+
const updateError = (0, import_react8.useCallback)(
|
|
1308
1892
|
(err) => {
|
|
1309
1893
|
setError(err);
|
|
1310
1894
|
onErrorChange?.(err);
|
|
1311
1895
|
},
|
|
1312
1896
|
[onErrorChange]
|
|
1313
1897
|
);
|
|
1314
|
-
const emitDecline = (0,
|
|
1898
|
+
const emitDecline = (0, import_react8.useCallback)(
|
|
1315
1899
|
(method, input, overrides) => {
|
|
1316
1900
|
onDecline?.(buildDeclineEvent(method, input, overrides));
|
|
1317
1901
|
},
|
|
1318
1902
|
[onDecline]
|
|
1319
1903
|
);
|
|
1320
1904
|
const showWallets = showApplePay || showGooglePay;
|
|
1321
|
-
const [paypalLoadState, setPaypalLoadState] = (0,
|
|
1322
|
-
const [walletLoadState, setWalletLoadState] = (0,
|
|
1323
|
-
const [
|
|
1324
|
-
(0,
|
|
1905
|
+
const [paypalLoadState, setPaypalLoadState] = (0, import_react8.useState)("loading");
|
|
1906
|
+
const [walletLoadState, setWalletLoadState] = (0, import_react8.useState)("loading");
|
|
1907
|
+
const [directPaypalReady, setDirectPaypalReady] = (0, import_react8.useState)(false);
|
|
1908
|
+
const [inAppBrowserDetected, setInAppBrowserDetected] = (0, import_react8.useState)();
|
|
1909
|
+
(0, import_react8.useEffect)(() => {
|
|
1325
1910
|
setInAppBrowserDetected(isInAppBrowser());
|
|
1326
1911
|
}, []);
|
|
1327
|
-
const
|
|
1328
|
-
const
|
|
1329
|
-
const
|
|
1912
|
+
const directPaypalConfigured = !!directPaypal?.clientId;
|
|
1913
|
+
const shouldShowPayPal = showPayPal && (directPaypalConfigured || inAppBrowserDetected === false);
|
|
1914
|
+
const shouldShowWallets = showWallets;
|
|
1915
|
+
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
1916
|
+
const shouldRenderStripePayPal = shouldShowPayPal && !directPaypalConfigured && !!paypalStripeInstance;
|
|
1330
1917
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
1331
|
-
const shouldDisplayPayPalRow =
|
|
1918
|
+
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
1332
1919
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
1333
|
-
const handleNameChange = (0,
|
|
1920
|
+
const handleNameChange = (0, import_react8.useCallback)((value) => {
|
|
1334
1921
|
setFullName(value);
|
|
1335
1922
|
onFullNameChange?.(value);
|
|
1336
1923
|
const parts = value.trim().split(/\s+/);
|
|
1337
1924
|
onFirstNameChange?.(parts[0] ?? "");
|
|
1338
1925
|
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
1339
1926
|
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
1340
|
-
const applyInlineSessionPatch = (0,
|
|
1927
|
+
const applyInlineSessionPatch = (0, import_react8.useCallback)(
|
|
1341
1928
|
(patch, method) => {
|
|
1342
1929
|
if (!checkout.applyInlineSessionPatch) {
|
|
1343
1930
|
return Promise.resolve({ error: null, sessionId });
|
|
@@ -1354,7 +1941,7 @@ function SplitCardFormInner({
|
|
|
1354
1941
|
},
|
|
1355
1942
|
[checkout.applyInlineSessionPatch, onError, sessionId, updateError]
|
|
1356
1943
|
);
|
|
1357
|
-
const runBeforeButtonClick = (0,
|
|
1944
|
+
const runBeforeButtonClick = (0, import_react8.useCallback)(async (method) => {
|
|
1358
1945
|
if (!onBeforeButtonClick) return { proceed: true };
|
|
1359
1946
|
try {
|
|
1360
1947
|
const result = await onBeforeButtonClick({
|
|
@@ -1390,7 +1977,7 @@ function SplitCardFormInner({
|
|
|
1390
1977
|
return { proceed: false };
|
|
1391
1978
|
}
|
|
1392
1979
|
}, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
|
|
1393
|
-
const processPaymentInternal = (0,
|
|
1980
|
+
const processPaymentInternal = (0, import_react8.useCallback)(
|
|
1394
1981
|
async (tokenizedBody, overrides) => {
|
|
1395
1982
|
if (processingRef.current) return;
|
|
1396
1983
|
processingRef.current = true;
|
|
@@ -1402,7 +1989,7 @@ function SplitCardFormInner({
|
|
|
1402
1989
|
const resolvedCompletionPaymentMethodId = overrides?.completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
|
|
1403
1990
|
const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
|
|
1404
1991
|
try {
|
|
1405
|
-
const api = new
|
|
1992
|
+
const api = new import_js2.PaymentAPI(baseUrl);
|
|
1406
1993
|
const response = await api.processPayment(effectiveAccount.userId ?? "", {
|
|
1407
1994
|
sessionId: effectiveSessionId,
|
|
1408
1995
|
tokenizedData: requestTokenizedBody,
|
|
@@ -1413,18 +2000,18 @@ function SplitCardFormInner({
|
|
|
1413
2000
|
lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
1414
2001
|
...avsConfig ? (() => {
|
|
1415
2002
|
const c = selectedCountryRef.current;
|
|
1416
|
-
const stateVisible = (0,
|
|
1417
|
-
const line1Visible = (0,
|
|
1418
|
-
const zipVisible = (0,
|
|
1419
|
-
const derivedState = line1Visible && !stateVisible && zipVisible ? (0,
|
|
2003
|
+
const stateVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.state, c);
|
|
2004
|
+
const line1Visible = (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, c);
|
|
2005
|
+
const zipVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, c);
|
|
2006
|
+
const derivedState = line1Visible && !stateVisible && zipVisible ? (0, import_shared5.getStateFromPostalCode)(c, zipCodeRef.current ?? "") : null;
|
|
1420
2007
|
const stateValue2 = stateVisible ? stateRef.current : derivedState;
|
|
1421
2008
|
return {
|
|
1422
2009
|
country: c,
|
|
1423
2010
|
...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
|
|
1424
|
-
...(0,
|
|
2011
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, c) && cityRef.current ? { city: cityRef.current } : {},
|
|
1425
2012
|
...stateValue2 ? { state: stateValue2 } : {},
|
|
1426
2013
|
...line1Visible && addressLine1Ref.current ? { addressLine1: addressLine1Ref.current } : {},
|
|
1427
|
-
...(0,
|
|
2014
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, c) && addressLine2Ref.current ? { addressLine2: addressLine2Ref.current } : {}
|
|
1428
2015
|
};
|
|
1429
2016
|
})() : {}
|
|
1430
2017
|
},
|
|
@@ -1436,17 +2023,18 @@ function SplitCardFormInner({
|
|
|
1436
2023
|
// Resolved exposure: which fields were actually shown for the active country.
|
|
1437
2024
|
// Country-scoped rules (e.g. ['US', 'CA']) are flattened to booleans here.
|
|
1438
2025
|
avsConfig: avsConfig ? {
|
|
1439
|
-
country: (0,
|
|
1440
|
-
postal_code: (0,
|
|
1441
|
-
address_line_1: (0,
|
|
1442
|
-
address_line_2: (0,
|
|
1443
|
-
city: (0,
|
|
1444
|
-
state: (0,
|
|
2026
|
+
country: (0, import_shared5.isAVSFieldVisible)(avsConfig.country, selectedCountryRef.current),
|
|
2027
|
+
postal_code: (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, selectedCountryRef.current),
|
|
2028
|
+
address_line_1: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, selectedCountryRef.current),
|
|
2029
|
+
address_line_2: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, selectedCountryRef.current),
|
|
2030
|
+
city: (0, import_shared5.isAVSFieldVisible)(avsConfig.city, selectedCountryRef.current),
|
|
2031
|
+
state: (0, import_shared5.isAVSFieldVisible)(avsConfig.state, selectedCountryRef.current)
|
|
1445
2032
|
} : void 0
|
|
1446
2033
|
});
|
|
1447
2034
|
if (response.ok) {
|
|
1448
2035
|
markSessionRecentlyCompleted(effectiveSessionId);
|
|
1449
2036
|
setOverlayStatus("success");
|
|
2037
|
+
setPaypalDirectRetry(null);
|
|
1450
2038
|
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
|
|
1451
2039
|
onComplete?.({
|
|
1452
2040
|
status: "succeeded",
|
|
@@ -1470,18 +2058,18 @@ function SplitCardFormInner({
|
|
|
1470
2058
|
const retryCC = selectedCountryRef.current;
|
|
1471
2059
|
const retryCountry = enableAVS ? retryCC : effectiveAccount.country;
|
|
1472
2060
|
if (retryCountry) retryBillingAddress["country"] = retryCountry;
|
|
1473
|
-
if (avsConfig && (0,
|
|
2061
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, retryCC) && zipCodeRef.current.trim()) {
|
|
1474
2062
|
retryBillingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
1475
2063
|
} else if (!avsConfig && effectiveAccount.zip) {
|
|
1476
2064
|
retryBillingAddress["postal_code"] = effectiveAccount.zip;
|
|
1477
2065
|
}
|
|
1478
|
-
if (avsConfig && (0,
|
|
1479
|
-
if (avsConfig && (0,
|
|
1480
|
-
if (avsConfig && (0,
|
|
1481
|
-
if (avsConfig && (0,
|
|
2066
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && addressLine1Ref.current.trim()) retryBillingAddress["line1"] = addressLine1Ref.current.trim();
|
|
2067
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, retryCC) && addressLine2Ref.current.trim()) retryBillingAddress["line2"] = addressLine2Ref.current.trim();
|
|
2068
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, retryCC) && cityRef.current.trim()) retryBillingAddress["city"] = cityRef.current.trim();
|
|
2069
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, retryCC) && stateRef.current.trim()) {
|
|
1482
2070
|
retryBillingAddress["state"] = stateRef.current.trim();
|
|
1483
|
-
} else if (avsConfig && (0,
|
|
1484
|
-
const derivedRetryState = (0,
|
|
2071
|
+
} else if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && !(0, import_shared5.isAVSFieldVisible)(avsConfig.state, retryCC) && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, retryCC)) {
|
|
2072
|
+
const derivedRetryState = (0, import_shared5.getStateFromPostalCode)(retryCC, zipCodeRef.current.trim());
|
|
1485
2073
|
if (derivedRetryState) retryBillingAddress["state"] = derivedRetryState;
|
|
1486
2074
|
}
|
|
1487
2075
|
const result = await flopay.confirmPayment({
|
|
@@ -1554,6 +2142,24 @@ function SplitCardFormInner({
|
|
|
1554
2142
|
}
|
|
1555
2143
|
return;
|
|
1556
2144
|
}
|
|
2145
|
+
if (json?.type === "paypal_direct_required") {
|
|
2146
|
+
const orderId = json["orderId"];
|
|
2147
|
+
if (!orderId) {
|
|
2148
|
+
setOverlayStatus("error");
|
|
2149
|
+
updateError("PayPal retry required but no order id provided.");
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
const prevAttempts = paypalDirectRetryRef.current?.attempts ?? 0;
|
|
2153
|
+
if (prevAttempts >= 2) {
|
|
2154
|
+
setOverlayStatus("error");
|
|
2155
|
+
updateError("PayPal payment could not be completed after multiple attempts.");
|
|
2156
|
+
emitDecline("paypal", "paypal_direct_required retry limit exceeded");
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
setPaypalDirectRetry({ orderId, attempts: prevAttempts + 1 });
|
|
2160
|
+
setOverlayStatus(null);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
1557
2163
|
setOverlayStatus("error");
|
|
1558
2164
|
const message = json?.message ?? "Payment failed. Please try again.";
|
|
1559
2165
|
updateError(message);
|
|
@@ -1574,7 +2180,7 @@ function SplitCardFormInner({
|
|
|
1574
2180
|
},
|
|
1575
2181
|
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
|
|
1576
2182
|
);
|
|
1577
|
-
const dispatchTokenizedBody = (0,
|
|
2183
|
+
const dispatchTokenizedBody = (0, import_react8.useCallback)(
|
|
1578
2184
|
(tokenizedBody, overrides) => {
|
|
1579
2185
|
if (onTokenizedBody) {
|
|
1580
2186
|
onTokenizedBody(tokenizedBody);
|
|
@@ -1584,7 +2190,7 @@ function SplitCardFormInner({
|
|
|
1584
2190
|
},
|
|
1585
2191
|
[onTokenizedBody, processPaymentInternal]
|
|
1586
2192
|
);
|
|
1587
|
-
(0,
|
|
2193
|
+
(0, import_react8.useImperativeHandle)(innerRef, () => ({
|
|
1588
2194
|
async handleNextAction(secret) {
|
|
1589
2195
|
if (!flopay) return;
|
|
1590
2196
|
setIs3DSActive(true);
|
|
@@ -1611,7 +2217,7 @@ function SplitCardFormInner({
|
|
|
1611
2217
|
}
|
|
1612
2218
|
}
|
|
1613
2219
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
1614
|
-
(0,
|
|
2220
|
+
(0, import_react8.useEffect)(() => {
|
|
1615
2221
|
if (typeof window === "undefined") return;
|
|
1616
2222
|
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
1617
2223
|
if (!stored) return;
|
|
@@ -1629,7 +2235,7 @@ function SplitCardFormInner({
|
|
|
1629
2235
|
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
1630
2236
|
}
|
|
1631
2237
|
}, [sessionId, dispatchTokenizedBody]);
|
|
1632
|
-
const handleSubmit = (0,
|
|
2238
|
+
const handleSubmit = (0, import_react8.useCallback)(
|
|
1633
2239
|
async (e) => {
|
|
1634
2240
|
e.preventDefault();
|
|
1635
2241
|
if (!flopay || !elements || isSubmitting || processingRef.current) return;
|
|
@@ -1643,20 +2249,20 @@ function SplitCardFormInner({
|
|
|
1643
2249
|
try {
|
|
1644
2250
|
if (avsConfig) {
|
|
1645
2251
|
const country = selectedCountryRef.current;
|
|
1646
|
-
if ((0,
|
|
1647
|
-
updateError((0,
|
|
2252
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, country) && !zipCodeRef.current.trim()) {
|
|
2253
|
+
updateError((0, import_shared5.getPostalCodeLabel)(country) + " is required");
|
|
1648
2254
|
return;
|
|
1649
2255
|
}
|
|
1650
|
-
if ((0,
|
|
2256
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
|
|
1651
2257
|
updateError("Street address is required");
|
|
1652
2258
|
return;
|
|
1653
2259
|
}
|
|
1654
|
-
if ((0,
|
|
2260
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.city, country) && !cityRef.current.trim()) {
|
|
1655
2261
|
updateError("City is required");
|
|
1656
2262
|
return;
|
|
1657
2263
|
}
|
|
1658
|
-
if ((0,
|
|
1659
|
-
updateError((0,
|
|
2264
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.state, country) && !stateRef.current.trim()) {
|
|
2265
|
+
updateError((0, import_shared5.getStateLabel)(country) + " is required");
|
|
1660
2266
|
return;
|
|
1661
2267
|
}
|
|
1662
2268
|
}
|
|
@@ -1670,18 +2276,18 @@ function SplitCardFormInner({
|
|
|
1670
2276
|
const cc = selectedCountryRef.current;
|
|
1671
2277
|
const avsCountry = enableAVS ? cc : resolvedAccount.country;
|
|
1672
2278
|
if (avsCountry) billingAddress["country"] = avsCountry;
|
|
1673
|
-
if (avsConfig && (0,
|
|
2279
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && zipCodeRef.current.trim()) {
|
|
1674
2280
|
billingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
1675
2281
|
} else if (!avsConfig && resolvedAccount.zip) {
|
|
1676
2282
|
billingAddress["postal_code"] = resolvedAccount.zip;
|
|
1677
2283
|
}
|
|
1678
|
-
if (avsConfig && (0,
|
|
1679
|
-
if (avsConfig && (0,
|
|
1680
|
-
if (avsConfig && (0,
|
|
1681
|
-
if (avsConfig && (0,
|
|
2284
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && addressLine1Ref.current.trim()) billingAddress["line1"] = addressLine1Ref.current.trim();
|
|
2285
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, cc) && addressLine2Ref.current.trim()) billingAddress["line2"] = addressLine2Ref.current.trim();
|
|
2286
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && cityRef.current.trim()) billingAddress["city"] = cityRef.current.trim();
|
|
2287
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && stateRef.current.trim()) {
|
|
1682
2288
|
billingAddress["state"] = stateRef.current.trim();
|
|
1683
|
-
} else if (avsConfig && (0,
|
|
1684
|
-
const derivedSubmitState = (0,
|
|
2289
|
+
} else if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && !(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc)) {
|
|
2290
|
+
const derivedSubmitState = (0, import_shared5.getStateFromPostalCode)(cc, zipCodeRef.current.trim());
|
|
1685
2291
|
if (derivedSubmitState) billingAddress["state"] = derivedSubmitState;
|
|
1686
2292
|
}
|
|
1687
2293
|
const billingDetails = {
|
|
@@ -1695,7 +2301,7 @@ function SplitCardFormInner({
|
|
|
1695
2301
|
return;
|
|
1696
2302
|
}
|
|
1697
2303
|
if (!sessionId || !resolvedAccount.email) {
|
|
1698
|
-
throw new
|
|
2304
|
+
throw new import_shared6.FloPayError("Missing sessionId or email", "validation_error");
|
|
1699
2305
|
}
|
|
1700
2306
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
1701
2307
|
method: "POST",
|
|
@@ -1721,7 +2327,7 @@ function SplitCardFormInner({
|
|
|
1721
2327
|
}
|
|
1722
2328
|
const intentJson = await intentResponse.json();
|
|
1723
2329
|
const intentClientSecret = intentJson.data?.id;
|
|
1724
|
-
if (!intentClientSecret) throw new
|
|
2330
|
+
if (!intentClientSecret) throw new import_shared6.FloPayError("No client_secret in payment intent response", "api_error");
|
|
1725
2331
|
const confirmResult = await flopay.confirmCardPayment({
|
|
1726
2332
|
clientSecret: intentClientSecret,
|
|
1727
2333
|
paymentMethodId: pmResult.paymentMethodId
|
|
@@ -1742,7 +2348,7 @@ function SplitCardFormInner({
|
|
|
1742
2348
|
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
1743
2349
|
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
1744
2350
|
if (!paymentIntentId) {
|
|
1745
|
-
const error2 = new
|
|
2351
|
+
const error2 = new import_shared6.FloPayError("No payment intent returned after confirmation.", "api_error");
|
|
1746
2352
|
setOverlayStatus("error");
|
|
1747
2353
|
updateError(error2.message);
|
|
1748
2354
|
onError?.(error2);
|
|
@@ -1771,7 +2377,7 @@ function SplitCardFormInner({
|
|
|
1771
2377
|
);
|
|
1772
2378
|
const isReady = flopay !== null && elements !== null;
|
|
1773
2379
|
if (!isReady) {
|
|
1774
|
-
return /* @__PURE__ */ (0,
|
|
2380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
|
|
1775
2381
|
}
|
|
1776
2382
|
const isButtons = layout === "buttons";
|
|
1777
2383
|
const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
|
|
@@ -1814,7 +2420,7 @@ function SplitCardFormInner({
|
|
|
1814
2420
|
invalid: { color: "#ef4444" }
|
|
1815
2421
|
}
|
|
1816
2422
|
};
|
|
1817
|
-
const cardFormBlock = /* @__PURE__ */ (0,
|
|
2423
|
+
const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1818
2424
|
backgroundColor: cardBg,
|
|
1819
2425
|
borderRadius: "8px",
|
|
1820
2426
|
padding: isButtons ? "0" : "1rem",
|
|
@@ -1822,7 +2428,7 @@ function SplitCardFormInner({
|
|
|
1822
2428
|
...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
|
|
1823
2429
|
...sharedInputPlaceholderVars
|
|
1824
2430
|
}, children: [
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
2431
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
|
|
1826
2432
|
.flopay-shared-input::placeholder {
|
|
1827
2433
|
color: var(--flopay-input-placeholder-color);
|
|
1828
2434
|
opacity: 1;
|
|
@@ -1831,12 +2437,12 @@ function SplitCardFormInner({
|
|
|
1831
2437
|
font-weight: var(--flopay-input-font-weight);
|
|
1832
2438
|
}
|
|
1833
2439
|
` }),
|
|
1834
|
-
isButtons && showCardForm && /* @__PURE__ */ (0,
|
|
2440
|
+
isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1835
2441
|
display: "flex",
|
|
1836
2442
|
alignItems: "center",
|
|
1837
2443
|
padding: "0.75rem 0 0.625rem"
|
|
1838
2444
|
}, children: [
|
|
1839
|
-
/* @__PURE__ */ (0,
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1840
2446
|
"button",
|
|
1841
2447
|
{
|
|
1842
2448
|
type: "button",
|
|
@@ -1858,7 +2464,7 @@ function SplitCardFormInner({
|
|
|
1858
2464
|
},
|
|
1859
2465
|
"aria-label": "Back to payment methods",
|
|
1860
2466
|
children: [
|
|
1861
|
-
/* @__PURE__ */ (0,
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
|
|
1862
2468
|
display: "inline-flex",
|
|
1863
2469
|
alignItems: "center",
|
|
1864
2470
|
justifyContent: "center",
|
|
@@ -1868,12 +2474,12 @@ function SplitCardFormInner({
|
|
|
1868
2474
|
backgroundColor: "#f3f4f6",
|
|
1869
2475
|
transition: "background-color 0.15s",
|
|
1870
2476
|
...bStyles.backButtonIcon
|
|
1871
|
-
}, children: /* @__PURE__ */ (0,
|
|
1872
|
-
/* @__PURE__ */ (0,
|
|
2477
|
+
}, 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" }) }) }),
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
1873
2479
|
]
|
|
1874
2480
|
}
|
|
1875
2481
|
),
|
|
1876
|
-
hideTitle ? /* @__PURE__ */ (0,
|
|
2482
|
+
hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1877
2483
|
flex: 1,
|
|
1878
2484
|
textAlign: "center",
|
|
1879
2485
|
fontWeight: 600,
|
|
@@ -1881,18 +2487,18 @@ function SplitCardFormInner({
|
|
|
1881
2487
|
color: "#262833",
|
|
1882
2488
|
paddingRight: 80,
|
|
1883
2489
|
...bStyles.title
|
|
1884
|
-
}, children: /* @__PURE__ */ (0,
|
|
2490
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
|
|
1885
2491
|
] }),
|
|
1886
|
-
!isButtons && !hideTitle && /* @__PURE__ */ (0,
|
|
1887
|
-
/* @__PURE__ */ (0,
|
|
2492
|
+
!isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1888
2494
|
backgroundColor: cardInputBg,
|
|
1889
2495
|
border: `1px solid ${resolvedBorder}`,
|
|
1890
2496
|
borderTopLeftRadius: "8px",
|
|
1891
2497
|
borderTopRightRadius: "8px",
|
|
1892
2498
|
padding: "10px"
|
|
1893
|
-
}, children: /* @__PURE__ */ (0,
|
|
1894
|
-
/* @__PURE__ */ (0,
|
|
1895
|
-
/* @__PURE__ */ (0,
|
|
2499
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1896
2502
|
flex: 1,
|
|
1897
2503
|
backgroundColor: cardInputBg,
|
|
1898
2504
|
border: `1px solid ${resolvedBorder}`,
|
|
@@ -1900,23 +2506,23 @@ function SplitCardFormInner({
|
|
|
1900
2506
|
borderRight: "none",
|
|
1901
2507
|
borderBottomLeftRadius: "8px",
|
|
1902
2508
|
padding: "10px"
|
|
1903
|
-
}, children: /* @__PURE__ */ (0,
|
|
1904
|
-
/* @__PURE__ */ (0,
|
|
2509
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
2510
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1905
2511
|
flex: 1,
|
|
1906
2512
|
backgroundColor: cardInputBg,
|
|
1907
2513
|
border: `1px solid ${resolvedBorder}`,
|
|
1908
2514
|
borderTop: "none",
|
|
1909
2515
|
borderBottomRightRadius: "8px",
|
|
1910
2516
|
padding: "10px"
|
|
1911
|
-
}, children: /* @__PURE__ */ (0,
|
|
2517
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardCvcElement, { options: stripeElementStyle }) })
|
|
1912
2518
|
] }),
|
|
1913
|
-
/* @__PURE__ */ (0,
|
|
2519
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1914
2520
|
backgroundColor: cardInputBg,
|
|
1915
2521
|
border: `1px solid ${resolvedBorder}`,
|
|
1916
2522
|
borderRadius: "8px",
|
|
1917
2523
|
marginTop: "0.5rem",
|
|
1918
2524
|
padding: "10px"
|
|
1919
|
-
}, children: /* @__PURE__ */ (0,
|
|
2525
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1920
2526
|
"input",
|
|
1921
2527
|
{
|
|
1922
2528
|
className: "flopay-shared-input",
|
|
@@ -1954,9 +2560,9 @@ function SplitCardFormInner({
|
|
|
1954
2560
|
...sharedInputTypography,
|
|
1955
2561
|
...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
|
|
1956
2562
|
});
|
|
1957
|
-
const stateOpts = (0,
|
|
1958
|
-
return /* @__PURE__ */ (0,
|
|
1959
|
-
(0,
|
|
2563
|
+
const stateOpts = (0, import_shared5.getStateOptions)(cc);
|
|
2564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2565
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: inputWrapStyle(bStyles.addressLine1Input), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1960
2566
|
"input",
|
|
1961
2567
|
{
|
|
1962
2568
|
className: "flopay-shared-input",
|
|
@@ -1973,7 +2579,7 @@ function SplitCardFormInner({
|
|
|
1973
2579
|
style: inputFieldStyle()
|
|
1974
2580
|
}
|
|
1975
2581
|
) }),
|
|
1976
|
-
(0,
|
|
2582
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: inputWrapStyle(bStyles.addressLine2Input), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1977
2583
|
"input",
|
|
1978
2584
|
{
|
|
1979
2585
|
className: "flopay-shared-input",
|
|
@@ -1989,21 +2595,21 @@ function SplitCardFormInner({
|
|
|
1989
2595
|
style: inputFieldStyle()
|
|
1990
2596
|
}
|
|
1991
2597
|
) }),
|
|
1992
|
-
((0,
|
|
2598
|
+
((0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1993
2599
|
display: "flex",
|
|
1994
2600
|
gap: "0",
|
|
1995
2601
|
marginTop: "0.5rem"
|
|
1996
2602
|
}, children: [
|
|
1997
|
-
(0,
|
|
2603
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1998
2604
|
flex: 1,
|
|
1999
2605
|
backgroundColor: cardInputBg,
|
|
2000
2606
|
border: `1px solid ${resolvedBorder}`,
|
|
2001
2607
|
padding: "10px",
|
|
2002
2608
|
borderTopLeftRadius: "8px",
|
|
2003
2609
|
borderBottomLeftRadius: "8px",
|
|
2004
|
-
...(0,
|
|
2610
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: "8px" },
|
|
2005
2611
|
...isButtons && bStyles.cityInput ? bStyles.cityInput : {}
|
|
2006
|
-
}, children: /* @__PURE__ */ (0,
|
|
2612
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2007
2613
|
"input",
|
|
2008
2614
|
{
|
|
2009
2615
|
className: "flopay-shared-input",
|
|
@@ -2020,16 +2626,16 @@ function SplitCardFormInner({
|
|
|
2020
2626
|
style: inputFieldStyle()
|
|
2021
2627
|
}
|
|
2022
2628
|
) }),
|
|
2023
|
-
(0,
|
|
2629
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2024
2630
|
flex: 1,
|
|
2025
2631
|
backgroundColor: cardInputBg,
|
|
2026
2632
|
border: `1px solid ${resolvedBorder}`,
|
|
2027
2633
|
padding: "10px",
|
|
2028
2634
|
borderTopRightRadius: "8px",
|
|
2029
2635
|
borderBottomRightRadius: "8px",
|
|
2030
|
-
...(0,
|
|
2636
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius: "8px" },
|
|
2031
2637
|
...isButtons && bStyles.stateInput ? bStyles.stateInput : {}
|
|
2032
|
-
}, children: stateOpts ? /* @__PURE__ */ (0,
|
|
2638
|
+
}, children: stateOpts ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2033
2639
|
"select",
|
|
2034
2640
|
{
|
|
2035
2641
|
value: stateValue,
|
|
@@ -2043,15 +2649,15 @@ function SplitCardFormInner({
|
|
|
2043
2649
|
"data-testid": "flopay-state",
|
|
2044
2650
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
2045
2651
|
children: [
|
|
2046
|
-
/* @__PURE__ */ (0,
|
|
2047
|
-
stateOpts.map((s) => /* @__PURE__ */ (0,
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: (0, import_shared5.getStateLabel)(cc) }),
|
|
2653
|
+
stateOpts.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: s.code, children: s.name }, s.code))
|
|
2048
2654
|
]
|
|
2049
2655
|
}
|
|
2050
|
-
) : /* @__PURE__ */ (0,
|
|
2656
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2051
2657
|
"input",
|
|
2052
2658
|
{
|
|
2053
2659
|
className: "flopay-shared-input",
|
|
2054
|
-
placeholder: (0,
|
|
2660
|
+
placeholder: (0, import_shared5.getStateLabel)(cc),
|
|
2055
2661
|
autoComplete: "address-level1",
|
|
2056
2662
|
value: stateValue,
|
|
2057
2663
|
onChange: (e) => {
|
|
@@ -2065,20 +2671,20 @@ function SplitCardFormInner({
|
|
|
2065
2671
|
}
|
|
2066
2672
|
) })
|
|
2067
2673
|
] }),
|
|
2068
|
-
((0,
|
|
2674
|
+
((0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2069
2675
|
display: "flex",
|
|
2070
2676
|
flexDirection: avsLayoutProp === "column" ? "column" : "row",
|
|
2071
2677
|
gap: avsLayoutProp === "column" ? "0.5rem" : "0",
|
|
2072
2678
|
marginTop: "0.5rem"
|
|
2073
2679
|
}, children: [
|
|
2074
|
-
(0,
|
|
2680
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2075
2681
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2076
2682
|
backgroundColor: cardInputBg,
|
|
2077
2683
|
border: `1px solid ${resolvedBorder}`,
|
|
2078
2684
|
padding: "10px",
|
|
2079
|
-
...avsLayoutProp === "row" && (0,
|
|
2685
|
+
...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
|
|
2080
2686
|
...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
|
|
2081
|
-
}, children: /* @__PURE__ */ (0,
|
|
2687
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2082
2688
|
"select",
|
|
2083
2689
|
{
|
|
2084
2690
|
value: selectedCountry,
|
|
@@ -2093,25 +2699,25 @@ function SplitCardFormInner({
|
|
|
2093
2699
|
autoComplete: "country",
|
|
2094
2700
|
"data-testid": "flopay-country",
|
|
2095
2701
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
2096
|
-
children:
|
|
2702
|
+
children: import_shared5.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: c.code, children: [
|
|
2097
2703
|
c.flag,
|
|
2098
2704
|
" ",
|
|
2099
2705
|
c.name
|
|
2100
2706
|
] }, c.code))
|
|
2101
2707
|
}
|
|
2102
2708
|
) }),
|
|
2103
|
-
(0,
|
|
2709
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2104
2710
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2105
2711
|
backgroundColor: cardInputBg,
|
|
2106
2712
|
border: `1px solid ${resolvedBorder}`,
|
|
2107
2713
|
padding: "10px",
|
|
2108
|
-
...avsLayoutProp === "row" && (0,
|
|
2714
|
+
...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
|
|
2109
2715
|
...isButtons && bStyles.zipInput ? bStyles.zipInput : {}
|
|
2110
|
-
}, children: /* @__PURE__ */ (0,
|
|
2716
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2111
2717
|
"input",
|
|
2112
2718
|
{
|
|
2113
2719
|
className: "flopay-shared-input",
|
|
2114
|
-
placeholder: (0,
|
|
2720
|
+
placeholder: (0, import_shared5.getPostalCodeLabel)(selectedCountry),
|
|
2115
2721
|
autoComplete: "postal-code",
|
|
2116
2722
|
value: zipCode,
|
|
2117
2723
|
onChange: (e) => {
|
|
@@ -2128,7 +2734,7 @@ function SplitCardFormInner({
|
|
|
2128
2734
|
] })
|
|
2129
2735
|
] });
|
|
2130
2736
|
})(),
|
|
2131
|
-
displayError && /* @__PURE__ */ (0,
|
|
2737
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
2132
2738
|
margin: "0.75rem 0",
|
|
2133
2739
|
padding: "0.625rem 0.875rem",
|
|
2134
2740
|
background: "#FEF2F2",
|
|
@@ -2142,10 +2748,10 @@ function SplitCardFormInner({
|
|
|
2142
2748
|
gap: "0.5rem",
|
|
2143
2749
|
...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
2144
2750
|
}, children: [
|
|
2145
|
-
/* @__PURE__ */ (0,
|
|
2751
|
+
/* @__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" }) }),
|
|
2146
2752
|
displayError
|
|
2147
2753
|
] }),
|
|
2148
|
-
children ?? /* @__PURE__ */ (0,
|
|
2754
|
+
children ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2149
2755
|
"button",
|
|
2150
2756
|
{
|
|
2151
2757
|
type: "submit",
|
|
@@ -2168,7 +2774,7 @@ function SplitCardFormInner({
|
|
|
2168
2774
|
children: isSubmitting ? "PROCESSING..." : submitLabel
|
|
2169
2775
|
}
|
|
2170
2776
|
),
|
|
2171
|
-
!isButtons && showSecurityFooter && /* @__PURE__ */ (0,
|
|
2777
|
+
!isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2172
2778
|
backgroundColor: "#EFF9F0",
|
|
2173
2779
|
borderRadius: "8px",
|
|
2174
2780
|
padding: "0.75rem",
|
|
@@ -2185,11 +2791,11 @@ function SplitCardFormInner({
|
|
|
2185
2791
|
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2186
2792
|
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;
|
|
2187
2793
|
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;
|
|
2188
|
-
return /* @__PURE__ */ (0,
|
|
2189
|
-
/* @__PURE__ */ (0,
|
|
2190
|
-
overlayStatus && /* @__PURE__ */ (0,
|
|
2191
|
-
/* @__PURE__ */ (0,
|
|
2192
|
-
/* @__PURE__ */ (0,
|
|
2794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2795
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
2796
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2797
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "grid" }, children: [
|
|
2798
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2193
2799
|
gridArea: "1 / 1",
|
|
2194
2800
|
display: "flex",
|
|
2195
2801
|
flexDirection: "column",
|
|
@@ -2198,7 +2804,75 @@ function SplitCardFormInner({
|
|
|
2198
2804
|
...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
|
|
2199
2805
|
...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
|
|
2200
2806
|
}, children: [
|
|
2201
|
-
|
|
2807
|
+
debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2808
|
+
"pre",
|
|
2809
|
+
{
|
|
2810
|
+
"data-testid": "flopay-direct-paypal-gate-debug",
|
|
2811
|
+
style: {
|
|
2812
|
+
margin: 0,
|
|
2813
|
+
padding: "6px 8px",
|
|
2814
|
+
background: "#eef2ff",
|
|
2815
|
+
border: "1px solid #c7d2fe",
|
|
2816
|
+
borderRadius: 6,
|
|
2817
|
+
color: "#111827",
|
|
2818
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2819
|
+
whiteSpace: "pre-wrap",
|
|
2820
|
+
wordBreak: "break-word"
|
|
2821
|
+
},
|
|
2822
|
+
children: [
|
|
2823
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2824
|
+
` showPayPal=${showPayPal}`,
|
|
2825
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2826
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2827
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2828
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2829
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2830
|
+
].join("\n")
|
|
2831
|
+
}
|
|
2832
|
+
),
|
|
2833
|
+
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2834
|
+
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2835
|
+
"div",
|
|
2836
|
+
{
|
|
2837
|
+
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
2838
|
+
style: {
|
|
2839
|
+
padding: "8px 10px",
|
|
2840
|
+
background: "#fef3c7",
|
|
2841
|
+
border: "1px solid #fcd34d",
|
|
2842
|
+
borderRadius: 6,
|
|
2843
|
+
color: "#78350f",
|
|
2844
|
+
fontSize: 13,
|
|
2845
|
+
lineHeight: 1.4
|
|
2846
|
+
},
|
|
2847
|
+
children: "Please confirm your PayPal payment to complete checkout."
|
|
2848
|
+
}
|
|
2849
|
+
),
|
|
2850
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2851
|
+
DirectPayPalButton,
|
|
2852
|
+
{
|
|
2853
|
+
sessionId,
|
|
2854
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
2855
|
+
email: resolvedAccount.email,
|
|
2856
|
+
clientId: directPaypal.clientId,
|
|
2857
|
+
environment: directPaypal.environment,
|
|
2858
|
+
currency: currency.toUpperCase(),
|
|
2859
|
+
isSubscription,
|
|
2860
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
2861
|
+
onComplete,
|
|
2862
|
+
onErrorChange: updateError,
|
|
2863
|
+
onDecline,
|
|
2864
|
+
onButtonClick,
|
|
2865
|
+
runBeforeButtonClick,
|
|
2866
|
+
isProcessing: isSubmitting,
|
|
2867
|
+
onLoadStateChange: setDirectPaypalReady,
|
|
2868
|
+
session: session ?? null,
|
|
2869
|
+
existingOrderId: paypalDirectRetry?.orderId,
|
|
2870
|
+
debug
|
|
2871
|
+
},
|
|
2872
|
+
paypalDirectRetry?.orderId ?? "fresh"
|
|
2873
|
+
)
|
|
2874
|
+
] }),
|
|
2875
|
+
shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2202
2876
|
PayPalButtonInner,
|
|
2203
2877
|
{
|
|
2204
2878
|
sessionId,
|
|
@@ -2213,7 +2887,7 @@ function SplitCardFormInner({
|
|
|
2213
2887
|
onLoadStateChange: setPaypalLoadState
|
|
2214
2888
|
}
|
|
2215
2889
|
) }),
|
|
2216
|
-
shouldRenderWallets ? /* @__PURE__ */ (0,
|
|
2890
|
+
shouldRenderWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2217
2891
|
WalletButtonInner,
|
|
2218
2892
|
{
|
|
2219
2893
|
sessionId,
|
|
@@ -2228,8 +2902,8 @@ function SplitCardFormInner({
|
|
|
2228
2902
|
runBeforeButtonClick,
|
|
2229
2903
|
onLoadStateChange: setWalletLoadState
|
|
2230
2904
|
}
|
|
2231
|
-
) }) : shouldShowWallets ? /* @__PURE__ */ (0,
|
|
2232
|
-
/* @__PURE__ */ (0,
|
|
2905
|
+
) }) : shouldShowWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
2906
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2233
2907
|
"button",
|
|
2234
2908
|
{
|
|
2235
2909
|
type: "button",
|
|
@@ -2267,10 +2941,10 @@ function SplitCardFormInner({
|
|
|
2267
2941
|
onMouseUp: (e) => {
|
|
2268
2942
|
e.currentTarget.style.transform = "scale(1)";
|
|
2269
2943
|
},
|
|
2270
|
-
children: /* @__PURE__ */ (0,
|
|
2944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
|
|
2271
2945
|
}
|
|
2272
2946
|
),
|
|
2273
|
-
displayError && viewState === "buttons" && /* @__PURE__ */ (0,
|
|
2947
|
+
displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
2274
2948
|
margin: "0.25rem 0",
|
|
2275
2949
|
padding: "0.625rem 0.875rem",
|
|
2276
2950
|
background: "#FEF2F2",
|
|
@@ -2284,11 +2958,11 @@ function SplitCardFormInner({
|
|
|
2284
2958
|
gap: "0.5rem",
|
|
2285
2959
|
...bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
2286
2960
|
}, children: [
|
|
2287
|
-
/* @__PURE__ */ (0,
|
|
2961
|
+
/* @__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" }) }),
|
|
2288
2962
|
displayError
|
|
2289
2963
|
] })
|
|
2290
2964
|
] }),
|
|
2291
|
-
isCardView && /* @__PURE__ */ (0,
|
|
2965
|
+
isCardView && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2292
2966
|
gridArea: "1 / 1",
|
|
2293
2967
|
...cardAnim ? { animation: cardAnim } : {},
|
|
2294
2968
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
@@ -2296,37 +2970,111 @@ function SplitCardFormInner({
|
|
|
2296
2970
|
] })
|
|
2297
2971
|
] });
|
|
2298
2972
|
}
|
|
2299
|
-
return /* @__PURE__ */ (0,
|
|
2300
|
-
/* @__PURE__ */ (0,
|
|
2301
|
-
overlayStatus && /* @__PURE__ */ (0,
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2974
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
2975
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2977
|
+
debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2978
|
+
"pre",
|
|
2979
|
+
{
|
|
2980
|
+
"data-testid": "flopay-direct-paypal-gate-debug-default",
|
|
2981
|
+
style: {
|
|
2982
|
+
margin: 0,
|
|
2983
|
+
padding: "6px 8px",
|
|
2984
|
+
background: "#eef2ff",
|
|
2985
|
+
border: "1px solid #c7d2fe",
|
|
2986
|
+
borderRadius: 6,
|
|
2987
|
+
color: "#111827",
|
|
2988
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2989
|
+
whiteSpace: "pre-wrap",
|
|
2990
|
+
wordBreak: "break-word"
|
|
2991
|
+
},
|
|
2992
|
+
children: [
|
|
2993
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2994
|
+
` showPayPal=${showPayPal}`,
|
|
2995
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2996
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2997
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2998
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2999
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
3000
|
+
].join("\n")
|
|
3001
|
+
}
|
|
3002
|
+
),
|
|
3003
|
+
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
3004
|
+
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3005
|
+
"div",
|
|
3006
|
+
{
|
|
3007
|
+
"data-testid": "flopay-paypal-direct-retry-notice-default",
|
|
3008
|
+
style: {
|
|
3009
|
+
padding: "8px 10px",
|
|
3010
|
+
background: "#fef3c7",
|
|
3011
|
+
border: "1px solid #fcd34d",
|
|
3012
|
+
borderRadius: 6,
|
|
3013
|
+
color: "#78350f",
|
|
3014
|
+
fontSize: 13,
|
|
3015
|
+
lineHeight: 1.4
|
|
3016
|
+
},
|
|
3017
|
+
children: "Please confirm your PayPal payment to complete checkout."
|
|
3018
|
+
}
|
|
3019
|
+
),
|
|
3020
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3021
|
+
DirectPayPalButton,
|
|
3022
|
+
{
|
|
3023
|
+
sessionId,
|
|
3024
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3025
|
+
email: resolvedAccount.email,
|
|
3026
|
+
clientId: directPaypal.clientId,
|
|
3027
|
+
environment: directPaypal.environment,
|
|
3028
|
+
currency: currency.toUpperCase(),
|
|
3029
|
+
isSubscription,
|
|
3030
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3031
|
+
onComplete,
|
|
3032
|
+
onErrorChange: updateError,
|
|
3033
|
+
onDecline,
|
|
3034
|
+
onButtonClick,
|
|
3035
|
+
runBeforeButtonClick,
|
|
3036
|
+
isProcessing: isSubmitting,
|
|
3037
|
+
onLoadStateChange: setDirectPaypalReady,
|
|
3038
|
+
session: session ?? null,
|
|
3039
|
+
existingOrderId: paypalDirectRetry?.orderId,
|
|
3040
|
+
debug
|
|
3041
|
+
},
|
|
3042
|
+
paypalDirectRetry?.orderId ?? "fresh"
|
|
3043
|
+
)
|
|
3044
|
+
] }),
|
|
3045
|
+
shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3046
|
+
PayPalButtonInner,
|
|
3047
|
+
{
|
|
3048
|
+
sessionId,
|
|
3049
|
+
email: resolvedAccount.email,
|
|
3050
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3051
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3052
|
+
onErrorChange: updateError,
|
|
3053
|
+
isProcessing: isSubmitting,
|
|
3054
|
+
onButtonClick,
|
|
3055
|
+
onDecline,
|
|
3056
|
+
runBeforeButtonClick,
|
|
3057
|
+
onLoadStateChange: setPaypalLoadState
|
|
3058
|
+
}
|
|
3059
|
+
) }),
|
|
3060
|
+
shouldRenderWallets && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3061
|
+
WalletButtonInner,
|
|
3062
|
+
{
|
|
3063
|
+
sessionId,
|
|
3064
|
+
email: resolvedAccount.email,
|
|
3065
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3066
|
+
showApplePay,
|
|
3067
|
+
showGooglePay,
|
|
3068
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3069
|
+
onErrorChange: updateError,
|
|
3070
|
+
onButtonClick,
|
|
3071
|
+
onDecline,
|
|
3072
|
+
runBeforeButtonClick,
|
|
3073
|
+
onLoadStateChange: setWalletLoadState
|
|
3074
|
+
}
|
|
3075
|
+
) })
|
|
3076
|
+
] }),
|
|
3077
|
+
(shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2330
3078
|
display: "flex",
|
|
2331
3079
|
alignItems: "center",
|
|
2332
3080
|
gap: "0.75rem",
|
|
@@ -2334,17 +3082,17 @@ function SplitCardFormInner({
|
|
|
2334
3082
|
color: "#999",
|
|
2335
3083
|
fontSize: "0.85rem"
|
|
2336
3084
|
}, children: [
|
|
2337
|
-
/* @__PURE__ */ (0,
|
|
2338
|
-
/* @__PURE__ */ (0,
|
|
2339
|
-
/* @__PURE__ */ (0,
|
|
3085
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
|
|
3086
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "or pay with card" }),
|
|
3087
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
2340
3088
|
] }),
|
|
2341
3089
|
cardFormBlock
|
|
2342
3090
|
] });
|
|
2343
3091
|
}
|
|
2344
3092
|
|
|
2345
3093
|
// src/saved-payment-flow.ts
|
|
2346
|
-
var
|
|
2347
|
-
var
|
|
3094
|
+
var import_js3 = require("@flopay/js");
|
|
3095
|
+
var import_shared7 = require("@flopay/shared");
|
|
2348
3096
|
var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
|
|
2349
3097
|
function getRedirectResultFromCheckoutProcessError(error) {
|
|
2350
3098
|
if (!error?.type || !error.threeDSecureToken) {
|
|
@@ -2361,9 +3109,11 @@ function getRedirectResultFromCheckoutProcessError(error) {
|
|
|
2361
3109
|
}
|
|
2362
3110
|
function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
|
|
2363
3111
|
const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
|
|
3112
|
+
const rawMessage = error?.message ?? fallbackMessage;
|
|
3113
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
2364
3114
|
return Object.assign(
|
|
2365
|
-
new
|
|
2366
|
-
|
|
3115
|
+
new import_shared7.FloPayError(
|
|
3116
|
+
message,
|
|
2367
3117
|
"api_error",
|
|
2368
3118
|
{
|
|
2369
3119
|
code: error?.gatewayErrorCode
|
|
@@ -2417,16 +3167,19 @@ function getRedirectTokenFromProcessResponse(json, options) {
|
|
|
2417
3167
|
return candidate;
|
|
2418
3168
|
}
|
|
2419
3169
|
}
|
|
2420
|
-
const
|
|
2421
|
-
if (
|
|
2422
|
-
const
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
3170
|
+
const nestedGateways = nestedRecord.gateways;
|
|
3171
|
+
if (nestedGateways && typeof nestedGateways === "object") {
|
|
3172
|
+
const stripeGateway = nestedGateways.stripe;
|
|
3173
|
+
if (stripeGateway && typeof stripeGateway === "object") {
|
|
3174
|
+
const stripeRecord = stripeGateway;
|
|
3175
|
+
const gatewayCandidates = [
|
|
3176
|
+
stripeRecord.stripeClientSecret,
|
|
3177
|
+
stripeRecord.clientSecret
|
|
3178
|
+
];
|
|
3179
|
+
for (const candidate of gatewayCandidates) {
|
|
3180
|
+
if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
|
|
3181
|
+
return candidate;
|
|
3182
|
+
}
|
|
2430
3183
|
}
|
|
2431
3184
|
}
|
|
2432
3185
|
}
|
|
@@ -2451,9 +3204,9 @@ async function recover3DSRedirectResult({
|
|
|
2451
3204
|
return null;
|
|
2452
3205
|
}
|
|
2453
3206
|
try {
|
|
2454
|
-
const api = new
|
|
3207
|
+
const api = new import_js3.PaymentAPI(billingApiUrl);
|
|
2455
3208
|
const unified = await api.getUnifiedCheckoutSession(sessionId);
|
|
2456
|
-
const refreshedToken = unified.
|
|
3209
|
+
const refreshedToken = unified.data.stripe?.clientSecret;
|
|
2457
3210
|
if (isStripePaymentIntentClientSecret(refreshedToken)) {
|
|
2458
3211
|
return {
|
|
2459
3212
|
type: "3ds_required",
|
|
@@ -2479,7 +3232,7 @@ async function processSavedPaymentForMode({
|
|
|
2479
3232
|
const lastName = session.customer?.lastName ?? session.accountData?.lastName ?? "";
|
|
2480
3233
|
const country = session.customer?.country ?? session.accountData?.country ?? void 0;
|
|
2481
3234
|
const zip = session.customer?.zip ?? session.accountData?.zip ?? void 0;
|
|
2482
|
-
const api = new
|
|
3235
|
+
const api = new import_js3.PaymentAPI(baseUrl);
|
|
2483
3236
|
const response = await retryOnceOnFetchFailure(() => api.processPayment(customerId, {
|
|
2484
3237
|
sessionId: resolvedSessionId,
|
|
2485
3238
|
tokenizedData,
|
|
@@ -2508,7 +3261,7 @@ async function processSavedPaymentForMode({
|
|
|
2508
3261
|
if (json?.type === "paypal_redirect_required" || json?.type === "3ds_required") {
|
|
2509
3262
|
const redirectToken = getRedirectTokenFromProcessResponse(json);
|
|
2510
3263
|
if (!redirectToken) {
|
|
2511
|
-
throw new
|
|
3264
|
+
throw new import_shared7.FloPayError(
|
|
2512
3265
|
"Authentication is required but no redirect token was provided.",
|
|
2513
3266
|
"api_error",
|
|
2514
3267
|
{ code: "authentication_required" }
|
|
@@ -2530,7 +3283,7 @@ async function processSavedPaymentForMode({
|
|
|
2530
3283
|
return recoveredRedirect;
|
|
2531
3284
|
}
|
|
2532
3285
|
throw Object.assign(
|
|
2533
|
-
new
|
|
3286
|
+
new import_shared7.FloPayError(
|
|
2534
3287
|
"Your card requires authentication. Please enter your payment details below.",
|
|
2535
3288
|
"api_error",
|
|
2536
3289
|
{ code: "authentication_required" }
|
|
@@ -2538,7 +3291,7 @@ async function processSavedPaymentForMode({
|
|
|
2538
3291
|
{ checkoutMethod: "card" }
|
|
2539
3292
|
);
|
|
2540
3293
|
}
|
|
2541
|
-
throw new
|
|
3294
|
+
throw new import_shared7.FloPayError(
|
|
2542
3295
|
json?.message ?? "Payment failed. Please try again.",
|
|
2543
3296
|
"api_error",
|
|
2544
3297
|
{
|
|
@@ -2558,13 +3311,13 @@ async function processSavedPaymentWithIntent({
|
|
|
2558
3311
|
const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
|
|
2559
3312
|
if (!customerEmail) {
|
|
2560
3313
|
throw Object.assign(
|
|
2561
|
-
new
|
|
3314
|
+
new import_shared7.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
|
|
2562
3315
|
param: "email"
|
|
2563
3316
|
}),
|
|
2564
3317
|
{ checkoutMethod: "card" }
|
|
2565
3318
|
);
|
|
2566
3319
|
}
|
|
2567
|
-
const api = new
|
|
3320
|
+
const api = new import_js3.PaymentAPI(billingApiUrl);
|
|
2568
3321
|
const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
|
|
2569
3322
|
sessionId,
|
|
2570
3323
|
customerEmail,
|
|
@@ -2586,7 +3339,7 @@ async function processSavedPaymentWithIntent({
|
|
|
2586
3339
|
});
|
|
2587
3340
|
if (!intentClientSecret) {
|
|
2588
3341
|
throw Object.assign(
|
|
2589
|
-
new
|
|
3342
|
+
new import_shared7.FloPayError("No client secret in payment intent response.", "api_error"),
|
|
2590
3343
|
{ checkoutMethod: "card" }
|
|
2591
3344
|
);
|
|
2592
3345
|
}
|
|
@@ -2609,7 +3362,7 @@ async function processSavedPaymentWithIntent({
|
|
|
2609
3362
|
const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
|
|
2610
3363
|
if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
|
|
2611
3364
|
throw Object.assign(
|
|
2612
|
-
new
|
|
3365
|
+
new import_shared7.FloPayError(
|
|
2613
3366
|
`Unfortunately, your payment could not be processed. Please try again using a different payment method or contact your bank for assistance. If the issue persists, feel free to reach out to us for support.`,
|
|
2614
3367
|
"api_error",
|
|
2615
3368
|
{
|
|
@@ -2657,12 +3410,12 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2657
3410
|
}) {
|
|
2658
3411
|
const stripe = flopay?.getRawProvider();
|
|
2659
3412
|
if (!stripe) {
|
|
2660
|
-
throw new
|
|
3413
|
+
throw new import_shared7.FloPayError("Payment provider is not available.", "api_error");
|
|
2661
3414
|
}
|
|
2662
3415
|
if (redirectResult.type === "3ds_required") {
|
|
2663
3416
|
if (!attempt3DS || !redirectResult.threeDSecureToken) {
|
|
2664
3417
|
throw Object.assign(
|
|
2665
|
-
new
|
|
3418
|
+
new import_shared7.FloPayError(
|
|
2666
3419
|
"Your card requires authentication. Please enter your payment details below.",
|
|
2667
3420
|
"api_error",
|
|
2668
3421
|
{ code: "authentication_required" }
|
|
@@ -2678,7 +3431,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2678
3431
|
);
|
|
2679
3432
|
if (retrieveError) {
|
|
2680
3433
|
throw Object.assign(
|
|
2681
|
-
new
|
|
3434
|
+
new import_shared7.FloPayError(
|
|
2682
3435
|
retrieveError.message ?? "Failed to retrieve 3DS payment status.",
|
|
2683
3436
|
"api_error",
|
|
2684
3437
|
{ code: retrieveError.code }
|
|
@@ -2704,7 +3457,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2704
3457
|
);
|
|
2705
3458
|
if (confirmError) {
|
|
2706
3459
|
throw Object.assign(
|
|
2707
|
-
new
|
|
3460
|
+
new import_shared7.FloPayError(
|
|
2708
3461
|
confirmError.message ?? "3DS authentication failed.",
|
|
2709
3462
|
"api_error",
|
|
2710
3463
|
{ code: confirmError.code }
|
|
@@ -2719,7 +3472,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2719
3472
|
});
|
|
2720
3473
|
if (nextActionError) {
|
|
2721
3474
|
throw Object.assign(
|
|
2722
|
-
new
|
|
3475
|
+
new import_shared7.FloPayError(
|
|
2723
3476
|
nextActionError.message ?? "3DS authentication failed.",
|
|
2724
3477
|
"api_error",
|
|
2725
3478
|
{ code: nextActionError.code }
|
|
@@ -2759,7 +3512,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2759
3512
|
});
|
|
2760
3513
|
}
|
|
2761
3514
|
throw Object.assign(
|
|
2762
|
-
new
|
|
3515
|
+
new import_shared7.FloPayError("3DS authentication did not complete successfully.", "api_error"),
|
|
2763
3516
|
{ checkoutMethod: "card" }
|
|
2764
3517
|
);
|
|
2765
3518
|
}
|
|
@@ -2767,7 +3520,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2767
3520
|
const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
|
|
2768
3521
|
if (!paypalStripe) {
|
|
2769
3522
|
throw Object.assign(
|
|
2770
|
-
new
|
|
3523
|
+
new import_shared7.FloPayError("PayPal is not available.", "api_error"),
|
|
2771
3524
|
{ checkoutMethod: "paypal" }
|
|
2772
3525
|
);
|
|
2773
3526
|
}
|
|
@@ -2777,7 +3530,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2777
3530
|
});
|
|
2778
3531
|
if (error2) {
|
|
2779
3532
|
throw Object.assign(
|
|
2780
|
-
new
|
|
3533
|
+
new import_shared7.FloPayError(
|
|
2781
3534
|
error2.message ?? "PayPal authorization failed.",
|
|
2782
3535
|
"api_error",
|
|
2783
3536
|
{ code: error2.code }
|
|
@@ -2800,7 +3553,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2800
3553
|
});
|
|
2801
3554
|
if (error) {
|
|
2802
3555
|
throw Object.assign(
|
|
2803
|
-
new
|
|
3556
|
+
new import_shared7.FloPayError(
|
|
2804
3557
|
error.message ?? "PayPal authorization failed.",
|
|
2805
3558
|
"api_error",
|
|
2806
3559
|
{ code: error.code }
|
|
@@ -2813,33 +3566,48 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2813
3566
|
checkoutMethod: "paypal"
|
|
2814
3567
|
};
|
|
2815
3568
|
}
|
|
2816
|
-
throw new
|
|
3569
|
+
throw new import_shared7.FloPayError("Unsupported payment redirect state.", "api_error");
|
|
2817
3570
|
}
|
|
2818
3571
|
function normalizeSavedPaymentError(err) {
|
|
2819
|
-
if (err instanceof
|
|
3572
|
+
if (err instanceof import_shared7.FloPayError) {
|
|
3573
|
+
const friendly = applyFriendlyMessageOverride(err.message);
|
|
3574
|
+
if (friendly && friendly !== err.message) {
|
|
3575
|
+
return Object.assign(
|
|
3576
|
+
new import_shared7.FloPayError(friendly, err.type, {
|
|
3577
|
+
code: err.code,
|
|
3578
|
+
declineCode: err.declineCode,
|
|
3579
|
+
param: err.param,
|
|
3580
|
+
statusCode: err.statusCode
|
|
3581
|
+
}),
|
|
3582
|
+
{ checkoutMethod: err.checkoutMethod }
|
|
3583
|
+
);
|
|
3584
|
+
}
|
|
2820
3585
|
return err;
|
|
2821
3586
|
}
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
);
|
|
3587
|
+
const rawMessage = err instanceof Error ? err.message : "Payment failed. Please try again.";
|
|
3588
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
3589
|
+
return new import_shared7.FloPayError(message, "api_error");
|
|
2826
3590
|
}
|
|
2827
3591
|
function resolveSavedPaymentPublishableKeys(unified) {
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
if (
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
}
|
|
2834
|
-
if (!publishableKey) {
|
|
2835
|
-
throw new import_shared6.FloPayError(
|
|
2836
|
-
"No publishable key found in the checkout session. Ensure the session includes gatewayData.publishableKey.",
|
|
3592
|
+
const publishableKey = unified.data.stripe?.publishableKey;
|
|
3593
|
+
const hasDirectPaypal = Boolean(unified.data.paypal?.publishableKey);
|
|
3594
|
+
if (!publishableKey && !hasDirectPaypal) {
|
|
3595
|
+
throw new import_shared7.FloPayError(
|
|
3596
|
+
"Session advertises no supported gateways (expected `gateways.stripe` and/or `gateways.paypal`).",
|
|
2837
3597
|
"validation_error"
|
|
2838
3598
|
);
|
|
2839
3599
|
}
|
|
3600
|
+
if (!publishableKey) {
|
|
3601
|
+
return {};
|
|
3602
|
+
}
|
|
2840
3603
|
return {
|
|
2841
3604
|
publishableKey,
|
|
2842
|
-
|
|
3605
|
+
// Direct-PayPal sessions can still use Stripe's PayPal Element for the
|
|
3606
|
+
// saved-PM redirect leg. Prefer the dedicated Stripe-PayPal sub-account
|
|
3607
|
+
// publishable key when the backend advertises one; fall back to the
|
|
3608
|
+
// primary Stripe publishable key so the resume flow still has a Stripe
|
|
3609
|
+
// instance to drive Stripe's PayPal PI.
|
|
3610
|
+
paypalPublishableKey: unified.data.stripe?.paypalPublishableKey ?? publishableKey
|
|
2843
3611
|
};
|
|
2844
3612
|
}
|
|
2845
3613
|
async function loadSavedPaymentProviders({
|
|
@@ -2848,13 +3616,16 @@ async function loadSavedPaymentProviders({
|
|
|
2848
3616
|
billingApiUrl,
|
|
2849
3617
|
locale
|
|
2850
3618
|
}) {
|
|
3619
|
+
if (!publishableKey) {
|
|
3620
|
+
return { flopay: null, paypalFlopay: null };
|
|
3621
|
+
}
|
|
2851
3622
|
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2852
3623
|
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2853
|
-
(0,
|
|
3624
|
+
(0, import_js3.loadFloPay)(publishableKey, {
|
|
2854
3625
|
billingApiUrl,
|
|
2855
3626
|
locale
|
|
2856
3627
|
}),
|
|
2857
|
-
needsSeparatePaypal ? (0,
|
|
3628
|
+
needsSeparatePaypal ? (0, import_js3.loadFloPay)(paypalPublishableKey, {
|
|
2858
3629
|
billingApiUrl,
|
|
2859
3630
|
locale
|
|
2860
3631
|
}).catch((err) => {
|
|
@@ -2869,13 +3640,26 @@ async function loadSavedPaymentProviders({
|
|
|
2869
3640
|
}
|
|
2870
3641
|
|
|
2871
3642
|
// src/flopay-checkout.tsx
|
|
2872
|
-
var
|
|
3643
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2873
3644
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
2874
3645
|
var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
|
|
2875
3646
|
var sessionInflightMap = /* @__PURE__ */ new Map();
|
|
2876
3647
|
function sleep(ms) {
|
|
2877
3648
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2878
3649
|
}
|
|
3650
|
+
function resolveDirectPaypalConfig(unified) {
|
|
3651
|
+
const clientId = unified?.data.paypal?.publishableKey;
|
|
3652
|
+
if (!clientId) return void 0;
|
|
3653
|
+
return {
|
|
3654
|
+
clientId,
|
|
3655
|
+
environment: unified?.data.paypal?.environment
|
|
3656
|
+
};
|
|
3657
|
+
}
|
|
3658
|
+
function isPayPalOnlyUnified(unified) {
|
|
3659
|
+
if (!unified) return false;
|
|
3660
|
+
if (unified.data.stripe?.publishableKey) return false;
|
|
3661
|
+
return Boolean(resolveDirectPaypalConfig(unified)?.clientId);
|
|
3662
|
+
}
|
|
2879
3663
|
function canUseStorage() {
|
|
2880
3664
|
return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
|
|
2881
3665
|
}
|
|
@@ -2949,6 +3733,7 @@ function FloPayCheckout({
|
|
|
2949
3733
|
showPayPal = true,
|
|
2950
3734
|
showApplePay = true,
|
|
2951
3735
|
showGooglePay = true,
|
|
3736
|
+
debug = false,
|
|
2952
3737
|
layout,
|
|
2953
3738
|
buttonsTheme,
|
|
2954
3739
|
buttonsStyles,
|
|
@@ -2969,81 +3754,81 @@ function FloPayCheckout({
|
|
|
2969
3754
|
renderConfirmButton,
|
|
2970
3755
|
onSessionCompleted
|
|
2971
3756
|
}) {
|
|
2972
|
-
const resolvedBillingUrl = (0,
|
|
3757
|
+
const resolvedBillingUrl = (0, import_shared8.resolveBillingApiUrl)(billingApiUrl);
|
|
2973
3758
|
const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
|
|
2974
3759
|
const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
|
|
2975
|
-
const [unified, setUnified] = (0,
|
|
2976
|
-
const [flopay, setFloPay] = (0,
|
|
2977
|
-
const flopayRef = (0,
|
|
2978
|
-
const [paypalFlopay, setPaypalFloPay] = (0,
|
|
2979
|
-
const paypalFlopayRef = (0,
|
|
2980
|
-
const [session, setSession] = (0,
|
|
2981
|
-
const [resolvedSessionId, setResolvedSessionId] = (0,
|
|
3760
|
+
const [unified, setUnified] = (0, import_react9.useState)(null);
|
|
3761
|
+
const [flopay, setFloPay] = (0, import_react9.useState)(null);
|
|
3762
|
+
const flopayRef = (0, import_react9.useRef)(null);
|
|
3763
|
+
const [paypalFlopay, setPaypalFloPay] = (0, import_react9.useState)(null);
|
|
3764
|
+
const paypalFlopayRef = (0, import_react9.useRef)(null);
|
|
3765
|
+
const [session, setSession] = (0, import_react9.useState)(null);
|
|
3766
|
+
const [resolvedSessionId, setResolvedSessionId] = (0, import_react9.useState)(sessionIdProp ?? "");
|
|
2982
3767
|
const activeSessionId = sessionIdProp ?? resolvedSessionId;
|
|
2983
3768
|
const initSessionDependency = createSessionParams ? "" : activeSessionId;
|
|
2984
|
-
const [isLoading, setIsLoading] = (0,
|
|
2985
|
-
const [loadError, setLoadError] = (0,
|
|
2986
|
-
const [currentMode, setCurrentMode] = (0,
|
|
2987
|
-
const [confirmProcessing, setConfirmProcessing] = (0,
|
|
2988
|
-
const [modeError, setModeError] = (0,
|
|
2989
|
-
const [modeOverlayStatus, setModeOverlayStatus] = (0,
|
|
2990
|
-
const [modeOverlayError, setModeOverlayError] = (0,
|
|
2991
|
-
const [createSessionPatch, setCreateSessionPatch] = (0,
|
|
2992
|
-
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0,
|
|
2993
|
-
const [cardBootstrapPending, setCardBootstrapPending] = (0,
|
|
2994
|
-
const autoCheckoutAttempted = (0,
|
|
2995
|
-
const paypalResumeAttempted = (0,
|
|
2996
|
-
const savedPaymentKeysRef = (0,
|
|
2997
|
-
const onCompleteRef = (0,
|
|
3769
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(true);
|
|
3770
|
+
const [loadError, setLoadError] = (0, import_react9.useState)(null);
|
|
3771
|
+
const [currentMode, setCurrentMode] = (0, import_react9.useState)("full");
|
|
3772
|
+
const [confirmProcessing, setConfirmProcessing] = (0, import_react9.useState)(false);
|
|
3773
|
+
const [modeError, setModeError] = (0, import_react9.useState)(initialErrorMessage);
|
|
3774
|
+
const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react9.useState)(null);
|
|
3775
|
+
const [modeOverlayError, setModeOverlayError] = (0, import_react9.useState)(null);
|
|
3776
|
+
const [createSessionPatch, setCreateSessionPatch] = (0, import_react9.useState)(void 0);
|
|
3777
|
+
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react9.useState)("");
|
|
3778
|
+
const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react9.useState)(false);
|
|
3779
|
+
const autoCheckoutAttempted = (0, import_react9.useRef)(false);
|
|
3780
|
+
const paypalResumeAttempted = (0, import_react9.useRef)(false);
|
|
3781
|
+
const savedPaymentKeysRef = (0, import_react9.useRef)(null);
|
|
3782
|
+
const onCompleteRef = (0, import_react9.useRef)(onComplete);
|
|
2998
3783
|
onCompleteRef.current = onComplete;
|
|
2999
|
-
const onErrorRef = (0,
|
|
3784
|
+
const onErrorRef = (0, import_react9.useRef)(onError);
|
|
3000
3785
|
onErrorRef.current = onError;
|
|
3001
|
-
const onDeclineRef = (0,
|
|
3786
|
+
const onDeclineRef = (0, import_react9.useRef)(onDecline);
|
|
3002
3787
|
onDeclineRef.current = onDecline;
|
|
3003
|
-
const onSessionCompletedRef = (0,
|
|
3788
|
+
const onSessionCompletedRef = (0, import_react9.useRef)(onSessionCompleted);
|
|
3004
3789
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
3005
|
-
(0,
|
|
3790
|
+
(0, import_react9.useEffect)(() => {
|
|
3006
3791
|
console.info("[FloPay] Checkout initialized", {
|
|
3007
|
-
sdk_version:
|
|
3792
|
+
sdk_version: import_shared8.SDK_VERSION,
|
|
3008
3793
|
checkout_type: checkoutType,
|
|
3009
3794
|
checkout_layout: checkoutLayout,
|
|
3010
3795
|
billing_api_url: resolvedBillingUrl
|
|
3011
3796
|
});
|
|
3012
3797
|
}, [checkoutLayout, checkoutType, resolvedBillingUrl]);
|
|
3013
|
-
const baseCreateSessionHash = (0,
|
|
3798
|
+
const baseCreateSessionHash = (0, import_react9.useMemo)(
|
|
3014
3799
|
() => createSessionParams ? hashCreateParams(createSessionParams) : "",
|
|
3015
3800
|
[createSessionParams]
|
|
3016
3801
|
);
|
|
3017
|
-
const activeCreateSessionPatch = (0,
|
|
3802
|
+
const activeCreateSessionPatch = (0, import_react9.useMemo)(
|
|
3018
3803
|
() => createSessionPatchBaseHash === baseCreateSessionHash ? createSessionPatch : void 0,
|
|
3019
3804
|
[createSessionPatch, createSessionPatchBaseHash, baseCreateSessionHash]
|
|
3020
3805
|
);
|
|
3021
|
-
const effectiveCreateSessionBase = (0,
|
|
3806
|
+
const effectiveCreateSessionBase = (0, import_react9.useMemo)(
|
|
3022
3807
|
() => createSessionParams ? mergeInlineSessionPatch(createSessionParams, activeCreateSessionPatch) : void 0,
|
|
3023
3808
|
[createSessionParams, activeCreateSessionPatch]
|
|
3024
3809
|
);
|
|
3025
3810
|
const effectiveCreateSessionMode = checkoutModeProp ?? effectiveCreateSessionBase?.checkoutMode ?? "full";
|
|
3026
|
-
const effectiveCreateSession = (0,
|
|
3811
|
+
const effectiveCreateSession = (0, import_react9.useMemo)(
|
|
3027
3812
|
() => effectiveCreateSessionBase ? {
|
|
3028
3813
|
...effectiveCreateSessionBase,
|
|
3029
3814
|
checkoutMode: effectiveCreateSessionMode
|
|
3030
3815
|
} : void 0,
|
|
3031
3816
|
[effectiveCreateSessionBase, effectiveCreateSessionMode]
|
|
3032
3817
|
);
|
|
3033
|
-
(0,
|
|
3818
|
+
(0, import_react9.useEffect)(() => {
|
|
3034
3819
|
setCreateSessionPatch(void 0);
|
|
3035
3820
|
setCreateSessionPatchBaseHash(baseCreateSessionHash);
|
|
3036
3821
|
}, [baseCreateSessionHash]);
|
|
3037
|
-
(0,
|
|
3822
|
+
(0, import_react9.useEffect)(() => {
|
|
3038
3823
|
setModeError(initialErrorMessage);
|
|
3039
3824
|
}, [initialErrorMessage]);
|
|
3040
|
-
const emitDecline = (0,
|
|
3825
|
+
const emitDecline = (0, import_react9.useCallback)(
|
|
3041
3826
|
(method, input, overrides) => {
|
|
3042
3827
|
onDeclineRef.current?.(buildDeclineEvent(method, input, overrides));
|
|
3043
3828
|
},
|
|
3044
3829
|
[]
|
|
3045
3830
|
);
|
|
3046
|
-
const runSavedPaymentFlow = (0,
|
|
3831
|
+
const runSavedPaymentFlow = (0, import_react9.useCallback)(
|
|
3047
3832
|
async (sess, options) => {
|
|
3048
3833
|
setModeError(null);
|
|
3049
3834
|
setModeOverlayError(null);
|
|
@@ -3053,7 +3838,7 @@ function FloPayCheckout({
|
|
|
3053
3838
|
const redirectResult = getRedirectResultFromCheckoutProcessError(options?.initialAutoProcessingError);
|
|
3054
3839
|
let paymentResult;
|
|
3055
3840
|
if (redirectResult) {
|
|
3056
|
-
if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
|
|
3841
|
+
if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
|
|
3057
3842
|
persistPayPalResumeState({
|
|
3058
3843
|
sessionId: activeSessionId2,
|
|
3059
3844
|
publishableKey: savedPaymentKeysRef.current.publishableKey,
|
|
@@ -3072,12 +3857,12 @@ function FloPayCheckout({
|
|
|
3072
3857
|
clearPayPalResumeState();
|
|
3073
3858
|
}
|
|
3074
3859
|
} else if (options?.initialAutoProcessingPending) {
|
|
3075
|
-
const api = new
|
|
3860
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3076
3861
|
const completed = await api.waitForCheckoutSessionCompletion(options.initialAutoProcessingPending.sessionId, {
|
|
3077
3862
|
initialDelayMs: options.initialAutoProcessingPending.retryAfterMs
|
|
3078
3863
|
});
|
|
3079
3864
|
if (completed.data.session?.status !== "complete") {
|
|
3080
|
-
throw new
|
|
3865
|
+
throw new import_shared8.FloPayError("Automatic payment failed. Please try again.", "api_error", {
|
|
3081
3866
|
code: completed.data.session?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
3082
3867
|
});
|
|
3083
3868
|
}
|
|
@@ -3105,7 +3890,7 @@ function FloPayCheckout({
|
|
|
3105
3890
|
if (result.type === "success") {
|
|
3106
3891
|
paymentResult = result.result;
|
|
3107
3892
|
} else {
|
|
3108
|
-
if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
|
|
3893
|
+
if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
|
|
3109
3894
|
persistPayPalResumeState({
|
|
3110
3895
|
sessionId: activeSessionId2,
|
|
3111
3896
|
publishableKey: savedPaymentKeysRef.current.publishableKey,
|
|
@@ -3161,7 +3946,7 @@ function FloPayCheckout({
|
|
|
3161
3946
|
resolvedBillingUrl
|
|
3162
3947
|
]
|
|
3163
3948
|
);
|
|
3164
|
-
(0,
|
|
3949
|
+
(0, import_react9.useEffect)(() => {
|
|
3165
3950
|
if (typeof window === "undefined" || paypalResumeAttempted.current) {
|
|
3166
3951
|
return;
|
|
3167
3952
|
}
|
|
@@ -3183,7 +3968,7 @@ function FloPayCheckout({
|
|
|
3183
3968
|
try {
|
|
3184
3969
|
if (params.get("redirect_status") === "failed") {
|
|
3185
3970
|
throw Object.assign(
|
|
3186
|
-
new
|
|
3971
|
+
new import_shared8.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
|
|
3187
3972
|
{ checkoutMethod: "paypal" }
|
|
3188
3973
|
);
|
|
3189
3974
|
}
|
|
@@ -3196,17 +3981,17 @@ function FloPayCheckout({
|
|
|
3196
3981
|
billingApiUrl: resolvedBillingUrl,
|
|
3197
3982
|
locale
|
|
3198
3983
|
});
|
|
3199
|
-
const paypalStripe = (resumePaypalFlopay ?? resumeFlopay)
|
|
3984
|
+
const paypalStripe = (resumePaypalFlopay ?? resumeFlopay)?.getRawProvider();
|
|
3200
3985
|
if (!paypalStripe) {
|
|
3201
3986
|
throw Object.assign(
|
|
3202
|
-
new
|
|
3987
|
+
new import_shared8.FloPayError("PayPal is not available.", "api_error"),
|
|
3203
3988
|
{ checkoutMethod: "paypal" }
|
|
3204
3989
|
);
|
|
3205
3990
|
}
|
|
3206
3991
|
const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
|
|
3207
3992
|
if (error) {
|
|
3208
3993
|
throw Object.assign(
|
|
3209
|
-
new
|
|
3994
|
+
new import_shared8.FloPayError(
|
|
3210
3995
|
error.message ?? "Failed to retrieve PayPal payment status.",
|
|
3211
3996
|
"api_error",
|
|
3212
3997
|
{ code: error.code }
|
|
@@ -3217,14 +4002,14 @@ function FloPayCheckout({
|
|
|
3217
4002
|
const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
|
|
3218
4003
|
if (!paymentIntent || resultStatus === "failed") {
|
|
3219
4004
|
throw Object.assign(
|
|
3220
|
-
new
|
|
4005
|
+
new import_shared8.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
|
|
3221
4006
|
{ checkoutMethod: "paypal" }
|
|
3222
4007
|
);
|
|
3223
4008
|
}
|
|
3224
4009
|
const paymentMethodId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
3225
4010
|
let finalResultStatus = resultStatus;
|
|
3226
4011
|
if (resumeState.sessionId) {
|
|
3227
|
-
const resumeApi = new
|
|
4012
|
+
const resumeApi = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3228
4013
|
const resumeSessionResult = await resumeApi.getUnifiedCheckoutSession(resumeState.sessionId);
|
|
3229
4014
|
const resumeSession = resumeSessionResult.data.session;
|
|
3230
4015
|
if (resumeSession && resumeSession.status !== "complete") {
|
|
@@ -3241,7 +4026,7 @@ function FloPayCheckout({
|
|
|
3241
4026
|
});
|
|
3242
4027
|
if (processResult.type !== "success") {
|
|
3243
4028
|
throw Object.assign(
|
|
3244
|
-
new
|
|
4029
|
+
new import_shared8.FloPayError("Failed to finalize PayPal payment.", "api_error"),
|
|
3245
4030
|
{ checkoutMethod: "paypal" }
|
|
3246
4031
|
);
|
|
3247
4032
|
}
|
|
@@ -3278,7 +4063,7 @@ function FloPayCheckout({
|
|
|
3278
4063
|
}
|
|
3279
4064
|
})();
|
|
3280
4065
|
}, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
|
|
3281
|
-
const initializedHashRef = (0,
|
|
4066
|
+
const initializedHashRef = (0, import_react9.useRef)(null);
|
|
3282
4067
|
function hashCreateParams(params) {
|
|
3283
4068
|
const key = JSON.stringify({
|
|
3284
4069
|
c: params?.clientId,
|
|
@@ -3303,23 +4088,23 @@ function FloPayCheckout({
|
|
|
3303
4088
|
}
|
|
3304
4089
|
return `flopay_session_${Math.abs(h).toString(36)}`;
|
|
3305
4090
|
}
|
|
3306
|
-
const createSessionHash = (0,
|
|
4091
|
+
const createSessionHash = (0, import_react9.useMemo)(
|
|
3307
4092
|
() => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
|
|
3308
4093
|
[effectiveCreateSession]
|
|
3309
4094
|
);
|
|
3310
|
-
const createSessionParamsRef = (0,
|
|
4095
|
+
const createSessionParamsRef = (0, import_react9.useRef)(effectiveCreateSession);
|
|
3311
4096
|
createSessionParamsRef.current = effectiveCreateSession;
|
|
3312
|
-
(0,
|
|
4097
|
+
(0, import_react9.useEffect)(() => {
|
|
3313
4098
|
setResolvedSessionId(sessionIdProp ?? "");
|
|
3314
4099
|
}, [sessionIdProp]);
|
|
3315
|
-
(0,
|
|
4100
|
+
(0, import_react9.useEffect)(() => {
|
|
3316
4101
|
autoCheckoutAttempted.current = false;
|
|
3317
4102
|
setModeError(initialErrorMessage);
|
|
3318
4103
|
setModeOverlayError(null);
|
|
3319
4104
|
setModeOverlayStatus(null);
|
|
3320
4105
|
}, [createSessionHash, initialErrorMessage, sessionIdProp]);
|
|
3321
4106
|
async function resolveInlineSession(params, cacheKey) {
|
|
3322
|
-
const api = new
|
|
4107
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3323
4108
|
let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
|
|
3324
4109
|
let realResult = null;
|
|
3325
4110
|
if (sid) {
|
|
@@ -3355,11 +4140,11 @@ function FloPayCheckout({
|
|
|
3355
4140
|
}
|
|
3356
4141
|
return { sid: sid ?? "", result: realResult };
|
|
3357
4142
|
}
|
|
3358
|
-
const bootstrapInlineSession = (0,
|
|
4143
|
+
const bootstrapInlineSession = (0, import_react9.useCallback)(
|
|
3359
4144
|
async (patch) => {
|
|
3360
4145
|
const baseParams = createSessionParamsRef.current;
|
|
3361
4146
|
if (!baseParams) {
|
|
3362
|
-
throw new
|
|
4147
|
+
throw new import_shared8.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
|
|
3363
4148
|
}
|
|
3364
4149
|
const mergedParams = mergeInlineSessionPatch(baseParams, patch);
|
|
3365
4150
|
const cacheKey = hashCreateParams(mergedParams);
|
|
@@ -3416,7 +4201,7 @@ function FloPayCheckout({
|
|
|
3416
4201
|
},
|
|
3417
4202
|
[locale, resolvedBillingUrl]
|
|
3418
4203
|
);
|
|
3419
|
-
const handleInlineSessionPatch = (0,
|
|
4204
|
+
const handleInlineSessionPatch = (0, import_react9.useCallback)(async (patch) => {
|
|
3420
4205
|
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
|
|
3421
4206
|
return {
|
|
3422
4207
|
sessionId: resolvedSessionId,
|
|
@@ -3439,7 +4224,7 @@ function FloPayCheckout({
|
|
|
3439
4224
|
resolvedSessionId,
|
|
3440
4225
|
session
|
|
3441
4226
|
]);
|
|
3442
|
-
(0,
|
|
4227
|
+
(0, import_react9.useEffect)(() => {
|
|
3443
4228
|
let cancelled = false;
|
|
3444
4229
|
setLoadError(null);
|
|
3445
4230
|
if (createSessionHash) {
|
|
@@ -3464,7 +4249,8 @@ function FloPayCheckout({
|
|
|
3464
4249
|
const resolved = await bootstrapInlineSession();
|
|
3465
4250
|
const resolvedSession = resolved.result.data.session ?? null;
|
|
3466
4251
|
savedPaymentKeysRef.current = resolveSavedPaymentPublishableKeys(resolved.result);
|
|
3467
|
-
|
|
4252
|
+
const resolvedPaypalOnly = isPayPalOnlyUnified(resolved.result);
|
|
4253
|
+
if (!cancelled && shouldAutoProcessInlineSession && resolvedSession && !resolvedPaypalOnly) {
|
|
3468
4254
|
autoCheckoutAttempted.current = true;
|
|
3469
4255
|
await runSavedPaymentFlow(resolvedSession, {
|
|
3470
4256
|
attempt3DS: true,
|
|
@@ -3478,12 +4264,15 @@ function FloPayCheckout({
|
|
|
3478
4264
|
return;
|
|
3479
4265
|
}
|
|
3480
4266
|
if (!cancelled && shouldAutoProcessInlineSession) {
|
|
4267
|
+
if (resolvedPaypalOnly) {
|
|
4268
|
+
autoCheckoutAttempted.current = true;
|
|
4269
|
+
}
|
|
3481
4270
|
setModeOverlayStatus(null);
|
|
3482
4271
|
setModeOverlayError(null);
|
|
3483
4272
|
}
|
|
3484
4273
|
} catch (err) {
|
|
3485
4274
|
if (cancelled) return;
|
|
3486
|
-
const errorCode = err instanceof
|
|
4275
|
+
const errorCode = err instanceof import_shared8.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
3487
4276
|
if (shouldAutoProcessInlineSession && errorCode === "session_auto_completed") {
|
|
3488
4277
|
autoCheckoutAttempted.current = true;
|
|
3489
4278
|
setModeOverlayStatus("success");
|
|
@@ -3499,7 +4288,7 @@ function FloPayCheckout({
|
|
|
3499
4288
|
setModeOverlayStatus(null);
|
|
3500
4289
|
setModeOverlayError(null);
|
|
3501
4290
|
}
|
|
3502
|
-
const floPayErr = err instanceof
|
|
4291
|
+
const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
|
|
3503
4292
|
setLoadError(floPayErr);
|
|
3504
4293
|
}
|
|
3505
4294
|
})();
|
|
@@ -3510,14 +4299,14 @@ function FloPayCheckout({
|
|
|
3510
4299
|
setIsLoading(true);
|
|
3511
4300
|
async function init() {
|
|
3512
4301
|
try {
|
|
3513
|
-
const api = new
|
|
4302
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3514
4303
|
const result = await api.getUnifiedCheckoutSession(activeSessionId);
|
|
3515
4304
|
if (cancelled) return;
|
|
3516
4305
|
setUnified(result);
|
|
3517
4306
|
const sess = result.data.session ?? null;
|
|
3518
4307
|
setSession(sess);
|
|
3519
4308
|
if (!sess) {
|
|
3520
|
-
throw new
|
|
4309
|
+
throw new import_shared8.FloPayError("No session data returned", "api_error");
|
|
3521
4310
|
}
|
|
3522
4311
|
if (sess.status === "complete") {
|
|
3523
4312
|
setIsLoading(false);
|
|
@@ -3525,14 +4314,15 @@ function FloPayCheckout({
|
|
|
3525
4314
|
return;
|
|
3526
4315
|
}
|
|
3527
4316
|
if (sess.status === "expired") {
|
|
3528
|
-
throw new
|
|
4317
|
+
throw new import_shared8.FloPayError("Checkout session has expired.", "api_error", {
|
|
3529
4318
|
code: "checkout_session_expired"
|
|
3530
4319
|
});
|
|
3531
4320
|
}
|
|
3532
4321
|
const effectiveMode = checkoutModeProp ?? sess.checkoutMode ?? "full";
|
|
3533
4322
|
setCurrentMode(effectiveMode);
|
|
3534
4323
|
const hasPayPalRedirectParams = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent");
|
|
3535
|
-
|
|
4324
|
+
const paypalOnly = isPayPalOnlyUnified(result);
|
|
4325
|
+
if (effectiveMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams && !paypalOnly) {
|
|
3536
4326
|
autoCheckoutAttempted.current = true;
|
|
3537
4327
|
const stripeInitPromise = initStripe(result);
|
|
3538
4328
|
try {
|
|
@@ -3559,7 +4349,7 @@ function FloPayCheckout({
|
|
|
3559
4349
|
if (!cancelled) setIsLoading(false);
|
|
3560
4350
|
} catch (err) {
|
|
3561
4351
|
if (cancelled) return;
|
|
3562
|
-
const floPayErr = err instanceof
|
|
4352
|
+
const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
|
|
3563
4353
|
setLoadError(floPayErr);
|
|
3564
4354
|
setIsLoading(false);
|
|
3565
4355
|
}
|
|
@@ -3599,7 +4389,7 @@ function FloPayCheckout({
|
|
|
3599
4389
|
initSessionDependency,
|
|
3600
4390
|
runSavedPaymentFlow
|
|
3601
4391
|
]);
|
|
3602
|
-
const handleConfirmCheckout = (0,
|
|
4392
|
+
const handleConfirmCheckout = (0, import_react9.useCallback)(async () => {
|
|
3603
4393
|
if (confirmProcessing || !session) return;
|
|
3604
4394
|
setConfirmProcessing(true);
|
|
3605
4395
|
setModeError(null);
|
|
@@ -3612,17 +4402,19 @@ function FloPayCheckout({
|
|
|
3612
4402
|
setConfirmProcessing(false);
|
|
3613
4403
|
}
|
|
3614
4404
|
}, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
|
|
3615
|
-
const
|
|
3616
|
-
|
|
4405
|
+
const directPaypalConfig = resolveDirectPaypalConfig(unified);
|
|
4406
|
+
const isPaypalOnlySession = isPayPalOnlyUnified(unified);
|
|
4407
|
+
const providerOptions = (0, import_react9.useMemo)(() => {
|
|
4408
|
+
if (!unified || !session || !unified.data.stripe?.publishableKey) return void 0;
|
|
3617
4409
|
const opts = {
|
|
3618
4410
|
appearance,
|
|
3619
4411
|
paymentMethodCreation: "manual",
|
|
3620
4412
|
billingApiUrl: resolvedBillingUrl
|
|
3621
4413
|
};
|
|
3622
|
-
if (unified.
|
|
4414
|
+
if (unified.data.stripe?.clientSecret) {
|
|
3623
4415
|
opts.clientSecret = unified.data.stripe.clientSecret;
|
|
3624
4416
|
} else {
|
|
3625
|
-
const displayTotal = (0,
|
|
4417
|
+
const displayTotal = (0, import_shared8.buildCheckoutDisplayData)(session).total;
|
|
3626
4418
|
opts.amount = Math.round(displayTotal * 100) || session.amount;
|
|
3627
4419
|
opts.currency = session.currency?.toLowerCase();
|
|
3628
4420
|
}
|
|
@@ -3631,7 +4423,7 @@ function FloPayCheckout({
|
|
|
3631
4423
|
const shouldHandleInlineSessionPatch = Boolean(
|
|
3632
4424
|
createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && effectiveCreateSessionMode === "full"
|
|
3633
4425
|
);
|
|
3634
|
-
const checkoutValue = (0,
|
|
4426
|
+
const checkoutValue = (0, import_react9.useMemo)(
|
|
3635
4427
|
() => ({
|
|
3636
4428
|
session,
|
|
3637
4429
|
loading: isLoading,
|
|
@@ -3652,8 +4444,8 @@ function FloPayCheckout({
|
|
|
3652
4444
|
cardBootstrapPending
|
|
3653
4445
|
]
|
|
3654
4446
|
);
|
|
3655
|
-
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
|
|
3656
|
-
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0,
|
|
4447
|
+
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
|
|
4448
|
+
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3657
4449
|
ProcessingOverlay,
|
|
3658
4450
|
{
|
|
3659
4451
|
status: modeOverlayStatus,
|
|
@@ -3662,31 +4454,31 @@ function FloPayCheckout({
|
|
|
3662
4454
|
) : null;
|
|
3663
4455
|
if (isLoading) {
|
|
3664
4456
|
if (loadingNode) {
|
|
3665
|
-
return /* @__PURE__ */ (0,
|
|
4457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3666
4458
|
loadingNode,
|
|
3667
4459
|
modeOverlay
|
|
3668
4460
|
] });
|
|
3669
4461
|
}
|
|
3670
4462
|
if (layout === "buttons") {
|
|
3671
|
-
const skeletonBar = (h) => /* @__PURE__ */ (0,
|
|
4463
|
+
const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3672
4464
|
height: h,
|
|
3673
4465
|
borderRadius: 8,
|
|
3674
4466
|
background: "#e5e7eb",
|
|
3675
4467
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
3676
4468
|
} });
|
|
3677
|
-
return /* @__PURE__ */ (0,
|
|
3678
|
-
/* @__PURE__ */ (0,
|
|
4469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4470
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
3679
4471
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3680
4472
|
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3681
4473
|
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3682
|
-
/* @__PURE__ */ (0,
|
|
4474
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
3683
4475
|
] }),
|
|
3684
4476
|
modeOverlay
|
|
3685
4477
|
] });
|
|
3686
4478
|
}
|
|
3687
|
-
return /* @__PURE__ */ (0,
|
|
3688
|
-
/* @__PURE__ */ (0,
|
|
3689
|
-
/* @__PURE__ */ (0,
|
|
4479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4480
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
|
|
4481
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3690
4482
|
width: 24,
|
|
3691
4483
|
height: 24,
|
|
3692
4484
|
border: "2px solid #e5e7eb",
|
|
@@ -3694,16 +4486,16 @@ function FloPayCheckout({
|
|
|
3694
4486
|
borderRadius: "50%",
|
|
3695
4487
|
animation: "spin 0.6s linear infinite"
|
|
3696
4488
|
} }),
|
|
3697
|
-
/* @__PURE__ */ (0,
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
3698
4490
|
] }),
|
|
3699
4491
|
modeOverlay
|
|
3700
4492
|
] });
|
|
3701
4493
|
}
|
|
3702
4494
|
if (loadError) {
|
|
3703
4495
|
if (errorNode) {
|
|
3704
|
-
return /* @__PURE__ */ (0,
|
|
4496
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
|
|
3705
4497
|
}
|
|
3706
|
-
return /* @__PURE__ */ (0,
|
|
4498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3707
4499
|
"div",
|
|
3708
4500
|
{
|
|
3709
4501
|
style: {
|
|
@@ -3717,8 +4509,8 @@ function FloPayCheckout({
|
|
|
3717
4509
|
) });
|
|
3718
4510
|
}
|
|
3719
4511
|
if (shouldShowInterimButtons) {
|
|
3720
|
-
return /* @__PURE__ */ (0,
|
|
3721
|
-
/* @__PURE__ */ (0,
|
|
4512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4513
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3722
4514
|
InterimButtonsView,
|
|
3723
4515
|
{
|
|
3724
4516
|
onButtonClick,
|
|
@@ -3735,13 +4527,55 @@ function FloPayCheckout({
|
|
|
3735
4527
|
modeOverlay
|
|
3736
4528
|
] });
|
|
3737
4529
|
}
|
|
4530
|
+
if (isPaypalOnlySession && session && directPaypalConfig) {
|
|
4531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4532
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4533
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4534
|
+
"div",
|
|
4535
|
+
{
|
|
4536
|
+
role: "alert",
|
|
4537
|
+
"data-testid": "flopay-error",
|
|
4538
|
+
style: {
|
|
4539
|
+
padding: "0.625rem 0.875rem",
|
|
4540
|
+
background: "#FEF2F2",
|
|
4541
|
+
border: "1px solid #FECACA",
|
|
4542
|
+
borderRadius: "8px",
|
|
4543
|
+
color: "#991B1B",
|
|
4544
|
+
fontSize: "0.85rem",
|
|
4545
|
+
fontWeight: 600
|
|
4546
|
+
},
|
|
4547
|
+
children: modeError
|
|
4548
|
+
}
|
|
4549
|
+
),
|
|
4550
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4551
|
+
DirectPayPalButton,
|
|
4552
|
+
{
|
|
4553
|
+
sessionId: activeSessionId,
|
|
4554
|
+
billingApiUrl: resolvedBillingUrl,
|
|
4555
|
+
email: session.customer?.email,
|
|
4556
|
+
clientId: directPaypalConfig.clientId,
|
|
4557
|
+
environment: directPaypalConfig.environment,
|
|
4558
|
+
currency: (session.currency ?? "usd").toUpperCase(),
|
|
4559
|
+
isSubscription: session.mode === "subscription",
|
|
4560
|
+
onComplete,
|
|
4561
|
+
onErrorChange: setModeError,
|
|
4562
|
+
onDecline,
|
|
4563
|
+
onButtonClick,
|
|
4564
|
+
session,
|
|
4565
|
+
debug
|
|
4566
|
+
}
|
|
4567
|
+
)
|
|
4568
|
+
] }) }),
|
|
4569
|
+
modeOverlay
|
|
4570
|
+
] });
|
|
4571
|
+
}
|
|
3738
4572
|
if (!flopay || !providerOptions) {
|
|
3739
|
-
return /* @__PURE__ */ (0,
|
|
4573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: modeOverlay });
|
|
3740
4574
|
}
|
|
3741
4575
|
if (currentMode === "confirm") {
|
|
3742
|
-
return /* @__PURE__ */ (0,
|
|
3743
|
-
/* @__PURE__ */ (0,
|
|
3744
|
-
modeError && /* @__PURE__ */ (0,
|
|
4576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4577
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className, children: [
|
|
4578
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3745
4579
|
"div",
|
|
3746
4580
|
{
|
|
3747
4581
|
style: {
|
|
@@ -3756,7 +4590,7 @@ function FloPayCheckout({
|
|
|
3756
4590
|
renderConfirmButton ? renderConfirmButton({
|
|
3757
4591
|
onConfirm: handleConfirmCheckout,
|
|
3758
4592
|
isProcessing: confirmProcessing
|
|
3759
|
-
}) : /* @__PURE__ */ (0,
|
|
4593
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3760
4594
|
"button",
|
|
3761
4595
|
{
|
|
3762
4596
|
type: "button",
|
|
@@ -3781,9 +4615,9 @@ function FloPayCheckout({
|
|
|
3781
4615
|
modeOverlay
|
|
3782
4616
|
] });
|
|
3783
4617
|
}
|
|
3784
|
-
return /* @__PURE__ */ (0,
|
|
3785
|
-
/* @__PURE__ */ (0,
|
|
3786
|
-
modeError && /* @__PURE__ */ (0,
|
|
4618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4619
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4620
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3787
4621
|
"div",
|
|
3788
4622
|
{
|
|
3789
4623
|
style: {
|
|
@@ -3798,7 +4632,7 @@ function FloPayCheckout({
|
|
|
3798
4632
|
children: modeError
|
|
3799
4633
|
}
|
|
3800
4634
|
),
|
|
3801
|
-
/* @__PURE__ */ (0,
|
|
4635
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3802
4636
|
SessionInjector,
|
|
3803
4637
|
{
|
|
3804
4638
|
sessionId: activeSessionId,
|
|
@@ -3807,7 +4641,7 @@ function FloPayCheckout({
|
|
|
3807
4641
|
children
|
|
3808
4642
|
}
|
|
3809
4643
|
)
|
|
3810
|
-
] }) : /* @__PURE__ */ (0,
|
|
4644
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3811
4645
|
SplitCardForm,
|
|
3812
4646
|
{
|
|
3813
4647
|
sessionId: activeSessionId,
|
|
@@ -3815,7 +4649,7 @@ function FloPayCheckout({
|
|
|
3815
4649
|
userId: session?.customer?.id,
|
|
3816
4650
|
firstName: session?.customer?.firstName,
|
|
3817
4651
|
lastName: session?.customer?.lastName,
|
|
3818
|
-
totalAmount: session ? Math.round((0,
|
|
4652
|
+
totalAmount: session ? Math.round((0, import_shared8.buildCheckoutDisplayData)(session).total * 100) : 0,
|
|
3819
4653
|
currency: session?.currency?.toLowerCase() ?? "usd",
|
|
3820
4654
|
onComplete,
|
|
3821
4655
|
onError,
|
|
@@ -3846,7 +4680,11 @@ function FloPayCheckout({
|
|
|
3846
4680
|
checkoutType: createSessionParams ? "embedded_checkout" : "standard_checkout",
|
|
3847
4681
|
checkoutLayout: children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout",
|
|
3848
4682
|
submitLabel,
|
|
3849
|
-
className
|
|
4683
|
+
className,
|
|
4684
|
+
directPaypal: resolveDirectPaypalConfig(unified),
|
|
4685
|
+
isSubscription: session?.mode === "subscription",
|
|
4686
|
+
session,
|
|
4687
|
+
debug
|
|
3850
4688
|
}
|
|
3851
4689
|
) }) }),
|
|
3852
4690
|
modeOverlay
|
|
@@ -3858,8 +4696,8 @@ function SessionInjector({
|
|
|
3858
4696
|
session,
|
|
3859
4697
|
children
|
|
3860
4698
|
}) {
|
|
3861
|
-
return /* @__PURE__ */ (0,
|
|
3862
|
-
if (!
|
|
4699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: import_react9.default.Children.map(children, (child) => {
|
|
4700
|
+
if (!import_react9.default.isValidElement(child)) return child;
|
|
3863
4701
|
const existing = child.props;
|
|
3864
4702
|
const injected = {};
|
|
3865
4703
|
if (!existing.sessionId) injected.sessionId = sessionId;
|
|
@@ -3873,7 +4711,7 @@ function SessionInjector({
|
|
|
3873
4711
|
injected.lastName = session.customer.lastName;
|
|
3874
4712
|
}
|
|
3875
4713
|
if (Object.keys(injected).length === 0) return child;
|
|
3876
|
-
return
|
|
4714
|
+
return import_react9.default.cloneElement(child, injected);
|
|
3877
4715
|
}) });
|
|
3878
4716
|
}
|
|
3879
4717
|
function InterimButtonsView({
|
|
@@ -3891,15 +4729,15 @@ function InterimButtonsView({
|
|
|
3891
4729
|
cardBackButtonContent,
|
|
3892
4730
|
cardTitleContent
|
|
3893
4731
|
}) {
|
|
3894
|
-
const [showCardForm, setShowCardForm] = (0,
|
|
4732
|
+
const [showCardForm, setShowCardForm] = (0, import_react9.useState)(false);
|
|
3895
4733
|
const isCardOpenControlled = typeof cardOpen === "boolean";
|
|
3896
|
-
(0,
|
|
4734
|
+
(0, import_react9.useEffect)(() => {
|
|
3897
4735
|
if (isCardOpenControlled) {
|
|
3898
4736
|
setShowCardForm(cardOpen);
|
|
3899
4737
|
}
|
|
3900
4738
|
}, [cardOpen, isCardOpenControlled]);
|
|
3901
|
-
const bStyles = (0,
|
|
3902
|
-
const base = (0,
|
|
4739
|
+
const bStyles = (0, import_react9.useMemo)(() => {
|
|
4740
|
+
const base = (0, import_shared8.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
3903
4741
|
if (!stylesOverride) return base;
|
|
3904
4742
|
return {
|
|
3905
4743
|
...base,
|
|
@@ -3912,7 +4750,7 @@ function InterimButtonsView({
|
|
|
3912
4750
|
title: { ...base.title, ...stylesOverride.title }
|
|
3913
4751
|
};
|
|
3914
4752
|
}, [buttonsTheme, stylesOverride]);
|
|
3915
|
-
const skeleton = (h) => /* @__PURE__ */ (0,
|
|
4753
|
+
const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3916
4754
|
height: h,
|
|
3917
4755
|
borderRadius: 8,
|
|
3918
4756
|
background: "#e5e7eb",
|
|
@@ -3924,15 +4762,15 @@ function InterimButtonsView({
|
|
|
3924
4762
|
const inputBg = bStyles.cardInputBackground ?? "white";
|
|
3925
4763
|
const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
|
|
3926
4764
|
const hideTitle = isEmptySlotContent(cardTitleContent);
|
|
3927
|
-
return /* @__PURE__ */ (0,
|
|
4765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
|
|
3928
4766
|
backgroundColor: bStyles.cardFormContainer?.backgroundColor ?? "white",
|
|
3929
4767
|
borderRadius: "8px",
|
|
3930
4768
|
animation: "flopay-interim-expand 0.35s cubic-bezier(0.4, 0, 0.2, 1) both",
|
|
3931
4769
|
overflow: "hidden",
|
|
3932
4770
|
...bStyles.cardFormContainer
|
|
3933
4771
|
}, children: [
|
|
3934
|
-
/* @__PURE__ */ (0,
|
|
3935
|
-
/* @__PURE__ */ (0,
|
|
4772
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
|
|
4773
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3936
4774
|
"button",
|
|
3937
4775
|
{
|
|
3938
4776
|
type: "button",
|
|
@@ -3959,7 +4797,7 @@ function InterimButtonsView({
|
|
|
3959
4797
|
...bStyles.backButton
|
|
3960
4798
|
},
|
|
3961
4799
|
children: [
|
|
3962
|
-
/* @__PURE__ */ (0,
|
|
4800
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: {
|
|
3963
4801
|
display: "inline-flex",
|
|
3964
4802
|
alignItems: "center",
|
|
3965
4803
|
justifyContent: "center",
|
|
@@ -3968,12 +4806,12 @@ function InterimButtonsView({
|
|
|
3968
4806
|
borderRadius: "50%",
|
|
3969
4807
|
backgroundColor: "#f3f4f6",
|
|
3970
4808
|
...bStyles.backButtonIcon
|
|
3971
|
-
}, children: /* @__PURE__ */ (0,
|
|
3972
|
-
/* @__PURE__ */ (0,
|
|
4809
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
4810
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3973
4811
|
]
|
|
3974
4812
|
}
|
|
3975
4813
|
),
|
|
3976
|
-
hideTitle ? /* @__PURE__ */ (0,
|
|
4814
|
+
hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3977
4815
|
flex: 1,
|
|
3978
4816
|
textAlign: "center",
|
|
3979
4817
|
fontWeight: 600,
|
|
@@ -3981,15 +4819,15 @@ function InterimButtonsView({
|
|
|
3981
4819
|
color: "#262833",
|
|
3982
4820
|
paddingRight: 80,
|
|
3983
4821
|
...bStyles.title
|
|
3984
|
-
}, children: /* @__PURE__ */ (0,
|
|
4822
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TitleContentSlot, { content: cardTitleContent }) })
|
|
3985
4823
|
] }),
|
|
3986
|
-
/* @__PURE__ */ (0,
|
|
3987
|
-
/* @__PURE__ */ (0,
|
|
3988
|
-
/* @__PURE__ */ (0,
|
|
3989
|
-
/* @__PURE__ */ (0,
|
|
4824
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4825
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex" }, children: [
|
|
4826
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4827
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderBottomRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
3990
4828
|
] }),
|
|
3991
|
-
/* @__PURE__ */ (0,
|
|
3992
|
-
/* @__PURE__ */ (0,
|
|
4829
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4830
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3993
4831
|
height: 50,
|
|
3994
4832
|
borderRadius: 8,
|
|
3995
4833
|
marginTop: 16,
|
|
@@ -3998,7 +4836,7 @@ function InterimButtonsView({
|
|
|
3998
4836
|
...bStyles.submitButton,
|
|
3999
4837
|
opacity: 0.5
|
|
4000
4838
|
} }),
|
|
4001
|
-
/* @__PURE__ */ (0,
|
|
4839
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
4002
4840
|
@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
4003
4841
|
@keyframes flopay-interim-expand {
|
|
4004
4842
|
0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
|
|
@@ -4008,10 +4846,10 @@ function InterimButtonsView({
|
|
|
4008
4846
|
` })
|
|
4009
4847
|
] });
|
|
4010
4848
|
}
|
|
4011
|
-
return /* @__PURE__ */ (0,
|
|
4849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4012
4850
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4013
4851
|
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4014
|
-
/* @__PURE__ */ (0,
|
|
4852
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4015
4853
|
"button",
|
|
4016
4854
|
{
|
|
4017
4855
|
type: "button",
|
|
@@ -4051,10 +4889,10 @@ function InterimButtonsView({
|
|
|
4051
4889
|
onMouseUp: (e) => {
|
|
4052
4890
|
e.currentTarget.style.transform = "scale(1)";
|
|
4053
4891
|
},
|
|
4054
|
-
children: /* @__PURE__ */ (0,
|
|
4892
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardButtonContentSlot, { content: cardButtonContent })
|
|
4055
4893
|
}
|
|
4056
4894
|
),
|
|
4057
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4895
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
|
|
4058
4896
|
margin: "0.25rem 0",
|
|
4059
4897
|
padding: "0.625rem 0.875rem",
|
|
4060
4898
|
background: "#FEF2F2",
|
|
@@ -4068,22 +4906,22 @@ function InterimButtonsView({
|
|
|
4068
4906
|
gap: "0.5rem",
|
|
4069
4907
|
...bStyles.errorBanner
|
|
4070
4908
|
}, children: [
|
|
4071
|
-
/* @__PURE__ */ (0,
|
|
4909
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.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" }) }),
|
|
4072
4910
|
errorMessage
|
|
4073
4911
|
] }),
|
|
4074
|
-
/* @__PURE__ */ (0,
|
|
4912
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
4075
4913
|
] });
|
|
4076
4914
|
}
|
|
4077
4915
|
|
|
4078
4916
|
// src/checkout-form.tsx
|
|
4079
|
-
var
|
|
4080
|
-
var
|
|
4081
|
-
var
|
|
4082
|
-
var
|
|
4917
|
+
var import_js5 = require("@flopay/js");
|
|
4918
|
+
var import_shared9 = require("@flopay/shared");
|
|
4919
|
+
var import_react10 = require("react");
|
|
4920
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4083
4921
|
var WALLET_RESUME_KEY2 = "flopay_wallet_resume";
|
|
4084
|
-
var CheckoutForm = (0,
|
|
4922
|
+
var CheckoutForm = (0, import_react10.forwardRef)(
|
|
4085
4923
|
function CheckoutForm2(props, ref) {
|
|
4086
|
-
return /* @__PURE__ */ (0,
|
|
4924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
|
|
4087
4925
|
}
|
|
4088
4926
|
);
|
|
4089
4927
|
function CheckoutFormInner({
|
|
@@ -4112,34 +4950,34 @@ function CheckoutFormInner({
|
|
|
4112
4950
|
const paypalFlopay = usePayPalFloPay();
|
|
4113
4951
|
const elements = useElements();
|
|
4114
4952
|
const contextBillingUrl = useBillingApiUrl();
|
|
4115
|
-
const [processing, setProcessing] = (0,
|
|
4116
|
-
const [error, setError] = (0,
|
|
4117
|
-
const [is3DSActive, setIs3DSActive] = (0,
|
|
4953
|
+
const [processing, setProcessing] = (0, import_react10.useState)(false);
|
|
4954
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
4955
|
+
const [is3DSActive, setIs3DSActive] = (0, import_react10.useState)(false);
|
|
4118
4956
|
const displayError = externalError ?? error;
|
|
4119
4957
|
const isSubmitting = externalProcessing ?? processing;
|
|
4120
4958
|
const isSelfContained = !onTokenizedBody;
|
|
4121
4959
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
4122
|
-
const updateError = (0,
|
|
4960
|
+
const updateError = (0, import_react10.useCallback)(
|
|
4123
4961
|
(err) => {
|
|
4124
4962
|
setError(err);
|
|
4125
4963
|
onErrorChange?.(err);
|
|
4126
4964
|
},
|
|
4127
4965
|
[onErrorChange]
|
|
4128
4966
|
);
|
|
4129
|
-
const emitDecline = (0,
|
|
4967
|
+
const emitDecline = (0, import_react10.useCallback)(
|
|
4130
4968
|
(input, overrides) => {
|
|
4131
4969
|
onDecline?.(buildDeclineEvent("card", input, overrides));
|
|
4132
4970
|
},
|
|
4133
4971
|
[onDecline]
|
|
4134
4972
|
);
|
|
4135
|
-
const processPaymentInternal = (0,
|
|
4973
|
+
const processPaymentInternal = (0, import_react10.useCallback)(
|
|
4136
4974
|
async (tokenizedBody, completionPaymentMethodId) => {
|
|
4137
4975
|
setProcessing(true);
|
|
4138
4976
|
updateError(null);
|
|
4139
4977
|
const resolvedCompletionPaymentMethodId = completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
|
|
4140
4978
|
const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
|
|
4141
4979
|
try {
|
|
4142
|
-
const api = new
|
|
4980
|
+
const api = new import_js5.PaymentAPI(baseUrl);
|
|
4143
4981
|
const response = await api.processPayment(userId ?? "", {
|
|
4144
4982
|
sessionId,
|
|
4145
4983
|
tokenizedData: requestTokenizedBody,
|
|
@@ -4243,7 +5081,7 @@ function CheckoutFormInner({
|
|
|
4243
5081
|
},
|
|
4244
5082
|
[baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
|
|
4245
5083
|
);
|
|
4246
|
-
const dispatchTokenizedBody = (0,
|
|
5084
|
+
const dispatchTokenizedBody = (0, import_react10.useCallback)(
|
|
4247
5085
|
(tokenizedBody) => {
|
|
4248
5086
|
if (onTokenizedBody) {
|
|
4249
5087
|
onTokenizedBody(tokenizedBody);
|
|
@@ -4253,7 +5091,7 @@ function CheckoutFormInner({
|
|
|
4253
5091
|
},
|
|
4254
5092
|
[onTokenizedBody, processPaymentInternal]
|
|
4255
5093
|
);
|
|
4256
|
-
(0,
|
|
5094
|
+
(0, import_react10.useImperativeHandle)(innerRef, () => ({
|
|
4257
5095
|
async handleNextAction(secret) {
|
|
4258
5096
|
if (!flopay) return;
|
|
4259
5097
|
setIs3DSActive(true);
|
|
@@ -4280,7 +5118,7 @@ function CheckoutFormInner({
|
|
|
4280
5118
|
}
|
|
4281
5119
|
}
|
|
4282
5120
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
4283
|
-
(0,
|
|
5121
|
+
(0, import_react10.useEffect)(() => {
|
|
4284
5122
|
if (typeof window === "undefined") return;
|
|
4285
5123
|
const stored = localStorage.getItem(WALLET_RESUME_KEY2);
|
|
4286
5124
|
if (!stored) return;
|
|
@@ -4298,7 +5136,7 @@ function CheckoutFormInner({
|
|
|
4298
5136
|
localStorage.removeItem(WALLET_RESUME_KEY2);
|
|
4299
5137
|
}
|
|
4300
5138
|
}, [sessionId, dispatchTokenizedBody]);
|
|
4301
|
-
const handleSubmit = (0,
|
|
5139
|
+
const handleSubmit = (0, import_react10.useCallback)(
|
|
4302
5140
|
async (e) => {
|
|
4303
5141
|
e.preventDefault();
|
|
4304
5142
|
if (!flopay || !elements || isSubmitting) return;
|
|
@@ -4322,7 +5160,7 @@ function CheckoutFormInner({
|
|
|
4322
5160
|
return;
|
|
4323
5161
|
}
|
|
4324
5162
|
if (!sessionId || !email) {
|
|
4325
|
-
throw new
|
|
5163
|
+
throw new import_shared9.FloPayError("Missing sessionId or email", "validation_error");
|
|
4326
5164
|
}
|
|
4327
5165
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
4328
5166
|
method: "POST",
|
|
@@ -4346,7 +5184,7 @@ function CheckoutFormInner({
|
|
|
4346
5184
|
}
|
|
4347
5185
|
const intentJson = await intentResponse.json();
|
|
4348
5186
|
const intentClientSecret = intentJson.data?.id;
|
|
4349
|
-
if (!intentClientSecret) throw new
|
|
5187
|
+
if (!intentClientSecret) throw new import_shared9.FloPayError("No client_secret in payment intent response", "api_error");
|
|
4350
5188
|
const confirmResult = await flopay.confirmCardPayment({
|
|
4351
5189
|
clientSecret: intentClientSecret,
|
|
4352
5190
|
paymentMethodId: pmResult.paymentMethodId
|
|
@@ -4365,7 +5203,7 @@ function CheckoutFormInner({
|
|
|
4365
5203
|
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
4366
5204
|
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
4367
5205
|
if (!paymentIntentId) {
|
|
4368
|
-
const error2 = new
|
|
5206
|
+
const error2 = new import_shared9.FloPayError("No payment intent returned after confirmation.", "api_error");
|
|
4369
5207
|
updateError(error2.message);
|
|
4370
5208
|
onError?.(error2);
|
|
4371
5209
|
return;
|
|
@@ -4388,8 +5226,8 @@ function CheckoutFormInner({
|
|
|
4388
5226
|
[flopay, elements, isSubmitting, sessionId, email, baseUrl, isSelfContained, dispatchTokenizedBody, onError, updateError, emitDecline]
|
|
4389
5227
|
);
|
|
4390
5228
|
const isReady = flopay !== null && elements !== null;
|
|
4391
|
-
return /* @__PURE__ */ (0,
|
|
4392
|
-
(is3DSActive || isSubmitting) && /* @__PURE__ */ (0,
|
|
5229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5230
|
+
(is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-overlay", style: {
|
|
4393
5231
|
position: "absolute",
|
|
4394
5232
|
inset: 0,
|
|
4395
5233
|
background: "rgba(255,255,255,0.7)",
|
|
@@ -4398,12 +5236,12 @@ function CheckoutFormInner({
|
|
|
4398
5236
|
justifyContent: "center",
|
|
4399
5237
|
zIndex: 10
|
|
4400
5238
|
}, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
|
|
4401
|
-
!isReady && /* @__PURE__ */ (0,
|
|
4402
|
-
isReady && /* @__PURE__ */ (0,
|
|
4403
|
-
/* @__PURE__ */ (0,
|
|
4404
|
-
showAddress && /* @__PURE__ */ (0,
|
|
4405
|
-
displayError && /* @__PURE__ */ (0,
|
|
4406
|
-
children ?? /* @__PURE__ */ (0,
|
|
5239
|
+
!isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
|
|
5240
|
+
isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
5241
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaymentElement, { options: { layout } }),
|
|
5242
|
+
showAddress && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
|
|
5243
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
|
|
5244
|
+
children ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4407
5245
|
"button",
|
|
4408
5246
|
{
|
|
4409
5247
|
type: "submit",
|
|
@@ -4417,10 +5255,10 @@ function CheckoutFormInner({
|
|
|
4417
5255
|
}
|
|
4418
5256
|
|
|
4419
5257
|
// src/paypal-button.tsx
|
|
4420
|
-
var
|
|
4421
|
-
var
|
|
4422
|
-
var
|
|
4423
|
-
var
|
|
5258
|
+
var import_js6 = require("@flopay/js");
|
|
5259
|
+
var import_shared10 = require("@flopay/shared");
|
|
5260
|
+
var import_react11 = require("react");
|
|
5261
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4424
5262
|
function PayPalButton({
|
|
4425
5263
|
sessionId,
|
|
4426
5264
|
billingApiUrl,
|
|
@@ -4437,14 +5275,14 @@ function PayPalButton({
|
|
|
4437
5275
|
const flopay = useFloPay();
|
|
4438
5276
|
const elements = useElements();
|
|
4439
5277
|
const contextBillingUrl = useBillingApiUrl();
|
|
4440
|
-
const [ready, setReady] = (0,
|
|
4441
|
-
const [submitting, setSubmitting] = (0,
|
|
4442
|
-
const paypalResumeAttempted = (0,
|
|
5278
|
+
const [ready, setReady] = (0, import_react11.useState)(false);
|
|
5279
|
+
const [submitting, setSubmitting] = (0, import_react11.useState)(false);
|
|
5280
|
+
const paypalResumeAttempted = (0, import_react11.useRef)(false);
|
|
4443
5281
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
4444
|
-
const processPaymentInternal = (0,
|
|
5282
|
+
const processPaymentInternal = (0, import_react11.useCallback)(
|
|
4445
5283
|
async (tokenizedBody) => {
|
|
4446
5284
|
try {
|
|
4447
|
-
const api = new
|
|
5285
|
+
const api = new import_js6.PaymentAPI(baseUrl);
|
|
4448
5286
|
const response = await api.processPayment(userId ?? "", {
|
|
4449
5287
|
sessionId,
|
|
4450
5288
|
tokenizedData: tokenizedBody,
|
|
@@ -4468,7 +5306,7 @@ function PayPalButton({
|
|
|
4468
5306
|
},
|
|
4469
5307
|
[baseUrl, sessionId, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
|
|
4470
5308
|
);
|
|
4471
|
-
const dispatchTokenizedBody = (0,
|
|
5309
|
+
const dispatchTokenizedBody = (0, import_react11.useCallback)(
|
|
4472
5310
|
(body) => {
|
|
4473
5311
|
if (onTokenizedBody) {
|
|
4474
5312
|
onTokenizedBody(body);
|
|
@@ -4478,7 +5316,7 @@ function PayPalButton({
|
|
|
4478
5316
|
},
|
|
4479
5317
|
[onTokenizedBody, processPaymentInternal]
|
|
4480
5318
|
);
|
|
4481
|
-
(0,
|
|
5319
|
+
(0, import_react11.useEffect)(() => {
|
|
4482
5320
|
if (!flopay || paypalResumeAttempted.current) return;
|
|
4483
5321
|
const params = new URLSearchParams(window.location.search);
|
|
4484
5322
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -4526,13 +5364,13 @@ function PayPalButton({
|
|
|
4526
5364
|
}
|
|
4527
5365
|
})();
|
|
4528
5366
|
}, [flopay, dispatchTokenizedBody, onErrorChange]);
|
|
4529
|
-
const handlePayPalConfirm = (0,
|
|
5367
|
+
const handlePayPalConfirm = (0, import_react11.useCallback)(async () => {
|
|
4530
5368
|
if (!flopay || !elements) return;
|
|
4531
5369
|
try {
|
|
4532
5370
|
setSubmitting(true);
|
|
4533
5371
|
onErrorChange?.(null);
|
|
4534
5372
|
if (!sessionId || !email) {
|
|
4535
|
-
throw new
|
|
5373
|
+
throw new import_shared10.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
|
|
4536
5374
|
}
|
|
4537
5375
|
const result = await flopay.confirmPayPalPayment({
|
|
4538
5376
|
billingApiUrl: baseUrl,
|
|
@@ -4559,11 +5397,11 @@ function PayPalButton({
|
|
|
4559
5397
|
}
|
|
4560
5398
|
}, [flopay, elements, sessionId, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
|
|
4561
5399
|
if (!flopay || !elements) {
|
|
4562
|
-
return /* @__PURE__ */ (0,
|
|
5400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
|
|
4563
5401
|
}
|
|
4564
|
-
return /* @__PURE__ */ (0,
|
|
4565
|
-
!ready && /* @__PURE__ */ (0,
|
|
4566
|
-
/* @__PURE__ */ (0,
|
|
5402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
5403
|
+
!ready && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
|
|
5404
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4567
5405
|
"button",
|
|
4568
5406
|
{
|
|
4569
5407
|
type: "button",
|
|
@@ -4585,7 +5423,7 @@ function PayPalButton({
|
|
|
4585
5423
|
children: submitting ? "Processing..." : "PayPal"
|
|
4586
5424
|
}
|
|
4587
5425
|
) }),
|
|
4588
|
-
(submitting || isProcessing) && /* @__PURE__ */ (0,
|
|
5426
|
+
(submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
|
|
4589
5427
|
position: "fixed",
|
|
4590
5428
|
inset: 0,
|
|
4591
5429
|
background: "rgba(0,0,0,0.4)",
|
|
@@ -4593,7 +5431,7 @@ function PayPalButton({
|
|
|
4593
5431
|
alignItems: "center",
|
|
4594
5432
|
justifyContent: "center",
|
|
4595
5433
|
zIndex: 1e3
|
|
4596
|
-
}, children: /* @__PURE__ */ (0,
|
|
5434
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
|
|
4597
5435
|
background: "white",
|
|
4598
5436
|
borderRadius: 8,
|
|
4599
5437
|
padding: "1.5rem",
|
|
@@ -4605,20 +5443,20 @@ function PayPalButton({
|
|
|
4605
5443
|
}
|
|
4606
5444
|
|
|
4607
5445
|
// src/automatic-payment-button.tsx
|
|
4608
|
-
var
|
|
4609
|
-
var
|
|
4610
|
-
var
|
|
4611
|
-
var
|
|
5446
|
+
var import_react12 = require("react");
|
|
5447
|
+
var import_js7 = require("@flopay/js");
|
|
5448
|
+
var import_shared11 = require("@flopay/shared");
|
|
5449
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4612
5450
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
|
|
4613
5451
|
var PAYPAL_RESUME_STORAGE_KEY2 = "flopay_automatic_payment_button_resume";
|
|
4614
5452
|
function sleep2(ms) {
|
|
4615
5453
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4616
5454
|
}
|
|
4617
5455
|
function coerceError(err, fallbackMessage) {
|
|
4618
|
-
if (err instanceof
|
|
5456
|
+
if (err instanceof import_shared11.FloPayError) {
|
|
4619
5457
|
return err;
|
|
4620
5458
|
}
|
|
4621
|
-
return new
|
|
5459
|
+
return new import_shared11.FloPayError(
|
|
4622
5460
|
err instanceof Error ? err.message : fallbackMessage,
|
|
4623
5461
|
"api_error"
|
|
4624
5462
|
);
|
|
@@ -4725,11 +5563,11 @@ function FloPayAutomaticPaymentButton({
|
|
|
4725
5563
|
style,
|
|
4726
5564
|
...buttonProps
|
|
4727
5565
|
}) {
|
|
4728
|
-
const resolvedBillingUrl = (0,
|
|
4729
|
-
() => (0,
|
|
5566
|
+
const resolvedBillingUrl = (0, import_react12.useMemo)(
|
|
5567
|
+
() => (0, import_shared11.resolveBillingApiUrl)(billingApiUrl),
|
|
4730
5568
|
[billingApiUrl]
|
|
4731
5569
|
);
|
|
4732
|
-
const createSessionDraft = (0,
|
|
5570
|
+
const createSessionDraft = (0, import_react12.useMemo)(
|
|
4733
5571
|
() => resolveCreateSessionDraft({
|
|
4734
5572
|
createSession,
|
|
4735
5573
|
clientId,
|
|
@@ -4755,43 +5593,47 @@ function FloPayAutomaticPaymentButton({
|
|
|
4755
5593
|
utmMetadata
|
|
4756
5594
|
]
|
|
4757
5595
|
);
|
|
4758
|
-
const [isProcessing, setIsProcessing] = (0,
|
|
4759
|
-
const [overlayStatus, setOverlayStatus] = (0,
|
|
4760
|
-
const [overlayError, setOverlayError] = (0,
|
|
4761
|
-
const [fallbackSession, setFallbackSession] = (0,
|
|
4762
|
-
const automaticPaymentToken = (0,
|
|
5596
|
+
const [isProcessing, setIsProcessing] = (0, import_react12.useState)(false);
|
|
5597
|
+
const [overlayStatus, setOverlayStatus] = (0, import_react12.useState)(null);
|
|
5598
|
+
const [overlayError, setOverlayError] = (0, import_react12.useState)(null);
|
|
5599
|
+
const [fallbackSession, setFallbackSession] = (0, import_react12.useState)(null);
|
|
5600
|
+
const automaticPaymentToken = (0, import_react12.useMemo)(
|
|
4763
5601
|
() => paymentMethodId ? {
|
|
4764
5602
|
id: paymentMethodId,
|
|
4765
|
-
|
|
5603
|
+
// Saved PayPal `user_payment_method` records are submitted with
|
|
5604
|
+
// `type: 'paypal'` so the backend routes the upsell through the
|
|
5605
|
+
// direct PayPal gateway's vaulted-token flow. Card and wallet PMs
|
|
5606
|
+
// continue to use `type: 'card'`.
|
|
5607
|
+
type: checkoutMethod === "paypal" ? "paypal" : "card",
|
|
4766
5608
|
...checkoutMethod === "paypal" ? { isPaypal: true } : {}
|
|
4767
5609
|
} : void 0,
|
|
4768
5610
|
[checkoutMethod, paymentMethodId]
|
|
4769
5611
|
);
|
|
4770
|
-
const isMountedRef = (0,
|
|
4771
|
-
const resumeAttemptedRef = (0,
|
|
4772
|
-
const fallbackSessionRef = (0,
|
|
4773
|
-
const onSuccessRef = (0,
|
|
4774
|
-
const onErrorRef = (0,
|
|
4775
|
-
const onDeclineRef = (0,
|
|
4776
|
-
(0,
|
|
5612
|
+
const isMountedRef = (0, import_react12.useRef)(true);
|
|
5613
|
+
const resumeAttemptedRef = (0, import_react12.useRef)(false);
|
|
5614
|
+
const fallbackSessionRef = (0, import_react12.useRef)(fallbackSession);
|
|
5615
|
+
const onSuccessRef = (0, import_react12.useRef)(onSuccess);
|
|
5616
|
+
const onErrorRef = (0, import_react12.useRef)(onError);
|
|
5617
|
+
const onDeclineRef = (0, import_react12.useRef)(onDecline);
|
|
5618
|
+
(0, import_react12.useEffect)(() => {
|
|
4777
5619
|
fallbackSessionRef.current = fallbackSession;
|
|
4778
5620
|
}, [fallbackSession]);
|
|
4779
|
-
(0,
|
|
5621
|
+
(0, import_react12.useEffect)(() => {
|
|
4780
5622
|
onSuccessRef.current = onSuccess;
|
|
4781
5623
|
}, [onSuccess]);
|
|
4782
|
-
(0,
|
|
5624
|
+
(0, import_react12.useEffect)(() => {
|
|
4783
5625
|
onErrorRef.current = onError;
|
|
4784
5626
|
}, [onError]);
|
|
4785
|
-
(0,
|
|
5627
|
+
(0, import_react12.useEffect)(() => {
|
|
4786
5628
|
onDeclineRef.current = onDecline;
|
|
4787
5629
|
}, [onDecline]);
|
|
4788
|
-
(0,
|
|
5630
|
+
(0, import_react12.useEffect)(() => {
|
|
4789
5631
|
isMountedRef.current = true;
|
|
4790
5632
|
return () => {
|
|
4791
5633
|
isMountedRef.current = false;
|
|
4792
5634
|
};
|
|
4793
5635
|
}, []);
|
|
4794
|
-
(0,
|
|
5636
|
+
(0, import_react12.useEffect)(() => {
|
|
4795
5637
|
if (!fallbackSession || typeof window === "undefined") {
|
|
4796
5638
|
return;
|
|
4797
5639
|
}
|
|
@@ -4805,13 +5647,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
4805
5647
|
window.removeEventListener("keydown", handleKeyDown);
|
|
4806
5648
|
};
|
|
4807
5649
|
}, [fallbackSession]);
|
|
4808
|
-
const emitDecline = (0,
|
|
5650
|
+
const emitDecline = (0, import_react12.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
|
|
4809
5651
|
onDeclineRef.current?.(buildDeclineEvent(method, error, {
|
|
4810
5652
|
code: error.code,
|
|
4811
5653
|
declineCode: error.declineCode
|
|
4812
5654
|
}));
|
|
4813
5655
|
}, []);
|
|
4814
|
-
const showSuccess = (0,
|
|
5656
|
+
const showSuccess = (0, import_react12.useCallback)(async (event) => {
|
|
4815
5657
|
if (!isMountedRef.current) return;
|
|
4816
5658
|
setOverlayError(null);
|
|
4817
5659
|
setOverlayStatus("success");
|
|
@@ -4819,7 +5661,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4819
5661
|
if (!isMountedRef.current) return;
|
|
4820
5662
|
onSuccessRef.current?.(event);
|
|
4821
5663
|
}, []);
|
|
4822
|
-
const showError = (0,
|
|
5664
|
+
const showError = (0, import_react12.useCallback)(async (error, options) => {
|
|
4823
5665
|
if (!isMountedRef.current) return;
|
|
4824
5666
|
onErrorRef.current?.(error);
|
|
4825
5667
|
if (options?.emitDecline) {
|
|
@@ -4829,10 +5671,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
4829
5671
|
setOverlayStatus("error");
|
|
4830
5672
|
await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
|
|
4831
5673
|
}, [emitDecline]);
|
|
4832
|
-
const processResolvedSession = (0,
|
|
5674
|
+
const processResolvedSession = (0, import_react12.useCallback)(async (apiResult, resolvedSessionId, options) => {
|
|
4833
5675
|
const session = apiResult.data.session ?? null;
|
|
4834
5676
|
if (!session) {
|
|
4835
|
-
throw new
|
|
5677
|
+
throw new import_shared11.FloPayError("No session data returned", "api_error");
|
|
4836
5678
|
}
|
|
4837
5679
|
if (session.status === "complete") {
|
|
4838
5680
|
await showSuccess({
|
|
@@ -4844,7 +5686,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4844
5686
|
return;
|
|
4845
5687
|
}
|
|
4846
5688
|
if (session.status === "expired") {
|
|
4847
|
-
throw new
|
|
5689
|
+
throw new import_shared11.FloPayError("Checkout session has expired.", "api_error", {
|
|
4848
5690
|
code: "checkout_session_expired"
|
|
4849
5691
|
});
|
|
4850
5692
|
}
|
|
@@ -4854,13 +5696,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
4854
5696
|
const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
|
|
4855
5697
|
const shouldRetryPayPalClientSide = checkoutMethod === "paypal" && automaticPaymentToken?.isPaypal === true && options?.fromCreateSession === true;
|
|
4856
5698
|
if (apiResult.autoProcessingPending) {
|
|
4857
|
-
const api = new
|
|
5699
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
4858
5700
|
const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
|
|
4859
5701
|
initialDelayMs: apiResult.autoProcessingPending.retryAfterMs
|
|
4860
5702
|
});
|
|
4861
5703
|
const completedSession = completed.data.session;
|
|
4862
5704
|
if (!completedSession || completedSession.status !== "complete") {
|
|
4863
|
-
throw new
|
|
5705
|
+
throw new import_shared11.FloPayError("Automatic payment failed. Please try again.", "api_error", {
|
|
4864
5706
|
code: completedSession?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
4865
5707
|
});
|
|
4866
5708
|
}
|
|
@@ -4881,7 +5723,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4881
5723
|
publishableKey,
|
|
4882
5724
|
paypalPublishableKey
|
|
4883
5725
|
} = resolveSavedPaymentPublishableKeys(apiResult);
|
|
4884
|
-
if (redirectResult.type === "paypal_redirect_required") {
|
|
5726
|
+
if (redirectResult.type === "paypal_redirect_required" && publishableKey) {
|
|
4885
5727
|
persistPayPalResumeState2({
|
|
4886
5728
|
sessionId: session.id || resolvedSessionId,
|
|
4887
5729
|
publishableKey,
|
|
@@ -4937,7 +5779,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4937
5779
|
publishableKey,
|
|
4938
5780
|
paypalPublishableKey
|
|
4939
5781
|
} = resolveSavedPaymentPublishableKeys(apiResult);
|
|
4940
|
-
if (result.type === "paypal_redirect_required") {
|
|
5782
|
+
if (result.type === "paypal_redirect_required" && publishableKey) {
|
|
4941
5783
|
persistPayPalResumeState2({
|
|
4942
5784
|
sessionId: session.id || resolvedSessionId,
|
|
4943
5785
|
publishableKey,
|
|
@@ -4998,6 +5840,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
4998
5840
|
billingApiUrl: resolvedBillingUrl,
|
|
4999
5841
|
locale
|
|
5000
5842
|
});
|
|
5843
|
+
if (!flopay) {
|
|
5844
|
+
throw new import_shared11.FloPayError(
|
|
5845
|
+
"Stripe is not available for 3DS authentication.",
|
|
5846
|
+
"api_error",
|
|
5847
|
+
{ code: "authentication_required" }
|
|
5848
|
+
);
|
|
5849
|
+
}
|
|
5001
5850
|
const paymentResult = await processSavedPaymentWithIntent({
|
|
5002
5851
|
billingApiUrl: resolvedBillingUrl,
|
|
5003
5852
|
sessionId: fallbackSessionId,
|
|
@@ -5052,14 +5901,14 @@ function FloPayAutomaticPaymentButton({
|
|
|
5052
5901
|
showError,
|
|
5053
5902
|
showSuccess
|
|
5054
5903
|
]);
|
|
5055
|
-
const handleButtonClick = (0,
|
|
5904
|
+
const handleButtonClick = (0, import_react12.useCallback)(async (event) => {
|
|
5056
5905
|
buttonProps.onClick?.(event);
|
|
5057
5906
|
if (event.defaultPrevented || disabled || isProcessing) {
|
|
5058
5907
|
return;
|
|
5059
5908
|
}
|
|
5060
5909
|
setFallbackSession(null);
|
|
5061
5910
|
if (sessionId && createSessionDraft) {
|
|
5062
|
-
const error = new
|
|
5911
|
+
const error = new import_shared11.FloPayError(
|
|
5063
5912
|
"Provide either sessionId or create-session props, not both.",
|
|
5064
5913
|
"validation_error"
|
|
5065
5914
|
);
|
|
@@ -5071,7 +5920,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5071
5920
|
return;
|
|
5072
5921
|
}
|
|
5073
5922
|
if (!sessionId && !createSessionDraft) {
|
|
5074
|
-
const error = new
|
|
5923
|
+
const error = new import_shared11.FloPayError(
|
|
5075
5924
|
"Provide a sessionId or the props required to create an automatic payment session.",
|
|
5076
5925
|
"validation_error"
|
|
5077
5926
|
);
|
|
@@ -5086,7 +5935,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5086
5935
|
setOverlayError(null);
|
|
5087
5936
|
setOverlayStatus("processing");
|
|
5088
5937
|
try {
|
|
5089
|
-
const api = new
|
|
5938
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
5090
5939
|
if (sessionId) {
|
|
5091
5940
|
const result = await api.getUnifiedCheckoutSession(sessionId);
|
|
5092
5941
|
await processResolvedSession(result, sessionId);
|
|
@@ -5101,7 +5950,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5101
5950
|
fromCreateSession: true
|
|
5102
5951
|
});
|
|
5103
5952
|
} catch (err) {
|
|
5104
|
-
if (err instanceof
|
|
5953
|
+
if (err instanceof import_shared11.FloPayError && err.code === "session_auto_completed") {
|
|
5105
5954
|
await showSuccess({
|
|
5106
5955
|
result: { status: "succeeded" },
|
|
5107
5956
|
session: null,
|
|
@@ -5134,7 +5983,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5134
5983
|
showError,
|
|
5135
5984
|
showSuccess
|
|
5136
5985
|
]);
|
|
5137
|
-
const handleFallbackComplete = (0,
|
|
5986
|
+
const handleFallbackComplete = (0, import_react12.useCallback)((result) => {
|
|
5138
5987
|
const activeFallback = fallbackSessionRef.current;
|
|
5139
5988
|
setFallbackSession(null);
|
|
5140
5989
|
onSuccessRef.current?.({
|
|
@@ -5144,13 +5993,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
5144
5993
|
autoCompleted: false
|
|
5145
5994
|
});
|
|
5146
5995
|
}, []);
|
|
5147
|
-
const handleFallbackError = (0,
|
|
5996
|
+
const handleFallbackError = (0, import_react12.useCallback)((error) => {
|
|
5148
5997
|
onErrorRef.current?.(error);
|
|
5149
5998
|
}, []);
|
|
5150
|
-
const handleFallbackDecline = (0,
|
|
5999
|
+
const handleFallbackDecline = (0, import_react12.useCallback)((decline) => {
|
|
5151
6000
|
onDeclineRef.current?.(decline);
|
|
5152
6001
|
}, []);
|
|
5153
|
-
(0,
|
|
6002
|
+
(0, import_react12.useEffect)(() => {
|
|
5154
6003
|
if (typeof window === "undefined" || resumeAttemptedRef.current) {
|
|
5155
6004
|
return;
|
|
5156
6005
|
}
|
|
@@ -5171,7 +6020,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5171
6020
|
try {
|
|
5172
6021
|
if (params.get("redirect_status") === "failed") {
|
|
5173
6022
|
throw Object.assign(
|
|
5174
|
-
new
|
|
6023
|
+
new import_shared11.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
|
|
5175
6024
|
{ checkoutMethod: "paypal" }
|
|
5176
6025
|
);
|
|
5177
6026
|
}
|
|
@@ -5184,17 +6033,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
5184
6033
|
billingApiUrl: resolvedBillingUrl,
|
|
5185
6034
|
locale
|
|
5186
6035
|
});
|
|
5187
|
-
const paypalStripe = (paypalFlopay ?? flopay)
|
|
6036
|
+
const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
|
|
5188
6037
|
if (!paypalStripe) {
|
|
5189
6038
|
throw Object.assign(
|
|
5190
|
-
new
|
|
6039
|
+
new import_shared11.FloPayError("PayPal is not available.", "api_error"),
|
|
5191
6040
|
{ checkoutMethod: "paypal" }
|
|
5192
6041
|
);
|
|
5193
6042
|
}
|
|
5194
6043
|
const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
|
|
5195
6044
|
if (error) {
|
|
5196
6045
|
throw Object.assign(
|
|
5197
|
-
new
|
|
6046
|
+
new import_shared11.FloPayError(
|
|
5198
6047
|
error.message ?? "Failed to retrieve PayPal payment status.",
|
|
5199
6048
|
"api_error",
|
|
5200
6049
|
{ code: error.code }
|
|
@@ -5205,23 +6054,23 @@ function FloPayAutomaticPaymentButton({
|
|
|
5205
6054
|
const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
|
|
5206
6055
|
if (!paymentIntent || resultStatus === "failed") {
|
|
5207
6056
|
throw Object.assign(
|
|
5208
|
-
new
|
|
6057
|
+
new import_shared11.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
|
|
5209
6058
|
{ checkoutMethod: "paypal" }
|
|
5210
6059
|
);
|
|
5211
6060
|
}
|
|
5212
6061
|
const paymentMethodId2 = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
5213
6062
|
if (!resumeState.sessionId) {
|
|
5214
6063
|
throw Object.assign(
|
|
5215
|
-
new
|
|
6064
|
+
new import_shared11.FloPayError("Missing session id on PayPal resume.", "api_error"),
|
|
5216
6065
|
{ checkoutMethod: "paypal" }
|
|
5217
6066
|
);
|
|
5218
6067
|
}
|
|
5219
|
-
const api = new
|
|
6068
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
5220
6069
|
const sessionResult = await api.getUnifiedCheckoutSession(resumeState.sessionId);
|
|
5221
6070
|
let resumeSession = sessionResult.data.session;
|
|
5222
6071
|
if (!resumeSession) {
|
|
5223
6072
|
throw Object.assign(
|
|
5224
|
-
new
|
|
6073
|
+
new import_shared11.FloPayError("Could not load session to capture PayPal payment.", "api_error"),
|
|
5225
6074
|
{ checkoutMethod: "paypal" }
|
|
5226
6075
|
);
|
|
5227
6076
|
}
|
|
@@ -5240,7 +6089,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5240
6089
|
});
|
|
5241
6090
|
if (processResult.type !== "success") {
|
|
5242
6091
|
throw Object.assign(
|
|
5243
|
-
new
|
|
6092
|
+
new import_shared11.FloPayError("Failed to finalize PayPal payment.", "api_error"),
|
|
5244
6093
|
{ checkoutMethod: "paypal" }
|
|
5245
6094
|
);
|
|
5246
6095
|
}
|
|
@@ -5281,8 +6130,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
5281
6130
|
}
|
|
5282
6131
|
})();
|
|
5283
6132
|
}, [locale, resolvedBillingUrl, showError, showSuccess]);
|
|
5284
|
-
const bStyles = (0,
|
|
5285
|
-
const base = (0,
|
|
6133
|
+
const bStyles = (0, import_react12.useMemo)(() => {
|
|
6134
|
+
const base = (0, import_shared11.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
5286
6135
|
if (!stylesOverride) return base;
|
|
5287
6136
|
return {
|
|
5288
6137
|
...base,
|
|
@@ -5291,8 +6140,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
5291
6140
|
};
|
|
5292
6141
|
}, [buttonsTheme, stylesOverride]);
|
|
5293
6142
|
const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
5294
|
-
return /* @__PURE__ */ (0,
|
|
5295
|
-
/* @__PURE__ */ (0,
|
|
6143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6144
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5296
6145
|
"button",
|
|
5297
6146
|
{
|
|
5298
6147
|
...buttonProps,
|
|
@@ -5333,17 +6182,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
5333
6182
|
e.currentTarget.style.transform = "scale(1)";
|
|
5334
6183
|
}
|
|
5335
6184
|
},
|
|
5336
|
-
children: /* @__PURE__ */ (0,
|
|
6185
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CardButtonContentSlot, { content: children })
|
|
5337
6186
|
}
|
|
5338
6187
|
),
|
|
5339
|
-
overlayStatus && /* @__PURE__ */ (0,
|
|
6188
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5340
6189
|
ProcessingOverlay,
|
|
5341
6190
|
{
|
|
5342
6191
|
status: overlayStatus,
|
|
5343
6192
|
errorMessage: overlayError
|
|
5344
6193
|
}
|
|
5345
6194
|
),
|
|
5346
|
-
fallbackSession && /* @__PURE__ */ (0,
|
|
6195
|
+
fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5347
6196
|
"div",
|
|
5348
6197
|
{
|
|
5349
6198
|
"data-testid": "flopay-automatic-payment-fallback",
|
|
@@ -5364,7 +6213,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5364
6213
|
padding: "1.5rem",
|
|
5365
6214
|
zIndex: 1100
|
|
5366
6215
|
},
|
|
5367
|
-
children: /* @__PURE__ */ (0,
|
|
6216
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5368
6217
|
"div",
|
|
5369
6218
|
{
|
|
5370
6219
|
style: {
|
|
@@ -5380,7 +6229,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5380
6229
|
flexDirection: "column",
|
|
5381
6230
|
gap: "1rem"
|
|
5382
6231
|
},
|
|
5383
|
-
children: /* @__PURE__ */ (0,
|
|
6232
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5384
6233
|
FloPayCheckout,
|
|
5385
6234
|
{
|
|
5386
6235
|
sessionId: fallbackSession.sessionId,
|
|
@@ -5408,6 +6257,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5408
6257
|
CardExpiryElement,
|
|
5409
6258
|
CardNumberElement,
|
|
5410
6259
|
CheckoutForm,
|
|
6260
|
+
DirectPayPalButton,
|
|
5411
6261
|
FloPayAutomaticPaymentButton,
|
|
5412
6262
|
FloPayCheckout,
|
|
5413
6263
|
FloPayProvider,
|