@flopay/react 1.0.3 → 1.1.0
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 +11 -4
- package/dist/index.cjs +1244 -494
- 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 +1154 -405
- 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");
|
|
@@ -688,11 +689,562 @@ function isInAppBrowser(userAgent) {
|
|
|
688
689
|
return false;
|
|
689
690
|
}
|
|
690
691
|
|
|
691
|
-
// src/
|
|
692
|
-
var
|
|
692
|
+
// src/direct-paypal-button.tsx
|
|
693
|
+
var import_react7 = require("react");
|
|
694
|
+
var import_paypal_js = require("@paypal/paypal-js");
|
|
695
|
+
var import_js = require("@flopay/js");
|
|
696
|
+
var import_shared4 = require("@flopay/shared");
|
|
693
697
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
698
|
+
var DEFAULT_BUTTON_HEIGHT = 45;
|
|
699
|
+
function DirectPayPalButton({
|
|
700
|
+
sessionId,
|
|
701
|
+
billingApiUrl,
|
|
702
|
+
email,
|
|
703
|
+
clientId,
|
|
704
|
+
environment,
|
|
705
|
+
currency,
|
|
706
|
+
isSubscription,
|
|
707
|
+
onTokenizedBody,
|
|
708
|
+
onComplete,
|
|
709
|
+
onErrorChange,
|
|
710
|
+
onDecline,
|
|
711
|
+
isProcessing = false,
|
|
712
|
+
onLoadStateChange,
|
|
713
|
+
onButtonClick,
|
|
714
|
+
runBeforeButtonClick,
|
|
715
|
+
session,
|
|
716
|
+
existingOrderId,
|
|
717
|
+
debug = false
|
|
718
|
+
}) {
|
|
719
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
720
|
+
const [ready, setReady] = (0, import_react7.useState)(false);
|
|
721
|
+
const [failed, setFailed] = (0, import_react7.useState)(false);
|
|
722
|
+
const [submitting, setSubmitting] = (0, import_react7.useState)(false);
|
|
723
|
+
const baseUrl = (0, import_react7.useMemo)(() => billingApiUrl.replace(/\/+$/, ""), [billingApiUrl]);
|
|
724
|
+
const [debugLines, setDebugLines] = (0, import_react7.useState)([]);
|
|
725
|
+
const appendDebug = (line) => {
|
|
726
|
+
if (!debug) return;
|
|
727
|
+
setDebugLines((prev) => [...prev, `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 23)} ${line}`]);
|
|
728
|
+
};
|
|
729
|
+
const onTokenizedBodyRef = (0, import_react7.useRef)(onTokenizedBody);
|
|
730
|
+
const onCompleteRef = (0, import_react7.useRef)(onComplete);
|
|
731
|
+
const onErrorChangeRef = (0, import_react7.useRef)(onErrorChange);
|
|
732
|
+
const onDeclineRef = (0, import_react7.useRef)(onDecline);
|
|
733
|
+
const onButtonClickRef = (0, import_react7.useRef)(onButtonClick);
|
|
734
|
+
const onLoadStateChangeRef = (0, import_react7.useRef)(onLoadStateChange);
|
|
735
|
+
const runBeforeButtonClickRef = (0, import_react7.useRef)(runBeforeButtonClick);
|
|
736
|
+
const sessionRef = (0, import_react7.useRef)(session);
|
|
737
|
+
const emailRef = (0, import_react7.useRef)(email);
|
|
738
|
+
const beforeClickRef = (0, import_react7.useRef)(null);
|
|
739
|
+
(0, import_react7.useEffect)(() => {
|
|
740
|
+
onTokenizedBodyRef.current = onTokenizedBody;
|
|
741
|
+
}, [onTokenizedBody]);
|
|
742
|
+
(0, import_react7.useEffect)(() => {
|
|
743
|
+
onCompleteRef.current = onComplete;
|
|
744
|
+
}, [onComplete]);
|
|
745
|
+
(0, import_react7.useEffect)(() => {
|
|
746
|
+
onErrorChangeRef.current = onErrorChange;
|
|
747
|
+
}, [onErrorChange]);
|
|
748
|
+
(0, import_react7.useEffect)(() => {
|
|
749
|
+
onDeclineRef.current = onDecline;
|
|
750
|
+
}, [onDecline]);
|
|
751
|
+
(0, import_react7.useEffect)(() => {
|
|
752
|
+
onButtonClickRef.current = onButtonClick;
|
|
753
|
+
}, [onButtonClick]);
|
|
754
|
+
(0, import_react7.useEffect)(() => {
|
|
755
|
+
onLoadStateChangeRef.current = onLoadStateChange;
|
|
756
|
+
}, [onLoadStateChange]);
|
|
757
|
+
(0, import_react7.useEffect)(() => {
|
|
758
|
+
runBeforeButtonClickRef.current = runBeforeButtonClick;
|
|
759
|
+
}, [runBeforeButtonClick]);
|
|
760
|
+
(0, import_react7.useEffect)(() => {
|
|
761
|
+
sessionRef.current = session;
|
|
762
|
+
}, [session]);
|
|
763
|
+
(0, import_react7.useEffect)(() => {
|
|
764
|
+
emailRef.current = email;
|
|
765
|
+
}, [email]);
|
|
766
|
+
(0, import_react7.useEffect)(() => {
|
|
767
|
+
onLoadStateChangeRef.current?.(ready && !failed);
|
|
768
|
+
}, [ready, failed]);
|
|
769
|
+
const normalizedEnv = (0, import_shared4.normalizeGatewayEnvironment)(environment);
|
|
770
|
+
(0, import_react7.useEffect)(() => {
|
|
771
|
+
const maskedClient = clientId ? `${clientId.slice(0, 6)}\u2026(len ${clientId.length})` : "(empty)";
|
|
772
|
+
const ua = typeof navigator !== "undefined" ? navigator.userAgent : "(no navigator)";
|
|
773
|
+
appendDebug(`mount clientId=${maskedClient} env=${environment ?? "(unset)"}\u2192${normalizedEnv ?? "live"} ccy=${currency} sub=${isSubscription}`);
|
|
774
|
+
appendDebug(`ua=${ua.slice(0, 80)}${ua.length > 80 ? "\u2026" : ""}`);
|
|
775
|
+
if (!clientId) {
|
|
776
|
+
appendDebug("FAIL: clientId empty \u2014 gateway misconfigured");
|
|
777
|
+
setFailed(true);
|
|
778
|
+
onErrorChangeRef.current?.("Direct PayPal gateway is misconfigured.");
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (!containerRef.current) {
|
|
782
|
+
appendDebug("FAIL: containerRef not attached");
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
let cancelled = false;
|
|
786
|
+
let activeButtons = null;
|
|
787
|
+
let rendered = false;
|
|
788
|
+
const container = containerRef.current;
|
|
789
|
+
let containerObserver = null;
|
|
790
|
+
let perfObserver = null;
|
|
791
|
+
const watchdogTimers = [];
|
|
792
|
+
const formatDims = (el) => {
|
|
793
|
+
if (!el || typeof el.getBoundingClientRect !== "function") return "(no rect)";
|
|
794
|
+
const rect = el.getBoundingClientRect();
|
|
795
|
+
return `${Math.round(rect.width)}\xD7${Math.round(rect.height)}`;
|
|
796
|
+
};
|
|
797
|
+
const classifyIframeSrc = (raw) => {
|
|
798
|
+
if (!raw) return "(empty)";
|
|
799
|
+
try {
|
|
800
|
+
const url = new URL(raw, typeof window !== "undefined" ? window.location.href : "https://localhost");
|
|
801
|
+
const path = url.pathname.toLowerCase();
|
|
802
|
+
if (path.includes("checkcaptcha") || path.includes("captcha")) return `CAPTCHA(${url.host}${path})`;
|
|
803
|
+
if (path.includes("risk") || path.includes("challenge")) return `RISK(${url.host}${path})`;
|
|
804
|
+
if (path.includes("smart/buttons")) return `smart-buttons(${url.host})`;
|
|
805
|
+
return `${url.host}${path}`.slice(0, 100);
|
|
806
|
+
} catch {
|
|
807
|
+
return raw.slice(0, 80);
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
const describeIframe = (frame) => {
|
|
811
|
+
const src = frame.getAttribute("src");
|
|
812
|
+
const srcdoc = frame.getAttribute("srcdoc");
|
|
813
|
+
const name = frame.getAttribute("name");
|
|
814
|
+
const sandbox = frame.getAttribute("sandbox");
|
|
815
|
+
const parts = [];
|
|
816
|
+
if (src) parts.push(`src=${classifyIframeSrc(src)}`);
|
|
817
|
+
if (srcdoc) parts.push(`srcdoc[${srcdoc.length}ch]`);
|
|
818
|
+
if (!src && !srcdoc) parts.push("src=(empty) srcdoc=(empty)");
|
|
819
|
+
if (name) parts.push(`name=${name.slice(0, 40)}`);
|
|
820
|
+
if (sandbox !== null) parts.push(`sandbox="${sandbox.slice(0, 40)}"`);
|
|
821
|
+
return parts.join(" ");
|
|
822
|
+
};
|
|
823
|
+
const inspectFrameContent = (frame) => {
|
|
824
|
+
if (!(frame instanceof HTMLIFrameElement)) return "";
|
|
825
|
+
try {
|
|
826
|
+
const cd = frame.contentDocument;
|
|
827
|
+
if (!cd) return "cd=null";
|
|
828
|
+
const bodyChildren = cd.body?.children.length ?? 0;
|
|
829
|
+
const bodyLen = cd.body?.innerHTML.length ?? 0;
|
|
830
|
+
const headLen = cd.head?.innerHTML.length ?? 0;
|
|
831
|
+
return `cd=same-origin readyState=${cd.readyState} body[${bodyChildren}children,${bodyLen}ch] head[${headLen}ch]`;
|
|
832
|
+
} catch (err) {
|
|
833
|
+
return `cd=cross-origin(${err.message.slice(0, 30)})`;
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
const errorMessages = [];
|
|
837
|
+
const onWindowError = (ev) => {
|
|
838
|
+
const msg = ev.message ?? String(ev.error ?? "(no message)");
|
|
839
|
+
if (msg && (msg.toLowerCase().includes("paypal") || msg.toLowerCase().includes("zoid") || msg.toLowerCase().includes("postrobot") || msg.toLowerCase().includes("storage"))) {
|
|
840
|
+
appendDebug(`window:error ${msg.slice(0, 140)}`);
|
|
841
|
+
errorMessages.push(msg);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
const onUnhandledRejection = (ev) => {
|
|
845
|
+
const reason = ev.reason instanceof Error ? ev.reason.message : String(ev.reason ?? "(no reason)");
|
|
846
|
+
if (reason && (reason.toLowerCase().includes("paypal") || reason.toLowerCase().includes("zoid") || reason.toLowerCase().includes("postrobot") || reason.toLowerCase().includes("storage"))) {
|
|
847
|
+
appendDebug(`window:rejection ${reason.slice(0, 140)}`);
|
|
848
|
+
errorMessages.push(reason);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
if (debug && typeof window !== "undefined") {
|
|
852
|
+
window.addEventListener("error", onWindowError);
|
|
853
|
+
window.addEventListener("unhandledrejection", onUnhandledRejection);
|
|
854
|
+
}
|
|
855
|
+
const paypalRequestCount = { value: 0 };
|
|
856
|
+
if (debug && typeof PerformanceObserver !== "undefined") {
|
|
857
|
+
try {
|
|
858
|
+
perfObserver = new PerformanceObserver((list) => {
|
|
859
|
+
for (const entry of list.getEntries()) {
|
|
860
|
+
if (!entry.name.toLowerCase().includes("paypal")) continue;
|
|
861
|
+
paypalRequestCount.value += 1;
|
|
862
|
+
const dur = Math.round(entry.duration);
|
|
863
|
+
appendDebug(`net ${dur}ms ${entry.name.slice(0, 90)}`);
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
perfObserver.observe({ type: "resource", buffered: true });
|
|
867
|
+
} catch {
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
const stopDiagnostics = () => {
|
|
871
|
+
containerObserver?.disconnect();
|
|
872
|
+
containerObserver = null;
|
|
873
|
+
perfObserver?.disconnect();
|
|
874
|
+
perfObserver = null;
|
|
875
|
+
while (watchdogTimers.length) clearTimeout(watchdogTimers.pop());
|
|
876
|
+
if (debug && typeof window !== "undefined") {
|
|
877
|
+
window.removeEventListener("error", onWindowError);
|
|
878
|
+
window.removeEventListener("unhandledrejection", onUnhandledRejection);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
const isZoidLifecycleMessage = (message) => {
|
|
882
|
+
if (!message) return false;
|
|
883
|
+
const lower = message.toLowerCase();
|
|
884
|
+
return lower.includes("zoid destroyed") || lower.includes("destroyed all components") || lower.includes("window closed") || lower.includes("detected container element removed");
|
|
885
|
+
};
|
|
886
|
+
const forwardError = (message) => {
|
|
887
|
+
if (cancelled) return;
|
|
888
|
+
if (isZoidLifecycleMessage(message)) return;
|
|
889
|
+
onErrorChangeRef.current?.(message);
|
|
890
|
+
};
|
|
891
|
+
const markRenderFailed = (message) => {
|
|
892
|
+
if (cancelled) return;
|
|
893
|
+
if (isZoidLifecycleMessage(message)) {
|
|
894
|
+
appendDebug(`markRenderFailed:skip-zoid msg=${message.slice(0, 80)}`);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
setFailed(true);
|
|
898
|
+
forwardError(message);
|
|
899
|
+
};
|
|
900
|
+
setFailed(false);
|
|
901
|
+
const dispatchTokenizedBody = async (body) => {
|
|
902
|
+
const prepared = beforeClickRef.current;
|
|
903
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
904
|
+
if (onTokenizedBodyRef.current) {
|
|
905
|
+
onTokenizedBodyRef.current(body, {
|
|
906
|
+
sessionId: effectiveSessionId,
|
|
907
|
+
accountPatch: prepared?.accountPatch
|
|
908
|
+
});
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
try {
|
|
912
|
+
const currentSession = sessionRef.current;
|
|
913
|
+
const currentEmail = prepared?.accountPatch?.email ?? emailRef.current;
|
|
914
|
+
const effectiveUserId = prepared?.accountPatch?.userId ?? currentSession?.customer?.id ?? currentSession?.accountData?.userId ?? "";
|
|
915
|
+
const api = new import_js.PaymentAPI(baseUrl);
|
|
916
|
+
const response = await api.processPayment(
|
|
917
|
+
effectiveUserId,
|
|
918
|
+
{
|
|
919
|
+
sessionId: effectiveSessionId,
|
|
920
|
+
tokenizedData: body,
|
|
921
|
+
accountData: {
|
|
922
|
+
userId: effectiveUserId,
|
|
923
|
+
email: currentEmail ?? currentSession?.customer?.email ?? "",
|
|
924
|
+
firstName: prepared?.accountPatch?.firstName ?? currentSession?.customer?.firstName ?? currentSession?.accountData?.firstName ?? "",
|
|
925
|
+
lastName: prepared?.accountPatch?.lastName ?? currentSession?.customer?.lastName ?? currentSession?.accountData?.lastName ?? "",
|
|
926
|
+
country: prepared?.accountPatch?.country ?? currentSession?.customer?.country ?? currentSession?.accountData?.country ?? void 0,
|
|
927
|
+
zip: prepared?.accountPatch?.zip ?? currentSession?.customer?.zip ?? currentSession?.accountData?.zip ?? void 0
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
);
|
|
931
|
+
if (response.ok) {
|
|
932
|
+
onCompleteRef.current?.({ status: "succeeded", checkoutMethod: "paypal" });
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const json = await response.json().catch(() => null);
|
|
936
|
+
const message = json?.["message"] ?? "PayPal payment failed.";
|
|
937
|
+
forwardError(message);
|
|
938
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
|
|
939
|
+
code: json?.["code"],
|
|
940
|
+
declineCode: json?.["declineCode"]
|
|
941
|
+
}));
|
|
942
|
+
} catch (err) {
|
|
943
|
+
const message = err instanceof Error ? err.message : "PayPal payment failed.";
|
|
944
|
+
forwardError(message);
|
|
945
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message));
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
const createPaypalIntent = async (fallbackMessage) => {
|
|
949
|
+
const prepared = beforeClickRef.current;
|
|
950
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
951
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? emailRef.current;
|
|
952
|
+
const response = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
953
|
+
method: "POST",
|
|
954
|
+
headers: { "Content-Type": "application/json" },
|
|
955
|
+
body: JSON.stringify({
|
|
956
|
+
sessionId: effectiveSessionId,
|
|
957
|
+
email: effectiveEmail,
|
|
958
|
+
paymentMethodType: "paypal",
|
|
959
|
+
isPaypal: "true"
|
|
960
|
+
})
|
|
961
|
+
});
|
|
962
|
+
const json = await response.json().catch(() => null);
|
|
963
|
+
if (!response.ok) {
|
|
964
|
+
throw new Error(json?.message ?? fallbackMessage);
|
|
965
|
+
}
|
|
966
|
+
const id = json?.data?.id;
|
|
967
|
+
if (!id) {
|
|
968
|
+
throw new Error(fallbackMessage);
|
|
969
|
+
}
|
|
970
|
+
return id;
|
|
971
|
+
};
|
|
972
|
+
appendDebug("loadScript:scheduled (deferred 1 tick)");
|
|
973
|
+
let loadPromise = null;
|
|
974
|
+
const startTimer = setTimeout(() => {
|
|
975
|
+
if (cancelled) {
|
|
976
|
+
appendDebug("loadScript:skipped (cancelled before defer ran)");
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
appendDebug("loadScript:start");
|
|
980
|
+
const paypalSdkEnv = normalizedEnv === "live" ? "production" : normalizedEnv;
|
|
981
|
+
loadPromise = (0, import_paypal_js.loadScript)({
|
|
982
|
+
clientId,
|
|
983
|
+
currency,
|
|
984
|
+
// Subscriptions need the `subscription` vault intent; one-time payments
|
|
985
|
+
// use a standard order capture.
|
|
986
|
+
intent: isSubscription ? "subscription" : "capture",
|
|
987
|
+
vault: isSubscription ? true : void 0,
|
|
988
|
+
// Tell PayPal which environment the clientId belongs to. Without
|
|
989
|
+
// this, PayPal defaults to live endpoints — and a sandbox clientId
|
|
990
|
+
// sent to live silently stalls in zoid's prerender forever (no
|
|
991
|
+
// error, no rejection).
|
|
992
|
+
...paypalSdkEnv ? { environment: paypalSdkEnv } : {},
|
|
993
|
+
// Namespace the sandbox SDK so it can coexist with a production SDK on
|
|
994
|
+
// the same page without clobbering `window.paypal`.
|
|
995
|
+
...paypalSdkEnv === "sandbox" ? { dataNamespace: "paypal_sandbox" } : {}
|
|
996
|
+
});
|
|
997
|
+
loadPromise.then((paypal) => {
|
|
998
|
+
appendDebug(`loadScript:resolved cancelled=${cancelled} ns=${!!paypal} buttons=${!!paypal?.Buttons}`);
|
|
999
|
+
if (cancelled || !paypal?.Buttons) {
|
|
1000
|
+
if (!cancelled && !paypal?.Buttons) appendDebug("FAIL: namespace missing Buttons factory");
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const handleApprove = async (data) => {
|
|
1004
|
+
try {
|
|
1005
|
+
setSubmitting(true);
|
|
1006
|
+
onErrorChangeRef.current?.(null);
|
|
1007
|
+
const token = data.subscriptionID ?? data.orderID ?? "";
|
|
1008
|
+
if (!token) {
|
|
1009
|
+
throw new import_shared4.FloPayError(
|
|
1010
|
+
"PayPal did not return an approval token.",
|
|
1011
|
+
"api_error",
|
|
1012
|
+
{ code: "paypal_missing_token" }
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
await dispatchTokenizedBody({
|
|
1016
|
+
id: token,
|
|
1017
|
+
isPaypal: true
|
|
1018
|
+
});
|
|
1019
|
+
} catch (err) {
|
|
1020
|
+
forwardError(err instanceof Error ? err.message : "PayPal capture failed.");
|
|
1021
|
+
} finally {
|
|
1022
|
+
setSubmitting(false);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
const buttons = paypal.Buttons({
|
|
1026
|
+
style: { layout: "horizontal", height: DEFAULT_BUTTON_HEIGHT, tagline: false },
|
|
1027
|
+
// PayPal's SDK awaits a Promise returned from `onClick` and aborts
|
|
1028
|
+
// the create-order/create-subscription step when `actions.reject()`
|
|
1029
|
+
// is invoked. Run the consumer's `runBeforeButtonClick` here so
|
|
1030
|
+
// inline-session/account patches land before the order is created,
|
|
1031
|
+
// matching the Stripe-rendered PayPal flow.
|
|
1032
|
+
onClick: async (_data, actions) => {
|
|
1033
|
+
const runner = runBeforeButtonClickRef.current;
|
|
1034
|
+
if (runner) {
|
|
1035
|
+
try {
|
|
1036
|
+
const beforeClick = await runner("paypal");
|
|
1037
|
+
if (!beforeClick.proceed) {
|
|
1038
|
+
beforeClickRef.current = null;
|
|
1039
|
+
await actions.reject();
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
beforeClickRef.current = {
|
|
1043
|
+
sessionId: beforeClick.sessionId,
|
|
1044
|
+
accountPatch: beforeClick.accountPatch
|
|
1045
|
+
};
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
appendDebug(`onClick:runBeforeButtonClick rejected msg=${(err instanceof Error ? err.message : String(err)).slice(0, 120)}`);
|
|
1048
|
+
beforeClickRef.current = null;
|
|
1049
|
+
await actions.reject();
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
} else {
|
|
1053
|
+
beforeClickRef.current = null;
|
|
1054
|
+
}
|
|
1055
|
+
onButtonClickRef.current?.("paypal");
|
|
1056
|
+
await actions.resolve();
|
|
1057
|
+
},
|
|
1058
|
+
// When the SDK is already holding an order/subscription id from a
|
|
1059
|
+
// prior backend round-trip (the `paypal_direct_required` retry
|
|
1060
|
+
// path), feed it straight to PayPal instead of creating a new one.
|
|
1061
|
+
// Otherwise fall back to the normal create-intent call.
|
|
1062
|
+
createOrder: isSubscription ? void 0 : existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal order."),
|
|
1063
|
+
createSubscription: isSubscription ? existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal subscription.") : void 0,
|
|
1064
|
+
onApprove: handleApprove,
|
|
1065
|
+
onCancel: () => {
|
|
1066
|
+
beforeClickRef.current = null;
|
|
1067
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
1068
|
+
},
|
|
1069
|
+
onError: (err) => {
|
|
1070
|
+
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1071
|
+
appendDebug(`onError rendered=${rendered} msg=${message.slice(0, 120)}`);
|
|
1072
|
+
if (rendered) {
|
|
1073
|
+
forwardError(message);
|
|
1074
|
+
onDeclineRef.current?.(buildDeclineEvent("paypal", message));
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
markRenderFailed(message);
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
const eligible = buttons.isEligible();
|
|
1081
|
+
appendDebug(`isEligible=${eligible}`);
|
|
1082
|
+
if (!eligible) {
|
|
1083
|
+
setReady(false);
|
|
1084
|
+
markRenderFailed(
|
|
1085
|
+
"PayPal buttons are not eligible to render in this context (paypal_ineligible)."
|
|
1086
|
+
);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const typedButtons = buttons;
|
|
1090
|
+
if (debug) {
|
|
1091
|
+
appendDebug(`container:dims ${formatDims(container)} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"}`);
|
|
1092
|
+
}
|
|
1093
|
+
if (debug && typeof MutationObserver !== "undefined") {
|
|
1094
|
+
containerObserver = new MutationObserver((mutations) => {
|
|
1095
|
+
for (const mutation of mutations) {
|
|
1096
|
+
if (mutation.type === "childList") {
|
|
1097
|
+
mutation.addedNodes.forEach((node) => {
|
|
1098
|
+
if (!(node instanceof Element)) return;
|
|
1099
|
+
const tag = node.tagName.toLowerCase();
|
|
1100
|
+
const title = (node.getAttribute("title") ?? "").slice(0, 40);
|
|
1101
|
+
const detail = tag === "iframe" ? ` ${describeIframe(node)}` : "";
|
|
1102
|
+
appendDebug(`child+ ${tag}${title ? ` title="${title}"` : ""}${detail} dims=${formatDims(node)}`);
|
|
1103
|
+
});
|
|
1104
|
+
} else if (mutation.type === "attributes" && mutation.target instanceof Element) {
|
|
1105
|
+
const target = mutation.target;
|
|
1106
|
+
if (target.tagName.toLowerCase() !== "iframe") continue;
|
|
1107
|
+
const attr = mutation.attributeName;
|
|
1108
|
+
if (attr === "src" || attr === "srcdoc") {
|
|
1109
|
+
appendDebug(`attr~ iframe ${attr}=${attr === "srcdoc" ? `[${(target.getAttribute("srcdoc") ?? "").length}ch]` : classifyIframeSrc(target.getAttribute("src"))} dims=${formatDims(target)}`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
containerObserver.observe(container, {
|
|
1115
|
+
childList: true,
|
|
1116
|
+
subtree: true,
|
|
1117
|
+
attributes: true,
|
|
1118
|
+
attributeFilter: ["src", "srcdoc"]
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
const snapshotContainer = (when) => {
|
|
1122
|
+
if (cancelled || rendered) return;
|
|
1123
|
+
const iframes = container.querySelectorAll("iframe");
|
|
1124
|
+
const hasStorageAccess = typeof document !== "undefined" && "hasStorageAccess" in document;
|
|
1125
|
+
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}`);
|
|
1126
|
+
iframes.forEach((frame, i) => {
|
|
1127
|
+
const title = (frame.getAttribute("title") ?? "").slice(0, 40);
|
|
1128
|
+
appendDebug(` iframe[${i}] ${formatDims(frame)}${title ? ` title="${title}"` : ""} ${describeIframe(frame)}`);
|
|
1129
|
+
const content = inspectFrameContent(frame);
|
|
1130
|
+
if (content) appendDebug(` ${content}`);
|
|
1131
|
+
});
|
|
1132
|
+
if (errorMessages.length === 0) {
|
|
1133
|
+
appendDebug(` (no PayPal/zoid window errors captured)`);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
if (debug) {
|
|
1137
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("3s"), 3e3));
|
|
1138
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("8s"), 8e3));
|
|
1139
|
+
watchdogTimers.push(setTimeout(() => snapshotContainer("15s"), 15e3));
|
|
1140
|
+
}
|
|
1141
|
+
appendDebug("render:start");
|
|
1142
|
+
buttons.render(container).then(() => {
|
|
1143
|
+
appendDebug(`render:resolved cancelled=${cancelled}`);
|
|
1144
|
+
stopDiagnostics();
|
|
1145
|
+
if (cancelled) {
|
|
1146
|
+
typedButtons.close().catch(() => {
|
|
1147
|
+
});
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
activeButtons = typedButtons;
|
|
1151
|
+
rendered = true;
|
|
1152
|
+
setReady(true);
|
|
1153
|
+
}).catch((err) => {
|
|
1154
|
+
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1155
|
+
appendDebug(`render:rejected msg=${message.slice(0, 120)}`);
|
|
1156
|
+
stopDiagnostics();
|
|
1157
|
+
markRenderFailed(message);
|
|
1158
|
+
});
|
|
1159
|
+
}).catch((err) => {
|
|
1160
|
+
const message = err instanceof Error ? err.message : "PayPal SDK failed to load.";
|
|
1161
|
+
appendDebug(`loadScript:rejected msg=${message.slice(0, 120)}`);
|
|
1162
|
+
markRenderFailed(message);
|
|
1163
|
+
});
|
|
1164
|
+
}, 0);
|
|
1165
|
+
return () => {
|
|
1166
|
+
cancelled = true;
|
|
1167
|
+
clearTimeout(startTimer);
|
|
1168
|
+
stopDiagnostics();
|
|
1169
|
+
if (activeButtons) {
|
|
1170
|
+
activeButtons.close().catch(() => {
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
}, [baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId]);
|
|
1175
|
+
const debugPanel = debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1176
|
+
"pre",
|
|
1177
|
+
{
|
|
1178
|
+
"data-testid": "flopay-direct-paypal-debug",
|
|
1179
|
+
style: {
|
|
1180
|
+
margin: "0 0 8px 0",
|
|
1181
|
+
padding: "6px 8px",
|
|
1182
|
+
background: failed ? "#fef2f2" : "#f3f4f6",
|
|
1183
|
+
border: `1px solid ${failed ? "#fca5a5" : "#d1d5db"}`,
|
|
1184
|
+
borderRadius: 6,
|
|
1185
|
+
color: "#111827",
|
|
1186
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
1187
|
+
whiteSpace: "pre-wrap",
|
|
1188
|
+
wordBreak: "break-word",
|
|
1189
|
+
maxHeight: 220,
|
|
1190
|
+
overflowY: "auto"
|
|
1191
|
+
},
|
|
1192
|
+
children: [
|
|
1193
|
+
`FloPay/DirectPayPal-debug (ready=${ready} failed=${failed})`,
|
|
1194
|
+
debugLines.length === 0 ? "\n(waiting for first lifecycle event\u2026)" : `
|
|
1195
|
+
${debugLines.join("\n")}`
|
|
1196
|
+
]
|
|
1197
|
+
}
|
|
1198
|
+
) : null;
|
|
1199
|
+
if (failed) {
|
|
1200
|
+
return debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: debugPanel }) : null;
|
|
1201
|
+
}
|
|
1202
|
+
return (
|
|
1203
|
+
// Single wrapper so the parent flex container sees exactly one flex item
|
|
1204
|
+
// (otherwise the fragment's placeholder + container become two siblings
|
|
1205
|
+
// and any spacing-sensitive layout has to reason about both). The wrapper
|
|
1206
|
+
// intentionally has no margin/padding so the parent owns all spacing.
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1208
|
+
debugPanel,
|
|
1209
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT }, children: [
|
|
1210
|
+
!ready && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1211
|
+
"div",
|
|
1212
|
+
{
|
|
1213
|
+
"data-testid": "flopay-direct-paypal-placeholder",
|
|
1214
|
+
style: {
|
|
1215
|
+
position: "absolute",
|
|
1216
|
+
inset: 0,
|
|
1217
|
+
borderRadius: 8,
|
|
1218
|
+
background: "#e5e7eb",
|
|
1219
|
+
animation: "flopay-pulse 1.5s ease-in-out infinite",
|
|
1220
|
+
pointerEvents: "none"
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
),
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1225
|
+
"div",
|
|
1226
|
+
{
|
|
1227
|
+
ref: containerRef,
|
|
1228
|
+
"data-testid": "flopay-direct-paypal-container",
|
|
1229
|
+
style: {
|
|
1230
|
+
minHeight: DEFAULT_BUTTON_HEIGHT,
|
|
1231
|
+
display: "flex",
|
|
1232
|
+
opacity: ready ? 1 : 0
|
|
1233
|
+
},
|
|
1234
|
+
"aria-busy": submitting || isProcessing
|
|
1235
|
+
}
|
|
1236
|
+
)
|
|
1237
|
+
] })
|
|
1238
|
+
] })
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/split-card-form.tsx
|
|
1243
|
+
var import_shared6 = require("@flopay/shared");
|
|
1244
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
694
1245
|
var WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
695
1246
|
var FLOPAY_KEYFRAMES = `
|
|
1247
|
+
.paypal-buttons { margin: 0 !important; vertical-align: top !important; }
|
|
696
1248
|
@keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
697
1249
|
@keyframes flopay-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
|
|
698
1250
|
@keyframes flopay-buttons-enter {
|
|
@@ -726,13 +1278,13 @@ function getButtonMethodLabel(method) {
|
|
|
726
1278
|
}
|
|
727
1279
|
}
|
|
728
1280
|
function normalizeBeforeButtonClickError(method, err) {
|
|
729
|
-
return err instanceof
|
|
1281
|
+
return err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(
|
|
730
1282
|
err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
|
|
731
1283
|
"validation_error"
|
|
732
1284
|
);
|
|
733
1285
|
}
|
|
734
1286
|
function FloPayKeyframes() {
|
|
735
|
-
return /* @__PURE__ */ (0,
|
|
1287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: FLOPAY_KEYFRAMES });
|
|
736
1288
|
}
|
|
737
1289
|
function toCssSize(value) {
|
|
738
1290
|
if (typeof value === "number") return `${value}px`;
|
|
@@ -753,8 +1305,8 @@ function ExpressCheckoutReadySwap({
|
|
|
753
1305
|
children
|
|
754
1306
|
}) {
|
|
755
1307
|
if (state === "unavailable" || state === "load_error") return null;
|
|
756
|
-
return /* @__PURE__ */ (0,
|
|
757
|
-
/* @__PURE__ */ (0,
|
|
1308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
758
1310
|
"div",
|
|
759
1311
|
{
|
|
760
1312
|
"data-testid": placeholderTestId,
|
|
@@ -773,7 +1325,7 @@ function ExpressCheckoutReadySwap({
|
|
|
773
1325
|
}
|
|
774
1326
|
}
|
|
775
1327
|
),
|
|
776
|
-
/* @__PURE__ */ (0,
|
|
1328
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
777
1329
|
"div",
|
|
778
1330
|
{
|
|
779
1331
|
style: {
|
|
@@ -791,9 +1343,9 @@ function ExpressCheckoutReadySwap({
|
|
|
791
1343
|
function isExpressCheckoutRowVisible(state) {
|
|
792
1344
|
return state !== "unavailable" && state !== "load_error";
|
|
793
1345
|
}
|
|
794
|
-
var SplitCardForm = (0,
|
|
1346
|
+
var SplitCardForm = (0, import_react8.forwardRef)(
|
|
795
1347
|
function SplitCardForm2(props, ref) {
|
|
796
|
-
return /* @__PURE__ */ (0,
|
|
1348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
|
|
797
1349
|
}
|
|
798
1350
|
);
|
|
799
1351
|
function PayPalButtonInner({
|
|
@@ -810,15 +1362,15 @@ function PayPalButtonInner({
|
|
|
810
1362
|
}) {
|
|
811
1363
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
812
1364
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
813
|
-
const [loadState, setLoadState] = (0,
|
|
814
|
-
(0,
|
|
1365
|
+
const [loadState, setLoadState] = (0, import_react8.useState)("loading");
|
|
1366
|
+
(0, import_react8.useEffect)(() => {
|
|
815
1367
|
onLoadStateChange?.(loadState);
|
|
816
1368
|
}, [loadState, onLoadStateChange]);
|
|
817
|
-
const [submitting, setSubmitting] = (0,
|
|
818
|
-
const paypalResumeAttempted = (0,
|
|
819
|
-
const beforeClickRef = (0,
|
|
1369
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1370
|
+
const paypalResumeAttempted = (0, import_react8.useRef)(false);
|
|
1371
|
+
const beforeClickRef = (0, import_react8.useRef)(null);
|
|
820
1372
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
821
|
-
(0,
|
|
1373
|
+
(0, import_react8.useEffect)(() => {
|
|
822
1374
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
823
1375
|
const params = new URLSearchParams(window.location.search);
|
|
824
1376
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -865,7 +1417,7 @@ function PayPalButtonInner({
|
|
|
865
1417
|
}
|
|
866
1418
|
})();
|
|
867
1419
|
}, [stripe, onTokenizedBody, onErrorChange, onDecline]);
|
|
868
|
-
const handlePayPalClick = (0,
|
|
1420
|
+
const handlePayPalClick = (0, import_react8.useCallback)(async (event) => {
|
|
869
1421
|
if (isProcessing || submitting) {
|
|
870
1422
|
event.reject();
|
|
871
1423
|
return;
|
|
@@ -883,7 +1435,7 @@ function PayPalButtonInner({
|
|
|
883
1435
|
onButtonClick?.("paypal");
|
|
884
1436
|
event.resolve();
|
|
885
1437
|
}, [isProcessing, onButtonClick, runBeforeButtonClick, submitting]);
|
|
886
|
-
const handlePayPalConfirm = (0,
|
|
1438
|
+
const handlePayPalConfirm = (0, import_react8.useCallback)(async (event) => {
|
|
887
1439
|
if (!stripe || !elements) return;
|
|
888
1440
|
let prepared = beforeClickRef.current;
|
|
889
1441
|
beforeClickRef.current = null;
|
|
@@ -975,8 +1527,8 @@ function PayPalButtonInner({
|
|
|
975
1527
|
setSubmitting(false);
|
|
976
1528
|
}
|
|
977
1529
|
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
|
|
978
|
-
return /* @__PURE__ */ (0,
|
|
979
|
-
/* @__PURE__ */ (0,
|
|
1530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1531
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
980
1532
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
981
1533
|
{
|
|
982
1534
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
@@ -1001,7 +1553,7 @@ function PayPalButtonInner({
|
|
|
1001
1553
|
}
|
|
1002
1554
|
}
|
|
1003
1555
|
) }),
|
|
1004
|
-
submitting && /* @__PURE__ */ (0,
|
|
1556
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1005
1557
|
] });
|
|
1006
1558
|
}
|
|
1007
1559
|
function WalletButtonInner({
|
|
@@ -1019,15 +1571,15 @@ function WalletButtonInner({
|
|
|
1019
1571
|
}) {
|
|
1020
1572
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
1021
1573
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
1022
|
-
const [loadState, setLoadState] = (0,
|
|
1023
|
-
(0,
|
|
1574
|
+
const [loadState, setLoadState] = (0, import_react8.useState)("loading");
|
|
1575
|
+
(0, import_react8.useEffect)(() => {
|
|
1024
1576
|
onLoadStateChange?.(loadState);
|
|
1025
1577
|
}, [loadState, onLoadStateChange]);
|
|
1026
|
-
const [submitting, setSubmitting] = (0,
|
|
1578
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1027
1579
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1028
|
-
const lastWalletMethodRef = (0,
|
|
1029
|
-
const beforeClickRef = (0,
|
|
1030
|
-
const handleWalletConfirm = (0,
|
|
1580
|
+
const lastWalletMethodRef = (0, import_react8.useRef)("card");
|
|
1581
|
+
const beforeClickRef = (0, import_react8.useRef)(null);
|
|
1582
|
+
const handleWalletConfirm = (0, import_react8.useCallback)(
|
|
1031
1583
|
async (event) => {
|
|
1032
1584
|
if (!stripe || !elements) return;
|
|
1033
1585
|
const walletType = event.expressPaymentType;
|
|
@@ -1116,12 +1668,16 @@ function WalletButtonInner({
|
|
|
1116
1668
|
},
|
|
1117
1669
|
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
|
|
1118
1670
|
);
|
|
1119
|
-
return /* @__PURE__ */ (0,
|
|
1120
|
-
/* @__PURE__ */ (0,
|
|
1671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1121
1673
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
1122
1674
|
{
|
|
1123
|
-
onReady: (event) =>
|
|
1124
|
-
|
|
1675
|
+
onReady: (event) => {
|
|
1676
|
+
setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"]));
|
|
1677
|
+
},
|
|
1678
|
+
onLoadError: (e) => {
|
|
1679
|
+
setLoadState("load_error");
|
|
1680
|
+
},
|
|
1125
1681
|
onClick: async (event) => {
|
|
1126
1682
|
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1127
1683
|
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
|
|
@@ -1156,7 +1712,7 @@ function WalletButtonInner({
|
|
|
1156
1712
|
}
|
|
1157
1713
|
}
|
|
1158
1714
|
) }),
|
|
1159
|
-
submitting && /* @__PURE__ */ (0,
|
|
1715
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1160
1716
|
] });
|
|
1161
1717
|
}
|
|
1162
1718
|
function SplitCardFormInner({
|
|
@@ -1208,55 +1764,64 @@ function SplitCardFormInner({
|
|
|
1208
1764
|
totalAmount = 0,
|
|
1209
1765
|
currency = "usd",
|
|
1210
1766
|
initialCardOpen = false,
|
|
1767
|
+
directPaypal,
|
|
1768
|
+
isSubscription = false,
|
|
1769
|
+
session,
|
|
1770
|
+
debug = false,
|
|
1211
1771
|
innerRef
|
|
1212
1772
|
}) {
|
|
1213
1773
|
const flopay = useFloPay();
|
|
1214
1774
|
const paypalFlopay = usePayPalFloPay();
|
|
1215
1775
|
const elements = useElements();
|
|
1216
|
-
const checkout = (0,
|
|
1776
|
+
const checkout = (0, import_react8.useContext)(CheckoutContext);
|
|
1217
1777
|
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,
|
|
1778
|
+
const [processing, setProcessing] = (0, import_react8.useState)(false);
|
|
1779
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1780
|
+
const [is3DSActive, setIs3DSActive] = (0, import_react8.useState)(false);
|
|
1781
|
+
const [selectedCountry, setSelectedCountry] = (0, import_react8.useState)(countryProp ?? "US");
|
|
1782
|
+
const [zipCode, setZipCode] = (0, import_react8.useState)(zipProp ?? "");
|
|
1783
|
+
const [addressLine1, setAddressLine1] = (0, import_react8.useState)(addressLine1Prop ?? "");
|
|
1784
|
+
const [addressLine2, setAddressLine2] = (0, import_react8.useState)(addressLine2Prop ?? "");
|
|
1785
|
+
const [city, setCity] = (0, import_react8.useState)(cityProp ?? "");
|
|
1786
|
+
const [stateValue, setStateValue] = (0, import_react8.useState)(stateProp ?? "");
|
|
1787
|
+
const [accountPatch, setAccountPatch] = (0, import_react8.useState)({});
|
|
1788
|
+
const zipCodeRef = (0, import_react8.useRef)(zipProp ?? "");
|
|
1789
|
+
const selectedCountryRef = (0, import_react8.useRef)(countryProp ?? "US");
|
|
1790
|
+
const addressLine1Ref = (0, import_react8.useRef)(addressLine1Prop ?? "");
|
|
1791
|
+
const addressLine2Ref = (0, import_react8.useRef)(addressLine2Prop ?? "");
|
|
1792
|
+
const cityRef = (0, import_react8.useRef)(cityProp ?? "");
|
|
1793
|
+
const stateRef = (0, import_react8.useRef)(stateProp ?? "");
|
|
1794
|
+
const avsConfig = (0, import_react8.useMemo)(() => (0, import_shared5.resolveAVSConfig)(enableAVSProp), [enableAVSProp]);
|
|
1235
1795
|
const enableAVS = avsConfig !== null;
|
|
1236
|
-
const [viewState, setViewState] = (0,
|
|
1796
|
+
const [viewState, setViewState] = (0, import_react8.useState)(initialCardOpen ? "card" : "buttons");
|
|
1237
1797
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
1238
1798
|
const TRANSITION_MS = 280;
|
|
1239
|
-
const expandToCard = (0,
|
|
1799
|
+
const expandToCard = (0, import_react8.useCallback)(() => {
|
|
1240
1800
|
setViewState("expanding");
|
|
1241
1801
|
setTimeout(() => setViewState("card"), TRANSITION_MS);
|
|
1242
1802
|
}, []);
|
|
1243
|
-
const collapseToButtons = (0,
|
|
1803
|
+
const collapseToButtons = (0, import_react8.useCallback)(() => {
|
|
1244
1804
|
setViewState("collapsing");
|
|
1245
1805
|
setTimeout(() => setViewState("buttons"), TRANSITION_MS);
|
|
1246
1806
|
}, []);
|
|
1247
|
-
(0,
|
|
1807
|
+
(0, import_react8.useEffect)(() => {
|
|
1248
1808
|
if (layout === "buttons" && initialCardOpen) {
|
|
1249
1809
|
setViewState("card");
|
|
1250
1810
|
}
|
|
1251
1811
|
}, [layout, initialCardOpen]);
|
|
1252
|
-
const [fullName, setFullName] = (0,
|
|
1253
|
-
const [formReady, setFormReady] = (0,
|
|
1254
|
-
const [overlayStatus, setOverlayStatus] = (0,
|
|
1255
|
-
const processingRef = (0,
|
|
1812
|
+
const [fullName, setFullName] = (0, import_react8.useState)("");
|
|
1813
|
+
const [formReady, setFormReady] = (0, import_react8.useState)(false);
|
|
1814
|
+
const [overlayStatus, setOverlayStatus] = (0, import_react8.useState)(null);
|
|
1815
|
+
const processingRef = (0, import_react8.useRef)(false);
|
|
1816
|
+
const [paypalDirectRetry, setPaypalDirectRetry] = (0, import_react8.useState)(null);
|
|
1817
|
+
const paypalDirectRetryRef = (0, import_react8.useRef)(paypalDirectRetry);
|
|
1818
|
+
(0, import_react8.useEffect)(() => {
|
|
1819
|
+
paypalDirectRetryRef.current = paypalDirectRetry;
|
|
1820
|
+
}, [paypalDirectRetry]);
|
|
1256
1821
|
const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
|
|
1257
1822
|
const displayError = externalError ?? error;
|
|
1258
|
-
const bStyles = (0,
|
|
1259
|
-
const base = (0,
|
|
1823
|
+
const bStyles = (0, import_react8.useMemo)(() => {
|
|
1824
|
+
const base = (0, import_shared5.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
1260
1825
|
if (!buttonsStylesOverride) return base;
|
|
1261
1826
|
return {
|
|
1262
1827
|
...base,
|
|
@@ -1273,7 +1838,7 @@ function SplitCardFormInner({
|
|
|
1273
1838
|
const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
|
|
1274
1839
|
const isSelfContained = !onTokenizedBody;
|
|
1275
1840
|
const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
|
|
1276
|
-
const resolvedAccount = (0,
|
|
1841
|
+
const resolvedAccount = (0, import_react8.useMemo)(() => mergeAccountPatch({
|
|
1277
1842
|
userId,
|
|
1278
1843
|
email,
|
|
1279
1844
|
firstName,
|
|
@@ -1281,63 +1846,66 @@ function SplitCardFormInner({
|
|
|
1281
1846
|
country: countryProp,
|
|
1282
1847
|
zip: zipProp
|
|
1283
1848
|
}, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
|
|
1284
|
-
const stripeInstance = (0,
|
|
1849
|
+
const stripeInstance = (0, import_react8.useMemo)(() => {
|
|
1285
1850
|
if (!flopay) return null;
|
|
1286
1851
|
return flopay.getRawProvider();
|
|
1287
1852
|
}, [flopay]);
|
|
1288
|
-
const paypalStripeInstance = (0,
|
|
1853
|
+
const paypalStripeInstance = (0, import_react8.useMemo)(() => {
|
|
1289
1854
|
if (!paypalFlopay) return null;
|
|
1290
1855
|
return paypalFlopay.getRawProvider();
|
|
1291
1856
|
}, [paypalFlopay]);
|
|
1292
1857
|
const amountInCents = totalAmount || 100;
|
|
1293
|
-
const walletOptions = (0,
|
|
1858
|
+
const walletOptions = (0, import_react8.useMemo)(() => ({
|
|
1294
1859
|
mode: "payment",
|
|
1295
1860
|
amount: amountInCents,
|
|
1296
1861
|
currency: currency.toLowerCase(),
|
|
1297
1862
|
paymentMethodCreation: "manual",
|
|
1298
1863
|
captureMethod: "manual"
|
|
1299
1864
|
}), [amountInCents, currency]);
|
|
1300
|
-
const paypalOptions = (0,
|
|
1865
|
+
const paypalOptions = (0, import_react8.useMemo)(() => ({
|
|
1301
1866
|
mode: "payment",
|
|
1302
1867
|
amount: amountInCents,
|
|
1303
1868
|
currency: currency.toLowerCase(),
|
|
1304
1869
|
captureMethod: "manual",
|
|
1305
1870
|
setupFutureUsage: "off_session"
|
|
1306
1871
|
}), [amountInCents, currency]);
|
|
1307
|
-
const updateError = (0,
|
|
1872
|
+
const updateError = (0, import_react8.useCallback)(
|
|
1308
1873
|
(err) => {
|
|
1309
1874
|
setError(err);
|
|
1310
1875
|
onErrorChange?.(err);
|
|
1311
1876
|
},
|
|
1312
1877
|
[onErrorChange]
|
|
1313
1878
|
);
|
|
1314
|
-
const emitDecline = (0,
|
|
1879
|
+
const emitDecline = (0, import_react8.useCallback)(
|
|
1315
1880
|
(method, input, overrides) => {
|
|
1316
1881
|
onDecline?.(buildDeclineEvent(method, input, overrides));
|
|
1317
1882
|
},
|
|
1318
1883
|
[onDecline]
|
|
1319
1884
|
);
|
|
1320
1885
|
const showWallets = showApplePay || showGooglePay;
|
|
1321
|
-
const [paypalLoadState, setPaypalLoadState] = (0,
|
|
1322
|
-
const [walletLoadState, setWalletLoadState] = (0,
|
|
1323
|
-
const [
|
|
1324
|
-
(0,
|
|
1886
|
+
const [paypalLoadState, setPaypalLoadState] = (0, import_react8.useState)("loading");
|
|
1887
|
+
const [walletLoadState, setWalletLoadState] = (0, import_react8.useState)("loading");
|
|
1888
|
+
const [directPaypalReady, setDirectPaypalReady] = (0, import_react8.useState)(false);
|
|
1889
|
+
const [inAppBrowserDetected, setInAppBrowserDetected] = (0, import_react8.useState)();
|
|
1890
|
+
(0, import_react8.useEffect)(() => {
|
|
1325
1891
|
setInAppBrowserDetected(isInAppBrowser());
|
|
1326
1892
|
}, []);
|
|
1327
|
-
const
|
|
1328
|
-
const
|
|
1329
|
-
const
|
|
1893
|
+
const directPaypalConfigured = !!directPaypal?.clientId;
|
|
1894
|
+
const shouldShowPayPal = showPayPal && (directPaypalConfigured || inAppBrowserDetected === false);
|
|
1895
|
+
const shouldShowWallets = showWallets;
|
|
1896
|
+
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
1897
|
+
const shouldRenderStripePayPal = shouldShowPayPal && !directPaypalConfigured && !!paypalStripeInstance;
|
|
1330
1898
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
1331
|
-
const shouldDisplayPayPalRow =
|
|
1899
|
+
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
1332
1900
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
1333
|
-
const handleNameChange = (0,
|
|
1901
|
+
const handleNameChange = (0, import_react8.useCallback)((value) => {
|
|
1334
1902
|
setFullName(value);
|
|
1335
1903
|
onFullNameChange?.(value);
|
|
1336
1904
|
const parts = value.trim().split(/\s+/);
|
|
1337
1905
|
onFirstNameChange?.(parts[0] ?? "");
|
|
1338
1906
|
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
1339
1907
|
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
1340
|
-
const applyInlineSessionPatch = (0,
|
|
1908
|
+
const applyInlineSessionPatch = (0, import_react8.useCallback)(
|
|
1341
1909
|
(patch, method) => {
|
|
1342
1910
|
if (!checkout.applyInlineSessionPatch) {
|
|
1343
1911
|
return Promise.resolve({ error: null, sessionId });
|
|
@@ -1354,7 +1922,7 @@ function SplitCardFormInner({
|
|
|
1354
1922
|
},
|
|
1355
1923
|
[checkout.applyInlineSessionPatch, onError, sessionId, updateError]
|
|
1356
1924
|
);
|
|
1357
|
-
const runBeforeButtonClick = (0,
|
|
1925
|
+
const runBeforeButtonClick = (0, import_react8.useCallback)(async (method) => {
|
|
1358
1926
|
if (!onBeforeButtonClick) return { proceed: true };
|
|
1359
1927
|
try {
|
|
1360
1928
|
const result = await onBeforeButtonClick({
|
|
@@ -1390,7 +1958,7 @@ function SplitCardFormInner({
|
|
|
1390
1958
|
return { proceed: false };
|
|
1391
1959
|
}
|
|
1392
1960
|
}, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
|
|
1393
|
-
const processPaymentInternal = (0,
|
|
1961
|
+
const processPaymentInternal = (0, import_react8.useCallback)(
|
|
1394
1962
|
async (tokenizedBody, overrides) => {
|
|
1395
1963
|
if (processingRef.current) return;
|
|
1396
1964
|
processingRef.current = true;
|
|
@@ -1402,7 +1970,7 @@ function SplitCardFormInner({
|
|
|
1402
1970
|
const resolvedCompletionPaymentMethodId = overrides?.completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
|
|
1403
1971
|
const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
|
|
1404
1972
|
try {
|
|
1405
|
-
const api = new
|
|
1973
|
+
const api = new import_js2.PaymentAPI(baseUrl);
|
|
1406
1974
|
const response = await api.processPayment(effectiveAccount.userId ?? "", {
|
|
1407
1975
|
sessionId: effectiveSessionId,
|
|
1408
1976
|
tokenizedData: requestTokenizedBody,
|
|
@@ -1413,18 +1981,18 @@ function SplitCardFormInner({
|
|
|
1413
1981
|
lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
1414
1982
|
...avsConfig ? (() => {
|
|
1415
1983
|
const c = selectedCountryRef.current;
|
|
1416
|
-
const stateVisible = (0,
|
|
1417
|
-
const line1Visible = (0,
|
|
1418
|
-
const zipVisible = (0,
|
|
1419
|
-
const derivedState = line1Visible && !stateVisible && zipVisible ? (0,
|
|
1984
|
+
const stateVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.state, c);
|
|
1985
|
+
const line1Visible = (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, c);
|
|
1986
|
+
const zipVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, c);
|
|
1987
|
+
const derivedState = line1Visible && !stateVisible && zipVisible ? (0, import_shared5.getStateFromPostalCode)(c, zipCodeRef.current ?? "") : null;
|
|
1420
1988
|
const stateValue2 = stateVisible ? stateRef.current : derivedState;
|
|
1421
1989
|
return {
|
|
1422
1990
|
country: c,
|
|
1423
1991
|
...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
|
|
1424
|
-
...(0,
|
|
1992
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, c) && cityRef.current ? { city: cityRef.current } : {},
|
|
1425
1993
|
...stateValue2 ? { state: stateValue2 } : {},
|
|
1426
1994
|
...line1Visible && addressLine1Ref.current ? { addressLine1: addressLine1Ref.current } : {},
|
|
1427
|
-
...(0,
|
|
1995
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, c) && addressLine2Ref.current ? { addressLine2: addressLine2Ref.current } : {}
|
|
1428
1996
|
};
|
|
1429
1997
|
})() : {}
|
|
1430
1998
|
},
|
|
@@ -1436,17 +2004,18 @@ function SplitCardFormInner({
|
|
|
1436
2004
|
// Resolved exposure: which fields were actually shown for the active country.
|
|
1437
2005
|
// Country-scoped rules (e.g. ['US', 'CA']) are flattened to booleans here.
|
|
1438
2006
|
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,
|
|
2007
|
+
country: (0, import_shared5.isAVSFieldVisible)(avsConfig.country, selectedCountryRef.current),
|
|
2008
|
+
postal_code: (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, selectedCountryRef.current),
|
|
2009
|
+
address_line_1: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, selectedCountryRef.current),
|
|
2010
|
+
address_line_2: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, selectedCountryRef.current),
|
|
2011
|
+
city: (0, import_shared5.isAVSFieldVisible)(avsConfig.city, selectedCountryRef.current),
|
|
2012
|
+
state: (0, import_shared5.isAVSFieldVisible)(avsConfig.state, selectedCountryRef.current)
|
|
1445
2013
|
} : void 0
|
|
1446
2014
|
});
|
|
1447
2015
|
if (response.ok) {
|
|
1448
2016
|
markSessionRecentlyCompleted(effectiveSessionId);
|
|
1449
2017
|
setOverlayStatus("success");
|
|
2018
|
+
setPaypalDirectRetry(null);
|
|
1450
2019
|
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
|
|
1451
2020
|
onComplete?.({
|
|
1452
2021
|
status: "succeeded",
|
|
@@ -1470,18 +2039,18 @@ function SplitCardFormInner({
|
|
|
1470
2039
|
const retryCC = selectedCountryRef.current;
|
|
1471
2040
|
const retryCountry = enableAVS ? retryCC : effectiveAccount.country;
|
|
1472
2041
|
if (retryCountry) retryBillingAddress["country"] = retryCountry;
|
|
1473
|
-
if (avsConfig && (0,
|
|
2042
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, retryCC) && zipCodeRef.current.trim()) {
|
|
1474
2043
|
retryBillingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
1475
2044
|
} else if (!avsConfig && effectiveAccount.zip) {
|
|
1476
2045
|
retryBillingAddress["postal_code"] = effectiveAccount.zip;
|
|
1477
2046
|
}
|
|
1478
|
-
if (avsConfig && (0,
|
|
1479
|
-
if (avsConfig && (0,
|
|
1480
|
-
if (avsConfig && (0,
|
|
1481
|
-
if (avsConfig && (0,
|
|
2047
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && addressLine1Ref.current.trim()) retryBillingAddress["line1"] = addressLine1Ref.current.trim();
|
|
2048
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, retryCC) && addressLine2Ref.current.trim()) retryBillingAddress["line2"] = addressLine2Ref.current.trim();
|
|
2049
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, retryCC) && cityRef.current.trim()) retryBillingAddress["city"] = cityRef.current.trim();
|
|
2050
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, retryCC) && stateRef.current.trim()) {
|
|
1482
2051
|
retryBillingAddress["state"] = stateRef.current.trim();
|
|
1483
|
-
} else if (avsConfig && (0,
|
|
1484
|
-
const derivedRetryState = (0,
|
|
2052
|
+
} 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)) {
|
|
2053
|
+
const derivedRetryState = (0, import_shared5.getStateFromPostalCode)(retryCC, zipCodeRef.current.trim());
|
|
1485
2054
|
if (derivedRetryState) retryBillingAddress["state"] = derivedRetryState;
|
|
1486
2055
|
}
|
|
1487
2056
|
const result = await flopay.confirmPayment({
|
|
@@ -1554,6 +2123,24 @@ function SplitCardFormInner({
|
|
|
1554
2123
|
}
|
|
1555
2124
|
return;
|
|
1556
2125
|
}
|
|
2126
|
+
if (json?.type === "paypal_direct_required") {
|
|
2127
|
+
const orderId = json["orderId"];
|
|
2128
|
+
if (!orderId) {
|
|
2129
|
+
setOverlayStatus("error");
|
|
2130
|
+
updateError("PayPal retry required but no order id provided.");
|
|
2131
|
+
return;
|
|
2132
|
+
}
|
|
2133
|
+
const prevAttempts = paypalDirectRetryRef.current?.attempts ?? 0;
|
|
2134
|
+
if (prevAttempts >= 2) {
|
|
2135
|
+
setOverlayStatus("error");
|
|
2136
|
+
updateError("PayPal payment could not be completed after multiple attempts.");
|
|
2137
|
+
emitDecline("paypal", "paypal_direct_required retry limit exceeded");
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
setPaypalDirectRetry({ orderId, attempts: prevAttempts + 1 });
|
|
2141
|
+
setOverlayStatus(null);
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
1557
2144
|
setOverlayStatus("error");
|
|
1558
2145
|
const message = json?.message ?? "Payment failed. Please try again.";
|
|
1559
2146
|
updateError(message);
|
|
@@ -1574,7 +2161,7 @@ function SplitCardFormInner({
|
|
|
1574
2161
|
},
|
|
1575
2162
|
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
|
|
1576
2163
|
);
|
|
1577
|
-
const dispatchTokenizedBody = (0,
|
|
2164
|
+
const dispatchTokenizedBody = (0, import_react8.useCallback)(
|
|
1578
2165
|
(tokenizedBody, overrides) => {
|
|
1579
2166
|
if (onTokenizedBody) {
|
|
1580
2167
|
onTokenizedBody(tokenizedBody);
|
|
@@ -1584,7 +2171,7 @@ function SplitCardFormInner({
|
|
|
1584
2171
|
},
|
|
1585
2172
|
[onTokenizedBody, processPaymentInternal]
|
|
1586
2173
|
);
|
|
1587
|
-
(0,
|
|
2174
|
+
(0, import_react8.useImperativeHandle)(innerRef, () => ({
|
|
1588
2175
|
async handleNextAction(secret) {
|
|
1589
2176
|
if (!flopay) return;
|
|
1590
2177
|
setIs3DSActive(true);
|
|
@@ -1611,7 +2198,7 @@ function SplitCardFormInner({
|
|
|
1611
2198
|
}
|
|
1612
2199
|
}
|
|
1613
2200
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
1614
|
-
(0,
|
|
2201
|
+
(0, import_react8.useEffect)(() => {
|
|
1615
2202
|
if (typeof window === "undefined") return;
|
|
1616
2203
|
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
1617
2204
|
if (!stored) return;
|
|
@@ -1629,7 +2216,7 @@ function SplitCardFormInner({
|
|
|
1629
2216
|
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
1630
2217
|
}
|
|
1631
2218
|
}, [sessionId, dispatchTokenizedBody]);
|
|
1632
|
-
const handleSubmit = (0,
|
|
2219
|
+
const handleSubmit = (0, import_react8.useCallback)(
|
|
1633
2220
|
async (e) => {
|
|
1634
2221
|
e.preventDefault();
|
|
1635
2222
|
if (!flopay || !elements || isSubmitting || processingRef.current) return;
|
|
@@ -1643,20 +2230,20 @@ function SplitCardFormInner({
|
|
|
1643
2230
|
try {
|
|
1644
2231
|
if (avsConfig) {
|
|
1645
2232
|
const country = selectedCountryRef.current;
|
|
1646
|
-
if ((0,
|
|
1647
|
-
updateError((0,
|
|
2233
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, country) && !zipCodeRef.current.trim()) {
|
|
2234
|
+
updateError((0, import_shared5.getPostalCodeLabel)(country) + " is required");
|
|
1648
2235
|
return;
|
|
1649
2236
|
}
|
|
1650
|
-
if ((0,
|
|
2237
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
|
|
1651
2238
|
updateError("Street address is required");
|
|
1652
2239
|
return;
|
|
1653
2240
|
}
|
|
1654
|
-
if ((0,
|
|
2241
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.city, country) && !cityRef.current.trim()) {
|
|
1655
2242
|
updateError("City is required");
|
|
1656
2243
|
return;
|
|
1657
2244
|
}
|
|
1658
|
-
if ((0,
|
|
1659
|
-
updateError((0,
|
|
2245
|
+
if ((0, import_shared5.isAVSFieldVisible)(avsConfig.state, country) && !stateRef.current.trim()) {
|
|
2246
|
+
updateError((0, import_shared5.getStateLabel)(country) + " is required");
|
|
1660
2247
|
return;
|
|
1661
2248
|
}
|
|
1662
2249
|
}
|
|
@@ -1670,18 +2257,18 @@ function SplitCardFormInner({
|
|
|
1670
2257
|
const cc = selectedCountryRef.current;
|
|
1671
2258
|
const avsCountry = enableAVS ? cc : resolvedAccount.country;
|
|
1672
2259
|
if (avsCountry) billingAddress["country"] = avsCountry;
|
|
1673
|
-
if (avsConfig && (0,
|
|
2260
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && zipCodeRef.current.trim()) {
|
|
1674
2261
|
billingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
1675
2262
|
} else if (!avsConfig && resolvedAccount.zip) {
|
|
1676
2263
|
billingAddress["postal_code"] = resolvedAccount.zip;
|
|
1677
2264
|
}
|
|
1678
|
-
if (avsConfig && (0,
|
|
1679
|
-
if (avsConfig && (0,
|
|
1680
|
-
if (avsConfig && (0,
|
|
1681
|
-
if (avsConfig && (0,
|
|
2265
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && addressLine1Ref.current.trim()) billingAddress["line1"] = addressLine1Ref.current.trim();
|
|
2266
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, cc) && addressLine2Ref.current.trim()) billingAddress["line2"] = addressLine2Ref.current.trim();
|
|
2267
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && cityRef.current.trim()) billingAddress["city"] = cityRef.current.trim();
|
|
2268
|
+
if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && stateRef.current.trim()) {
|
|
1682
2269
|
billingAddress["state"] = stateRef.current.trim();
|
|
1683
|
-
} else if (avsConfig && (0,
|
|
1684
|
-
const derivedSubmitState = (0,
|
|
2270
|
+
} 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)) {
|
|
2271
|
+
const derivedSubmitState = (0, import_shared5.getStateFromPostalCode)(cc, zipCodeRef.current.trim());
|
|
1685
2272
|
if (derivedSubmitState) billingAddress["state"] = derivedSubmitState;
|
|
1686
2273
|
}
|
|
1687
2274
|
const billingDetails = {
|
|
@@ -1695,7 +2282,7 @@ function SplitCardFormInner({
|
|
|
1695
2282
|
return;
|
|
1696
2283
|
}
|
|
1697
2284
|
if (!sessionId || !resolvedAccount.email) {
|
|
1698
|
-
throw new
|
|
2285
|
+
throw new import_shared6.FloPayError("Missing sessionId or email", "validation_error");
|
|
1699
2286
|
}
|
|
1700
2287
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
1701
2288
|
method: "POST",
|
|
@@ -1721,7 +2308,7 @@ function SplitCardFormInner({
|
|
|
1721
2308
|
}
|
|
1722
2309
|
const intentJson = await intentResponse.json();
|
|
1723
2310
|
const intentClientSecret = intentJson.data?.id;
|
|
1724
|
-
if (!intentClientSecret) throw new
|
|
2311
|
+
if (!intentClientSecret) throw new import_shared6.FloPayError("No client_secret in payment intent response", "api_error");
|
|
1725
2312
|
const confirmResult = await flopay.confirmCardPayment({
|
|
1726
2313
|
clientSecret: intentClientSecret,
|
|
1727
2314
|
paymentMethodId: pmResult.paymentMethodId
|
|
@@ -1742,7 +2329,7 @@ function SplitCardFormInner({
|
|
|
1742
2329
|
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
1743
2330
|
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
1744
2331
|
if (!paymentIntentId) {
|
|
1745
|
-
const error2 = new
|
|
2332
|
+
const error2 = new import_shared6.FloPayError("No payment intent returned after confirmation.", "api_error");
|
|
1746
2333
|
setOverlayStatus("error");
|
|
1747
2334
|
updateError(error2.message);
|
|
1748
2335
|
onError?.(error2);
|
|
@@ -1771,7 +2358,7 @@ function SplitCardFormInner({
|
|
|
1771
2358
|
);
|
|
1772
2359
|
const isReady = flopay !== null && elements !== null;
|
|
1773
2360
|
if (!isReady) {
|
|
1774
|
-
return /* @__PURE__ */ (0,
|
|
2361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
|
|
1775
2362
|
}
|
|
1776
2363
|
const isButtons = layout === "buttons";
|
|
1777
2364
|
const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
|
|
@@ -1814,7 +2401,7 @@ function SplitCardFormInner({
|
|
|
1814
2401
|
invalid: { color: "#ef4444" }
|
|
1815
2402
|
}
|
|
1816
2403
|
};
|
|
1817
|
-
const cardFormBlock = /* @__PURE__ */ (0,
|
|
2404
|
+
const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1818
2405
|
backgroundColor: cardBg,
|
|
1819
2406
|
borderRadius: "8px",
|
|
1820
2407
|
padding: isButtons ? "0" : "1rem",
|
|
@@ -1822,7 +2409,7 @@ function SplitCardFormInner({
|
|
|
1822
2409
|
...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
|
|
1823
2410
|
...sharedInputPlaceholderVars
|
|
1824
2411
|
}, children: [
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
2412
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
|
|
1826
2413
|
.flopay-shared-input::placeholder {
|
|
1827
2414
|
color: var(--flopay-input-placeholder-color);
|
|
1828
2415
|
opacity: 1;
|
|
@@ -1831,12 +2418,12 @@ function SplitCardFormInner({
|
|
|
1831
2418
|
font-weight: var(--flopay-input-font-weight);
|
|
1832
2419
|
}
|
|
1833
2420
|
` }),
|
|
1834
|
-
isButtons && showCardForm && /* @__PURE__ */ (0,
|
|
2421
|
+
isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1835
2422
|
display: "flex",
|
|
1836
2423
|
alignItems: "center",
|
|
1837
2424
|
padding: "0.75rem 0 0.625rem"
|
|
1838
2425
|
}, children: [
|
|
1839
|
-
/* @__PURE__ */ (0,
|
|
2426
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1840
2427
|
"button",
|
|
1841
2428
|
{
|
|
1842
2429
|
type: "button",
|
|
@@ -1858,7 +2445,7 @@ function SplitCardFormInner({
|
|
|
1858
2445
|
},
|
|
1859
2446
|
"aria-label": "Back to payment methods",
|
|
1860
2447
|
children: [
|
|
1861
|
-
/* @__PURE__ */ (0,
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
|
|
1862
2449
|
display: "inline-flex",
|
|
1863
2450
|
alignItems: "center",
|
|
1864
2451
|
justifyContent: "center",
|
|
@@ -1868,12 +2455,12 @@ function SplitCardFormInner({
|
|
|
1868
2455
|
backgroundColor: "#f3f4f6",
|
|
1869
2456
|
transition: "background-color 0.15s",
|
|
1870
2457
|
...bStyles.backButtonIcon
|
|
1871
|
-
}, children: /* @__PURE__ */ (0,
|
|
1872
|
-
/* @__PURE__ */ (0,
|
|
2458
|
+
}, 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" }) }) }),
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
1873
2460
|
]
|
|
1874
2461
|
}
|
|
1875
2462
|
),
|
|
1876
|
-
hideTitle ? /* @__PURE__ */ (0,
|
|
2463
|
+
hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1877
2464
|
flex: 1,
|
|
1878
2465
|
textAlign: "center",
|
|
1879
2466
|
fontWeight: 600,
|
|
@@ -1881,18 +2468,18 @@ function SplitCardFormInner({
|
|
|
1881
2468
|
color: "#262833",
|
|
1882
2469
|
paddingRight: 80,
|
|
1883
2470
|
...bStyles.title
|
|
1884
|
-
}, children: /* @__PURE__ */ (0,
|
|
2471
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
|
|
1885
2472
|
] }),
|
|
1886
|
-
!isButtons && !hideTitle && /* @__PURE__ */ (0,
|
|
1887
|
-
/* @__PURE__ */ (0,
|
|
2473
|
+
!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 }) }),
|
|
2474
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1888
2475
|
backgroundColor: cardInputBg,
|
|
1889
2476
|
border: `1px solid ${resolvedBorder}`,
|
|
1890
2477
|
borderTopLeftRadius: "8px",
|
|
1891
2478
|
borderTopRightRadius: "8px",
|
|
1892
2479
|
padding: "10px"
|
|
1893
|
-
}, children: /* @__PURE__ */ (0,
|
|
1894
|
-
/* @__PURE__ */ (0,
|
|
1895
|
-
/* @__PURE__ */ (0,
|
|
2480
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
|
|
2482
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1896
2483
|
flex: 1,
|
|
1897
2484
|
backgroundColor: cardInputBg,
|
|
1898
2485
|
border: `1px solid ${resolvedBorder}`,
|
|
@@ -1900,23 +2487,23 @@ function SplitCardFormInner({
|
|
|
1900
2487
|
borderRight: "none",
|
|
1901
2488
|
borderBottomLeftRadius: "8px",
|
|
1902
2489
|
padding: "10px"
|
|
1903
|
-
}, children: /* @__PURE__ */ (0,
|
|
1904
|
-
/* @__PURE__ */ (0,
|
|
2490
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1905
2492
|
flex: 1,
|
|
1906
2493
|
backgroundColor: cardInputBg,
|
|
1907
2494
|
border: `1px solid ${resolvedBorder}`,
|
|
1908
2495
|
borderTop: "none",
|
|
1909
2496
|
borderBottomRightRadius: "8px",
|
|
1910
2497
|
padding: "10px"
|
|
1911
|
-
}, children: /* @__PURE__ */ (0,
|
|
2498
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardCvcElement, { options: stripeElementStyle }) })
|
|
1912
2499
|
] }),
|
|
1913
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1914
2501
|
backgroundColor: cardInputBg,
|
|
1915
2502
|
border: `1px solid ${resolvedBorder}`,
|
|
1916
2503
|
borderRadius: "8px",
|
|
1917
2504
|
marginTop: "0.5rem",
|
|
1918
2505
|
padding: "10px"
|
|
1919
|
-
}, children: /* @__PURE__ */ (0,
|
|
2506
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1920
2507
|
"input",
|
|
1921
2508
|
{
|
|
1922
2509
|
className: "flopay-shared-input",
|
|
@@ -1954,9 +2541,9 @@ function SplitCardFormInner({
|
|
|
1954
2541
|
...sharedInputTypography,
|
|
1955
2542
|
...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
|
|
1956
2543
|
});
|
|
1957
|
-
const stateOpts = (0,
|
|
1958
|
-
return /* @__PURE__ */ (0,
|
|
1959
|
-
(0,
|
|
2544
|
+
const stateOpts = (0, import_shared5.getStateOptions)(cc);
|
|
2545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2546
|
+
(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
2547
|
"input",
|
|
1961
2548
|
{
|
|
1962
2549
|
className: "flopay-shared-input",
|
|
@@ -1973,7 +2560,7 @@ function SplitCardFormInner({
|
|
|
1973
2560
|
style: inputFieldStyle()
|
|
1974
2561
|
}
|
|
1975
2562
|
) }),
|
|
1976
|
-
(0,
|
|
2563
|
+
(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
2564
|
"input",
|
|
1978
2565
|
{
|
|
1979
2566
|
className: "flopay-shared-input",
|
|
@@ -1989,21 +2576,21 @@ function SplitCardFormInner({
|
|
|
1989
2576
|
style: inputFieldStyle()
|
|
1990
2577
|
}
|
|
1991
2578
|
) }),
|
|
1992
|
-
((0,
|
|
2579
|
+
((0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
1993
2580
|
display: "flex",
|
|
1994
2581
|
gap: "0",
|
|
1995
2582
|
marginTop: "0.5rem"
|
|
1996
2583
|
}, children: [
|
|
1997
|
-
(0,
|
|
2584
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
1998
2585
|
flex: 1,
|
|
1999
2586
|
backgroundColor: cardInputBg,
|
|
2000
2587
|
border: `1px solid ${resolvedBorder}`,
|
|
2001
2588
|
padding: "10px",
|
|
2002
2589
|
borderTopLeftRadius: "8px",
|
|
2003
2590
|
borderBottomLeftRadius: "8px",
|
|
2004
|
-
...(0,
|
|
2591
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: "8px" },
|
|
2005
2592
|
...isButtons && bStyles.cityInput ? bStyles.cityInput : {}
|
|
2006
|
-
}, children: /* @__PURE__ */ (0,
|
|
2593
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2007
2594
|
"input",
|
|
2008
2595
|
{
|
|
2009
2596
|
className: "flopay-shared-input",
|
|
@@ -2020,16 +2607,16 @@ function SplitCardFormInner({
|
|
|
2020
2607
|
style: inputFieldStyle()
|
|
2021
2608
|
}
|
|
2022
2609
|
) }),
|
|
2023
|
-
(0,
|
|
2610
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2024
2611
|
flex: 1,
|
|
2025
2612
|
backgroundColor: cardInputBg,
|
|
2026
2613
|
border: `1px solid ${resolvedBorder}`,
|
|
2027
2614
|
padding: "10px",
|
|
2028
2615
|
borderTopRightRadius: "8px",
|
|
2029
2616
|
borderBottomRightRadius: "8px",
|
|
2030
|
-
...(0,
|
|
2617
|
+
...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius: "8px" },
|
|
2031
2618
|
...isButtons && bStyles.stateInput ? bStyles.stateInput : {}
|
|
2032
|
-
}, children: stateOpts ? /* @__PURE__ */ (0,
|
|
2619
|
+
}, children: stateOpts ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2033
2620
|
"select",
|
|
2034
2621
|
{
|
|
2035
2622
|
value: stateValue,
|
|
@@ -2043,15 +2630,15 @@ function SplitCardFormInner({
|
|
|
2043
2630
|
"data-testid": "flopay-state",
|
|
2044
2631
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
2045
2632
|
children: [
|
|
2046
|
-
/* @__PURE__ */ (0,
|
|
2047
|
-
stateOpts.map((s) => /* @__PURE__ */ (0,
|
|
2633
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: (0, import_shared5.getStateLabel)(cc) }),
|
|
2634
|
+
stateOpts.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: s.code, children: s.name }, s.code))
|
|
2048
2635
|
]
|
|
2049
2636
|
}
|
|
2050
|
-
) : /* @__PURE__ */ (0,
|
|
2637
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2051
2638
|
"input",
|
|
2052
2639
|
{
|
|
2053
2640
|
className: "flopay-shared-input",
|
|
2054
|
-
placeholder: (0,
|
|
2641
|
+
placeholder: (0, import_shared5.getStateLabel)(cc),
|
|
2055
2642
|
autoComplete: "address-level1",
|
|
2056
2643
|
value: stateValue,
|
|
2057
2644
|
onChange: (e) => {
|
|
@@ -2065,20 +2652,20 @@ function SplitCardFormInner({
|
|
|
2065
2652
|
}
|
|
2066
2653
|
) })
|
|
2067
2654
|
] }),
|
|
2068
|
-
((0,
|
|
2655
|
+
((0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2069
2656
|
display: "flex",
|
|
2070
2657
|
flexDirection: avsLayoutProp === "column" ? "column" : "row",
|
|
2071
2658
|
gap: avsLayoutProp === "column" ? "0.5rem" : "0",
|
|
2072
2659
|
marginTop: "0.5rem"
|
|
2073
2660
|
}, children: [
|
|
2074
|
-
(0,
|
|
2661
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2075
2662
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2076
2663
|
backgroundColor: cardInputBg,
|
|
2077
2664
|
border: `1px solid ${resolvedBorder}`,
|
|
2078
2665
|
padding: "10px",
|
|
2079
|
-
...avsLayoutProp === "row" && (0,
|
|
2666
|
+
...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
|
|
2080
2667
|
...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
|
|
2081
|
-
}, children: /* @__PURE__ */ (0,
|
|
2668
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2082
2669
|
"select",
|
|
2083
2670
|
{
|
|
2084
2671
|
value: selectedCountry,
|
|
@@ -2093,25 +2680,25 @@ function SplitCardFormInner({
|
|
|
2093
2680
|
autoComplete: "country",
|
|
2094
2681
|
"data-testid": "flopay-country",
|
|
2095
2682
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
2096
|
-
children:
|
|
2683
|
+
children: import_shared5.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: c.code, children: [
|
|
2097
2684
|
c.flag,
|
|
2098
2685
|
" ",
|
|
2099
2686
|
c.name
|
|
2100
2687
|
] }, c.code))
|
|
2101
2688
|
}
|
|
2102
2689
|
) }),
|
|
2103
|
-
(0,
|
|
2690
|
+
(0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2104
2691
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2105
2692
|
backgroundColor: cardInputBg,
|
|
2106
2693
|
border: `1px solid ${resolvedBorder}`,
|
|
2107
2694
|
padding: "10px",
|
|
2108
|
-
...avsLayoutProp === "row" && (0,
|
|
2695
|
+
...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
|
|
2109
2696
|
...isButtons && bStyles.zipInput ? bStyles.zipInput : {}
|
|
2110
|
-
}, children: /* @__PURE__ */ (0,
|
|
2697
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2111
2698
|
"input",
|
|
2112
2699
|
{
|
|
2113
2700
|
className: "flopay-shared-input",
|
|
2114
|
-
placeholder: (0,
|
|
2701
|
+
placeholder: (0, import_shared5.getPostalCodeLabel)(selectedCountry),
|
|
2115
2702
|
autoComplete: "postal-code",
|
|
2116
2703
|
value: zipCode,
|
|
2117
2704
|
onChange: (e) => {
|
|
@@ -2128,7 +2715,7 @@ function SplitCardFormInner({
|
|
|
2128
2715
|
] })
|
|
2129
2716
|
] });
|
|
2130
2717
|
})(),
|
|
2131
|
-
displayError && /* @__PURE__ */ (0,
|
|
2718
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
2132
2719
|
margin: "0.75rem 0",
|
|
2133
2720
|
padding: "0.625rem 0.875rem",
|
|
2134
2721
|
background: "#FEF2F2",
|
|
@@ -2142,10 +2729,10 @@ function SplitCardFormInner({
|
|
|
2142
2729
|
gap: "0.5rem",
|
|
2143
2730
|
...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
2144
2731
|
}, children: [
|
|
2145
|
-
/* @__PURE__ */ (0,
|
|
2732
|
+
/* @__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
2733
|
displayError
|
|
2147
2734
|
] }),
|
|
2148
|
-
children ?? /* @__PURE__ */ (0,
|
|
2735
|
+
children ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2149
2736
|
"button",
|
|
2150
2737
|
{
|
|
2151
2738
|
type: "submit",
|
|
@@ -2168,7 +2755,7 @@ function SplitCardFormInner({
|
|
|
2168
2755
|
children: isSubmitting ? "PROCESSING..." : submitLabel
|
|
2169
2756
|
}
|
|
2170
2757
|
),
|
|
2171
|
-
!isButtons && showSecurityFooter && /* @__PURE__ */ (0,
|
|
2758
|
+
!isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2172
2759
|
backgroundColor: "#EFF9F0",
|
|
2173
2760
|
borderRadius: "8px",
|
|
2174
2761
|
padding: "0.75rem",
|
|
@@ -2185,11 +2772,11 @@ function SplitCardFormInner({
|
|
|
2185
2772
|
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2186
2773
|
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
2774
|
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,
|
|
2775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2776
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
2777
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2778
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "grid" }, children: [
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2193
2780
|
gridArea: "1 / 1",
|
|
2194
2781
|
display: "flex",
|
|
2195
2782
|
flexDirection: "column",
|
|
@@ -2198,7 +2785,75 @@ function SplitCardFormInner({
|
|
|
2198
2785
|
...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
|
|
2199
2786
|
...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
|
|
2200
2787
|
}, children: [
|
|
2201
|
-
|
|
2788
|
+
debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2789
|
+
"pre",
|
|
2790
|
+
{
|
|
2791
|
+
"data-testid": "flopay-direct-paypal-gate-debug",
|
|
2792
|
+
style: {
|
|
2793
|
+
margin: 0,
|
|
2794
|
+
padding: "6px 8px",
|
|
2795
|
+
background: "#eef2ff",
|
|
2796
|
+
border: "1px solid #c7d2fe",
|
|
2797
|
+
borderRadius: 6,
|
|
2798
|
+
color: "#111827",
|
|
2799
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2800
|
+
whiteSpace: "pre-wrap",
|
|
2801
|
+
wordBreak: "break-word"
|
|
2802
|
+
},
|
|
2803
|
+
children: [
|
|
2804
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2805
|
+
` showPayPal=${showPayPal}`,
|
|
2806
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2807
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2808
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2809
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2810
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2811
|
+
].join("\n")
|
|
2812
|
+
}
|
|
2813
|
+
),
|
|
2814
|
+
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2815
|
+
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2816
|
+
"div",
|
|
2817
|
+
{
|
|
2818
|
+
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
2819
|
+
style: {
|
|
2820
|
+
padding: "8px 10px",
|
|
2821
|
+
background: "#fef3c7",
|
|
2822
|
+
border: "1px solid #fcd34d",
|
|
2823
|
+
borderRadius: 6,
|
|
2824
|
+
color: "#78350f",
|
|
2825
|
+
fontSize: 13,
|
|
2826
|
+
lineHeight: 1.4
|
|
2827
|
+
},
|
|
2828
|
+
children: "Please confirm your PayPal payment to complete checkout."
|
|
2829
|
+
}
|
|
2830
|
+
),
|
|
2831
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2832
|
+
DirectPayPalButton,
|
|
2833
|
+
{
|
|
2834
|
+
sessionId,
|
|
2835
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
2836
|
+
email: resolvedAccount.email,
|
|
2837
|
+
clientId: directPaypal.clientId,
|
|
2838
|
+
environment: directPaypal.environment,
|
|
2839
|
+
currency: currency.toUpperCase(),
|
|
2840
|
+
isSubscription,
|
|
2841
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
2842
|
+
onComplete,
|
|
2843
|
+
onErrorChange: updateError,
|
|
2844
|
+
onDecline,
|
|
2845
|
+
onButtonClick,
|
|
2846
|
+
runBeforeButtonClick,
|
|
2847
|
+
isProcessing: isSubmitting,
|
|
2848
|
+
onLoadStateChange: setDirectPaypalReady,
|
|
2849
|
+
session: session ?? null,
|
|
2850
|
+
existingOrderId: paypalDirectRetry?.orderId,
|
|
2851
|
+
debug
|
|
2852
|
+
},
|
|
2853
|
+
paypalDirectRetry?.orderId ?? "fresh"
|
|
2854
|
+
)
|
|
2855
|
+
] }),
|
|
2856
|
+
shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2202
2857
|
PayPalButtonInner,
|
|
2203
2858
|
{
|
|
2204
2859
|
sessionId,
|
|
@@ -2213,7 +2868,7 @@ function SplitCardFormInner({
|
|
|
2213
2868
|
onLoadStateChange: setPaypalLoadState
|
|
2214
2869
|
}
|
|
2215
2870
|
) }),
|
|
2216
|
-
shouldRenderWallets ? /* @__PURE__ */ (0,
|
|
2871
|
+
shouldRenderWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2217
2872
|
WalletButtonInner,
|
|
2218
2873
|
{
|
|
2219
2874
|
sessionId,
|
|
@@ -2228,8 +2883,8 @@ function SplitCardFormInner({
|
|
|
2228
2883
|
runBeforeButtonClick,
|
|
2229
2884
|
onLoadStateChange: setWalletLoadState
|
|
2230
2885
|
}
|
|
2231
|
-
) }) : shouldShowWallets ? /* @__PURE__ */ (0,
|
|
2232
|
-
/* @__PURE__ */ (0,
|
|
2886
|
+
) }) : 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,
|
|
2887
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2233
2888
|
"button",
|
|
2234
2889
|
{
|
|
2235
2890
|
type: "button",
|
|
@@ -2267,10 +2922,10 @@ function SplitCardFormInner({
|
|
|
2267
2922
|
onMouseUp: (e) => {
|
|
2268
2923
|
e.currentTarget.style.transform = "scale(1)";
|
|
2269
2924
|
},
|
|
2270
|
-
children: /* @__PURE__ */ (0,
|
|
2925
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
|
|
2271
2926
|
}
|
|
2272
2927
|
),
|
|
2273
|
-
displayError && viewState === "buttons" && /* @__PURE__ */ (0,
|
|
2928
|
+
displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
2274
2929
|
margin: "0.25rem 0",
|
|
2275
2930
|
padding: "0.625rem 0.875rem",
|
|
2276
2931
|
background: "#FEF2F2",
|
|
@@ -2284,11 +2939,11 @@ function SplitCardFormInner({
|
|
|
2284
2939
|
gap: "0.5rem",
|
|
2285
2940
|
...bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
2286
2941
|
}, children: [
|
|
2287
|
-
/* @__PURE__ */ (0,
|
|
2942
|
+
/* @__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
2943
|
displayError
|
|
2289
2944
|
] })
|
|
2290
2945
|
] }),
|
|
2291
|
-
isCardView && /* @__PURE__ */ (0,
|
|
2946
|
+
isCardView && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2292
2947
|
gridArea: "1 / 1",
|
|
2293
2948
|
...cardAnim ? { animation: cardAnim } : {},
|
|
2294
2949
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
@@ -2296,37 +2951,111 @@ function SplitCardFormInner({
|
|
|
2296
2951
|
] })
|
|
2297
2952
|
] });
|
|
2298
2953
|
}
|
|
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
|
-
|
|
2954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2955
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
2956
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2957
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2958
|
+
debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2959
|
+
"pre",
|
|
2960
|
+
{
|
|
2961
|
+
"data-testid": "flopay-direct-paypal-gate-debug-default",
|
|
2962
|
+
style: {
|
|
2963
|
+
margin: 0,
|
|
2964
|
+
padding: "6px 8px",
|
|
2965
|
+
background: "#eef2ff",
|
|
2966
|
+
border: "1px solid #c7d2fe",
|
|
2967
|
+
borderRadius: 6,
|
|
2968
|
+
color: "#111827",
|
|
2969
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2970
|
+
whiteSpace: "pre-wrap",
|
|
2971
|
+
wordBreak: "break-word"
|
|
2972
|
+
},
|
|
2973
|
+
children: [
|
|
2974
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2975
|
+
` showPayPal=${showPayPal}`,
|
|
2976
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2977
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2978
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2979
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2980
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2981
|
+
].join("\n")
|
|
2982
|
+
}
|
|
2983
|
+
),
|
|
2984
|
+
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2985
|
+
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2986
|
+
"div",
|
|
2987
|
+
{
|
|
2988
|
+
"data-testid": "flopay-paypal-direct-retry-notice-default",
|
|
2989
|
+
style: {
|
|
2990
|
+
padding: "8px 10px",
|
|
2991
|
+
background: "#fef3c7",
|
|
2992
|
+
border: "1px solid #fcd34d",
|
|
2993
|
+
borderRadius: 6,
|
|
2994
|
+
color: "#78350f",
|
|
2995
|
+
fontSize: 13,
|
|
2996
|
+
lineHeight: 1.4
|
|
2997
|
+
},
|
|
2998
|
+
children: "Please confirm your PayPal payment to complete checkout."
|
|
2999
|
+
}
|
|
3000
|
+
),
|
|
3001
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3002
|
+
DirectPayPalButton,
|
|
3003
|
+
{
|
|
3004
|
+
sessionId,
|
|
3005
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3006
|
+
email: resolvedAccount.email,
|
|
3007
|
+
clientId: directPaypal.clientId,
|
|
3008
|
+
environment: directPaypal.environment,
|
|
3009
|
+
currency: currency.toUpperCase(),
|
|
3010
|
+
isSubscription,
|
|
3011
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3012
|
+
onComplete,
|
|
3013
|
+
onErrorChange: updateError,
|
|
3014
|
+
onDecline,
|
|
3015
|
+
onButtonClick,
|
|
3016
|
+
runBeforeButtonClick,
|
|
3017
|
+
isProcessing: isSubmitting,
|
|
3018
|
+
onLoadStateChange: setDirectPaypalReady,
|
|
3019
|
+
session: session ?? null,
|
|
3020
|
+
existingOrderId: paypalDirectRetry?.orderId,
|
|
3021
|
+
debug
|
|
3022
|
+
},
|
|
3023
|
+
paypalDirectRetry?.orderId ?? "fresh"
|
|
3024
|
+
)
|
|
3025
|
+
] }),
|
|
3026
|
+
shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3027
|
+
PayPalButtonInner,
|
|
3028
|
+
{
|
|
3029
|
+
sessionId,
|
|
3030
|
+
email: resolvedAccount.email,
|
|
3031
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3032
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3033
|
+
onErrorChange: updateError,
|
|
3034
|
+
isProcessing: isSubmitting,
|
|
3035
|
+
onButtonClick,
|
|
3036
|
+
onDecline,
|
|
3037
|
+
runBeforeButtonClick,
|
|
3038
|
+
onLoadStateChange: setPaypalLoadState
|
|
3039
|
+
}
|
|
3040
|
+
) }),
|
|
3041
|
+
shouldRenderWallets && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3042
|
+
WalletButtonInner,
|
|
3043
|
+
{
|
|
3044
|
+
sessionId,
|
|
3045
|
+
email: resolvedAccount.email,
|
|
3046
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3047
|
+
showApplePay,
|
|
3048
|
+
showGooglePay,
|
|
3049
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3050
|
+
onErrorChange: updateError,
|
|
3051
|
+
onButtonClick,
|
|
3052
|
+
onDecline,
|
|
3053
|
+
runBeforeButtonClick,
|
|
3054
|
+
onLoadStateChange: setWalletLoadState
|
|
3055
|
+
}
|
|
3056
|
+
) })
|
|
3057
|
+
] }),
|
|
3058
|
+
(shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
2330
3059
|
display: "flex",
|
|
2331
3060
|
alignItems: "center",
|
|
2332
3061
|
gap: "0.75rem",
|
|
@@ -2334,17 +3063,17 @@ function SplitCardFormInner({
|
|
|
2334
3063
|
color: "#999",
|
|
2335
3064
|
fontSize: "0.85rem"
|
|
2336
3065
|
}, children: [
|
|
2337
|
-
/* @__PURE__ */ (0,
|
|
2338
|
-
/* @__PURE__ */ (0,
|
|
2339
|
-
/* @__PURE__ */ (0,
|
|
3066
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
|
|
3067
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "or pay with card" }),
|
|
3068
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
2340
3069
|
] }),
|
|
2341
3070
|
cardFormBlock
|
|
2342
3071
|
] });
|
|
2343
3072
|
}
|
|
2344
3073
|
|
|
2345
3074
|
// src/saved-payment-flow.ts
|
|
2346
|
-
var
|
|
2347
|
-
var
|
|
3075
|
+
var import_js3 = require("@flopay/js");
|
|
3076
|
+
var import_shared7 = require("@flopay/shared");
|
|
2348
3077
|
var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
|
|
2349
3078
|
function getRedirectResultFromCheckoutProcessError(error) {
|
|
2350
3079
|
if (!error?.type || !error.threeDSecureToken) {
|
|
@@ -2362,7 +3091,7 @@ function getRedirectResultFromCheckoutProcessError(error) {
|
|
|
2362
3091
|
function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
|
|
2363
3092
|
const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
|
|
2364
3093
|
return Object.assign(
|
|
2365
|
-
new
|
|
3094
|
+
new import_shared7.FloPayError(
|
|
2366
3095
|
error?.message ?? fallbackMessage,
|
|
2367
3096
|
"api_error",
|
|
2368
3097
|
{
|
|
@@ -2417,16 +3146,19 @@ function getRedirectTokenFromProcessResponse(json, options) {
|
|
|
2417
3146
|
return candidate;
|
|
2418
3147
|
}
|
|
2419
3148
|
}
|
|
2420
|
-
const
|
|
2421
|
-
if (
|
|
2422
|
-
const
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
3149
|
+
const nestedGateways = nestedRecord.gateways;
|
|
3150
|
+
if (nestedGateways && typeof nestedGateways === "object") {
|
|
3151
|
+
const stripeGateway = nestedGateways.stripe;
|
|
3152
|
+
if (stripeGateway && typeof stripeGateway === "object") {
|
|
3153
|
+
const stripeRecord = stripeGateway;
|
|
3154
|
+
const gatewayCandidates = [
|
|
3155
|
+
stripeRecord.stripeClientSecret,
|
|
3156
|
+
stripeRecord.clientSecret
|
|
3157
|
+
];
|
|
3158
|
+
for (const candidate of gatewayCandidates) {
|
|
3159
|
+
if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
|
|
3160
|
+
return candidate;
|
|
3161
|
+
}
|
|
2430
3162
|
}
|
|
2431
3163
|
}
|
|
2432
3164
|
}
|
|
@@ -2451,9 +3183,9 @@ async function recover3DSRedirectResult({
|
|
|
2451
3183
|
return null;
|
|
2452
3184
|
}
|
|
2453
3185
|
try {
|
|
2454
|
-
const api = new
|
|
3186
|
+
const api = new import_js3.PaymentAPI(billingApiUrl);
|
|
2455
3187
|
const unified = await api.getUnifiedCheckoutSession(sessionId);
|
|
2456
|
-
const refreshedToken = unified.
|
|
3188
|
+
const refreshedToken = unified.data.stripe?.clientSecret;
|
|
2457
3189
|
if (isStripePaymentIntentClientSecret(refreshedToken)) {
|
|
2458
3190
|
return {
|
|
2459
3191
|
type: "3ds_required",
|
|
@@ -2479,7 +3211,7 @@ async function processSavedPaymentForMode({
|
|
|
2479
3211
|
const lastName = session.customer?.lastName ?? session.accountData?.lastName ?? "";
|
|
2480
3212
|
const country = session.customer?.country ?? session.accountData?.country ?? void 0;
|
|
2481
3213
|
const zip = session.customer?.zip ?? session.accountData?.zip ?? void 0;
|
|
2482
|
-
const api = new
|
|
3214
|
+
const api = new import_js3.PaymentAPI(baseUrl);
|
|
2483
3215
|
const response = await retryOnceOnFetchFailure(() => api.processPayment(customerId, {
|
|
2484
3216
|
sessionId: resolvedSessionId,
|
|
2485
3217
|
tokenizedData,
|
|
@@ -2508,7 +3240,7 @@ async function processSavedPaymentForMode({
|
|
|
2508
3240
|
if (json?.type === "paypal_redirect_required" || json?.type === "3ds_required") {
|
|
2509
3241
|
const redirectToken = getRedirectTokenFromProcessResponse(json);
|
|
2510
3242
|
if (!redirectToken) {
|
|
2511
|
-
throw new
|
|
3243
|
+
throw new import_shared7.FloPayError(
|
|
2512
3244
|
"Authentication is required but no redirect token was provided.",
|
|
2513
3245
|
"api_error",
|
|
2514
3246
|
{ code: "authentication_required" }
|
|
@@ -2530,7 +3262,7 @@ async function processSavedPaymentForMode({
|
|
|
2530
3262
|
return recoveredRedirect;
|
|
2531
3263
|
}
|
|
2532
3264
|
throw Object.assign(
|
|
2533
|
-
new
|
|
3265
|
+
new import_shared7.FloPayError(
|
|
2534
3266
|
"Your card requires authentication. Please enter your payment details below.",
|
|
2535
3267
|
"api_error",
|
|
2536
3268
|
{ code: "authentication_required" }
|
|
@@ -2538,7 +3270,7 @@ async function processSavedPaymentForMode({
|
|
|
2538
3270
|
{ checkoutMethod: "card" }
|
|
2539
3271
|
);
|
|
2540
3272
|
}
|
|
2541
|
-
throw new
|
|
3273
|
+
throw new import_shared7.FloPayError(
|
|
2542
3274
|
json?.message ?? "Payment failed. Please try again.",
|
|
2543
3275
|
"api_error",
|
|
2544
3276
|
{
|
|
@@ -2558,13 +3290,13 @@ async function processSavedPaymentWithIntent({
|
|
|
2558
3290
|
const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
|
|
2559
3291
|
if (!customerEmail) {
|
|
2560
3292
|
throw Object.assign(
|
|
2561
|
-
new
|
|
3293
|
+
new import_shared7.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
|
|
2562
3294
|
param: "email"
|
|
2563
3295
|
}),
|
|
2564
3296
|
{ checkoutMethod: "card" }
|
|
2565
3297
|
);
|
|
2566
3298
|
}
|
|
2567
|
-
const api = new
|
|
3299
|
+
const api = new import_js3.PaymentAPI(billingApiUrl);
|
|
2568
3300
|
const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
|
|
2569
3301
|
sessionId,
|
|
2570
3302
|
customerEmail,
|
|
@@ -2586,7 +3318,7 @@ async function processSavedPaymentWithIntent({
|
|
|
2586
3318
|
});
|
|
2587
3319
|
if (!intentClientSecret) {
|
|
2588
3320
|
throw Object.assign(
|
|
2589
|
-
new
|
|
3321
|
+
new import_shared7.FloPayError("No client secret in payment intent response.", "api_error"),
|
|
2590
3322
|
{ checkoutMethod: "card" }
|
|
2591
3323
|
);
|
|
2592
3324
|
}
|
|
@@ -2609,7 +3341,7 @@ async function processSavedPaymentWithIntent({
|
|
|
2609
3341
|
const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
|
|
2610
3342
|
if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
|
|
2611
3343
|
throw Object.assign(
|
|
2612
|
-
new
|
|
3344
|
+
new import_shared7.FloPayError(
|
|
2613
3345
|
`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
3346
|
"api_error",
|
|
2615
3347
|
{
|
|
@@ -2657,12 +3389,12 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2657
3389
|
}) {
|
|
2658
3390
|
const stripe = flopay?.getRawProvider();
|
|
2659
3391
|
if (!stripe) {
|
|
2660
|
-
throw new
|
|
3392
|
+
throw new import_shared7.FloPayError("Payment provider is not available.", "api_error");
|
|
2661
3393
|
}
|
|
2662
3394
|
if (redirectResult.type === "3ds_required") {
|
|
2663
3395
|
if (!attempt3DS || !redirectResult.threeDSecureToken) {
|
|
2664
3396
|
throw Object.assign(
|
|
2665
|
-
new
|
|
3397
|
+
new import_shared7.FloPayError(
|
|
2666
3398
|
"Your card requires authentication. Please enter your payment details below.",
|
|
2667
3399
|
"api_error",
|
|
2668
3400
|
{ code: "authentication_required" }
|
|
@@ -2678,7 +3410,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2678
3410
|
);
|
|
2679
3411
|
if (retrieveError) {
|
|
2680
3412
|
throw Object.assign(
|
|
2681
|
-
new
|
|
3413
|
+
new import_shared7.FloPayError(
|
|
2682
3414
|
retrieveError.message ?? "Failed to retrieve 3DS payment status.",
|
|
2683
3415
|
"api_error",
|
|
2684
3416
|
{ code: retrieveError.code }
|
|
@@ -2704,7 +3436,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2704
3436
|
);
|
|
2705
3437
|
if (confirmError) {
|
|
2706
3438
|
throw Object.assign(
|
|
2707
|
-
new
|
|
3439
|
+
new import_shared7.FloPayError(
|
|
2708
3440
|
confirmError.message ?? "3DS authentication failed.",
|
|
2709
3441
|
"api_error",
|
|
2710
3442
|
{ code: confirmError.code }
|
|
@@ -2719,7 +3451,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2719
3451
|
});
|
|
2720
3452
|
if (nextActionError) {
|
|
2721
3453
|
throw Object.assign(
|
|
2722
|
-
new
|
|
3454
|
+
new import_shared7.FloPayError(
|
|
2723
3455
|
nextActionError.message ?? "3DS authentication failed.",
|
|
2724
3456
|
"api_error",
|
|
2725
3457
|
{ code: nextActionError.code }
|
|
@@ -2759,7 +3491,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2759
3491
|
});
|
|
2760
3492
|
}
|
|
2761
3493
|
throw Object.assign(
|
|
2762
|
-
new
|
|
3494
|
+
new import_shared7.FloPayError("3DS authentication did not complete successfully.", "api_error"),
|
|
2763
3495
|
{ checkoutMethod: "card" }
|
|
2764
3496
|
);
|
|
2765
3497
|
}
|
|
@@ -2767,7 +3499,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2767
3499
|
const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
|
|
2768
3500
|
if (!paypalStripe) {
|
|
2769
3501
|
throw Object.assign(
|
|
2770
|
-
new
|
|
3502
|
+
new import_shared7.FloPayError("PayPal is not available.", "api_error"),
|
|
2771
3503
|
{ checkoutMethod: "paypal" }
|
|
2772
3504
|
);
|
|
2773
3505
|
}
|
|
@@ -2777,7 +3509,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2777
3509
|
});
|
|
2778
3510
|
if (error2) {
|
|
2779
3511
|
throw Object.assign(
|
|
2780
|
-
new
|
|
3512
|
+
new import_shared7.FloPayError(
|
|
2781
3513
|
error2.message ?? "PayPal authorization failed.",
|
|
2782
3514
|
"api_error",
|
|
2783
3515
|
{ code: error2.code }
|
|
@@ -2800,7 +3532,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2800
3532
|
});
|
|
2801
3533
|
if (error) {
|
|
2802
3534
|
throw Object.assign(
|
|
2803
|
-
new
|
|
3535
|
+
new import_shared7.FloPayError(
|
|
2804
3536
|
error.message ?? "PayPal authorization failed.",
|
|
2805
3537
|
"api_error",
|
|
2806
3538
|
{ code: error.code }
|
|
@@ -2813,33 +3545,33 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
2813
3545
|
checkoutMethod: "paypal"
|
|
2814
3546
|
};
|
|
2815
3547
|
}
|
|
2816
|
-
throw new
|
|
3548
|
+
throw new import_shared7.FloPayError("Unsupported payment redirect state.", "api_error");
|
|
2817
3549
|
}
|
|
2818
3550
|
function normalizeSavedPaymentError(err) {
|
|
2819
|
-
if (err instanceof
|
|
3551
|
+
if (err instanceof import_shared7.FloPayError) {
|
|
2820
3552
|
return err;
|
|
2821
3553
|
}
|
|
2822
|
-
return new
|
|
3554
|
+
return new import_shared7.FloPayError(
|
|
2823
3555
|
err instanceof Error ? err.message : "Payment failed. Please try again.",
|
|
2824
3556
|
"api_error"
|
|
2825
3557
|
);
|
|
2826
3558
|
}
|
|
2827
3559
|
function resolveSavedPaymentPublishableKeys(unified) {
|
|
2828
|
-
|
|
2829
|
-
let paypalPublishableKey;
|
|
2830
|
-
if (unified.provider === "stripe") {
|
|
2831
|
-
publishableKey = unified.data.stripe?.publishableKey;
|
|
2832
|
-
paypalPublishableKey = unified.data.stripe?.paypalPublishableKey ?? void 0;
|
|
2833
|
-
}
|
|
3560
|
+
const publishableKey = unified.data.stripe?.publishableKey;
|
|
2834
3561
|
if (!publishableKey) {
|
|
2835
|
-
throw new
|
|
2836
|
-
"No publishable key found in the checkout session. Ensure the session
|
|
3562
|
+
throw new import_shared7.FloPayError(
|
|
3563
|
+
"No publishable key found in the checkout session. Ensure the session advertises gateways.stripe.",
|
|
2837
3564
|
"validation_error"
|
|
2838
3565
|
);
|
|
2839
3566
|
}
|
|
2840
3567
|
return {
|
|
2841
3568
|
publishableKey,
|
|
2842
|
-
|
|
3569
|
+
// Direct-PayPal sessions can still use Stripe's PayPal Element for the
|
|
3570
|
+
// saved-PM redirect leg. Prefer the dedicated Stripe-PayPal sub-account
|
|
3571
|
+
// publishable key when the backend advertises one; fall back to the
|
|
3572
|
+
// primary Stripe publishable key so the resume flow still has a Stripe
|
|
3573
|
+
// instance to drive Stripe's PayPal PI.
|
|
3574
|
+
paypalPublishableKey: unified.data.stripe?.paypalPublishableKey ?? publishableKey
|
|
2843
3575
|
};
|
|
2844
3576
|
}
|
|
2845
3577
|
async function loadSavedPaymentProviders({
|
|
@@ -2850,11 +3582,11 @@ async function loadSavedPaymentProviders({
|
|
|
2850
3582
|
}) {
|
|
2851
3583
|
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2852
3584
|
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2853
|
-
(0,
|
|
3585
|
+
(0, import_js3.loadFloPay)(publishableKey, {
|
|
2854
3586
|
billingApiUrl,
|
|
2855
3587
|
locale
|
|
2856
3588
|
}),
|
|
2857
|
-
needsSeparatePaypal ? (0,
|
|
3589
|
+
needsSeparatePaypal ? (0, import_js3.loadFloPay)(paypalPublishableKey, {
|
|
2858
3590
|
billingApiUrl,
|
|
2859
3591
|
locale
|
|
2860
3592
|
}).catch((err) => {
|
|
@@ -2869,13 +3601,21 @@ async function loadSavedPaymentProviders({
|
|
|
2869
3601
|
}
|
|
2870
3602
|
|
|
2871
3603
|
// src/flopay-checkout.tsx
|
|
2872
|
-
var
|
|
3604
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2873
3605
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
2874
3606
|
var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
|
|
2875
3607
|
var sessionInflightMap = /* @__PURE__ */ new Map();
|
|
2876
3608
|
function sleep(ms) {
|
|
2877
3609
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2878
3610
|
}
|
|
3611
|
+
function resolveDirectPaypalConfig(unified) {
|
|
3612
|
+
const clientId = unified?.data.paypal?.publishableKey;
|
|
3613
|
+
if (!clientId) return void 0;
|
|
3614
|
+
return {
|
|
3615
|
+
clientId,
|
|
3616
|
+
environment: unified?.data.paypal?.environment
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
2879
3619
|
function canUseStorage() {
|
|
2880
3620
|
return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
|
|
2881
3621
|
}
|
|
@@ -2949,6 +3689,7 @@ function FloPayCheckout({
|
|
|
2949
3689
|
showPayPal = true,
|
|
2950
3690
|
showApplePay = true,
|
|
2951
3691
|
showGooglePay = true,
|
|
3692
|
+
debug = false,
|
|
2952
3693
|
layout,
|
|
2953
3694
|
buttonsTheme,
|
|
2954
3695
|
buttonsStyles,
|
|
@@ -2969,81 +3710,81 @@ function FloPayCheckout({
|
|
|
2969
3710
|
renderConfirmButton,
|
|
2970
3711
|
onSessionCompleted
|
|
2971
3712
|
}) {
|
|
2972
|
-
const resolvedBillingUrl = (0,
|
|
3713
|
+
const resolvedBillingUrl = (0, import_shared8.resolveBillingApiUrl)(billingApiUrl);
|
|
2973
3714
|
const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
|
|
2974
3715
|
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,
|
|
3716
|
+
const [unified, setUnified] = (0, import_react9.useState)(null);
|
|
3717
|
+
const [flopay, setFloPay] = (0, import_react9.useState)(null);
|
|
3718
|
+
const flopayRef = (0, import_react9.useRef)(null);
|
|
3719
|
+
const [paypalFlopay, setPaypalFloPay] = (0, import_react9.useState)(null);
|
|
3720
|
+
const paypalFlopayRef = (0, import_react9.useRef)(null);
|
|
3721
|
+
const [session, setSession] = (0, import_react9.useState)(null);
|
|
3722
|
+
const [resolvedSessionId, setResolvedSessionId] = (0, import_react9.useState)(sessionIdProp ?? "");
|
|
2982
3723
|
const activeSessionId = sessionIdProp ?? resolvedSessionId;
|
|
2983
3724
|
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,
|
|
3725
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(true);
|
|
3726
|
+
const [loadError, setLoadError] = (0, import_react9.useState)(null);
|
|
3727
|
+
const [currentMode, setCurrentMode] = (0, import_react9.useState)("full");
|
|
3728
|
+
const [confirmProcessing, setConfirmProcessing] = (0, import_react9.useState)(false);
|
|
3729
|
+
const [modeError, setModeError] = (0, import_react9.useState)(initialErrorMessage);
|
|
3730
|
+
const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react9.useState)(null);
|
|
3731
|
+
const [modeOverlayError, setModeOverlayError] = (0, import_react9.useState)(null);
|
|
3732
|
+
const [createSessionPatch, setCreateSessionPatch] = (0, import_react9.useState)(void 0);
|
|
3733
|
+
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react9.useState)("");
|
|
3734
|
+
const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react9.useState)(false);
|
|
3735
|
+
const autoCheckoutAttempted = (0, import_react9.useRef)(false);
|
|
3736
|
+
const paypalResumeAttempted = (0, import_react9.useRef)(false);
|
|
3737
|
+
const savedPaymentKeysRef = (0, import_react9.useRef)(null);
|
|
3738
|
+
const onCompleteRef = (0, import_react9.useRef)(onComplete);
|
|
2998
3739
|
onCompleteRef.current = onComplete;
|
|
2999
|
-
const onErrorRef = (0,
|
|
3740
|
+
const onErrorRef = (0, import_react9.useRef)(onError);
|
|
3000
3741
|
onErrorRef.current = onError;
|
|
3001
|
-
const onDeclineRef = (0,
|
|
3742
|
+
const onDeclineRef = (0, import_react9.useRef)(onDecline);
|
|
3002
3743
|
onDeclineRef.current = onDecline;
|
|
3003
|
-
const onSessionCompletedRef = (0,
|
|
3744
|
+
const onSessionCompletedRef = (0, import_react9.useRef)(onSessionCompleted);
|
|
3004
3745
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
3005
|
-
(0,
|
|
3746
|
+
(0, import_react9.useEffect)(() => {
|
|
3006
3747
|
console.info("[FloPay] Checkout initialized", {
|
|
3007
|
-
sdk_version:
|
|
3748
|
+
sdk_version: import_shared8.SDK_VERSION,
|
|
3008
3749
|
checkout_type: checkoutType,
|
|
3009
3750
|
checkout_layout: checkoutLayout,
|
|
3010
3751
|
billing_api_url: resolvedBillingUrl
|
|
3011
3752
|
});
|
|
3012
3753
|
}, [checkoutLayout, checkoutType, resolvedBillingUrl]);
|
|
3013
|
-
const baseCreateSessionHash = (0,
|
|
3754
|
+
const baseCreateSessionHash = (0, import_react9.useMemo)(
|
|
3014
3755
|
() => createSessionParams ? hashCreateParams(createSessionParams) : "",
|
|
3015
3756
|
[createSessionParams]
|
|
3016
3757
|
);
|
|
3017
|
-
const activeCreateSessionPatch = (0,
|
|
3758
|
+
const activeCreateSessionPatch = (0, import_react9.useMemo)(
|
|
3018
3759
|
() => createSessionPatchBaseHash === baseCreateSessionHash ? createSessionPatch : void 0,
|
|
3019
3760
|
[createSessionPatch, createSessionPatchBaseHash, baseCreateSessionHash]
|
|
3020
3761
|
);
|
|
3021
|
-
const effectiveCreateSessionBase = (0,
|
|
3762
|
+
const effectiveCreateSessionBase = (0, import_react9.useMemo)(
|
|
3022
3763
|
() => createSessionParams ? mergeInlineSessionPatch(createSessionParams, activeCreateSessionPatch) : void 0,
|
|
3023
3764
|
[createSessionParams, activeCreateSessionPatch]
|
|
3024
3765
|
);
|
|
3025
3766
|
const effectiveCreateSessionMode = checkoutModeProp ?? effectiveCreateSessionBase?.checkoutMode ?? "full";
|
|
3026
|
-
const effectiveCreateSession = (0,
|
|
3767
|
+
const effectiveCreateSession = (0, import_react9.useMemo)(
|
|
3027
3768
|
() => effectiveCreateSessionBase ? {
|
|
3028
3769
|
...effectiveCreateSessionBase,
|
|
3029
3770
|
checkoutMode: effectiveCreateSessionMode
|
|
3030
3771
|
} : void 0,
|
|
3031
3772
|
[effectiveCreateSessionBase, effectiveCreateSessionMode]
|
|
3032
3773
|
);
|
|
3033
|
-
(0,
|
|
3774
|
+
(0, import_react9.useEffect)(() => {
|
|
3034
3775
|
setCreateSessionPatch(void 0);
|
|
3035
3776
|
setCreateSessionPatchBaseHash(baseCreateSessionHash);
|
|
3036
3777
|
}, [baseCreateSessionHash]);
|
|
3037
|
-
(0,
|
|
3778
|
+
(0, import_react9.useEffect)(() => {
|
|
3038
3779
|
setModeError(initialErrorMessage);
|
|
3039
3780
|
}, [initialErrorMessage]);
|
|
3040
|
-
const emitDecline = (0,
|
|
3781
|
+
const emitDecline = (0, import_react9.useCallback)(
|
|
3041
3782
|
(method, input, overrides) => {
|
|
3042
3783
|
onDeclineRef.current?.(buildDeclineEvent(method, input, overrides));
|
|
3043
3784
|
},
|
|
3044
3785
|
[]
|
|
3045
3786
|
);
|
|
3046
|
-
const runSavedPaymentFlow = (0,
|
|
3787
|
+
const runSavedPaymentFlow = (0, import_react9.useCallback)(
|
|
3047
3788
|
async (sess, options) => {
|
|
3048
3789
|
setModeError(null);
|
|
3049
3790
|
setModeOverlayError(null);
|
|
@@ -3072,12 +3813,12 @@ function FloPayCheckout({
|
|
|
3072
3813
|
clearPayPalResumeState();
|
|
3073
3814
|
}
|
|
3074
3815
|
} else if (options?.initialAutoProcessingPending) {
|
|
3075
|
-
const api = new
|
|
3816
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3076
3817
|
const completed = await api.waitForCheckoutSessionCompletion(options.initialAutoProcessingPending.sessionId, {
|
|
3077
3818
|
initialDelayMs: options.initialAutoProcessingPending.retryAfterMs
|
|
3078
3819
|
});
|
|
3079
3820
|
if (completed.data.session?.status !== "complete") {
|
|
3080
|
-
throw new
|
|
3821
|
+
throw new import_shared8.FloPayError("Automatic payment failed. Please try again.", "api_error", {
|
|
3081
3822
|
code: completed.data.session?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
3082
3823
|
});
|
|
3083
3824
|
}
|
|
@@ -3161,7 +3902,7 @@ function FloPayCheckout({
|
|
|
3161
3902
|
resolvedBillingUrl
|
|
3162
3903
|
]
|
|
3163
3904
|
);
|
|
3164
|
-
(0,
|
|
3905
|
+
(0, import_react9.useEffect)(() => {
|
|
3165
3906
|
if (typeof window === "undefined" || paypalResumeAttempted.current) {
|
|
3166
3907
|
return;
|
|
3167
3908
|
}
|
|
@@ -3183,7 +3924,7 @@ function FloPayCheckout({
|
|
|
3183
3924
|
try {
|
|
3184
3925
|
if (params.get("redirect_status") === "failed") {
|
|
3185
3926
|
throw Object.assign(
|
|
3186
|
-
new
|
|
3927
|
+
new import_shared8.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
|
|
3187
3928
|
{ checkoutMethod: "paypal" }
|
|
3188
3929
|
);
|
|
3189
3930
|
}
|
|
@@ -3199,14 +3940,14 @@ function FloPayCheckout({
|
|
|
3199
3940
|
const paypalStripe = (resumePaypalFlopay ?? resumeFlopay).getRawProvider();
|
|
3200
3941
|
if (!paypalStripe) {
|
|
3201
3942
|
throw Object.assign(
|
|
3202
|
-
new
|
|
3943
|
+
new import_shared8.FloPayError("PayPal is not available.", "api_error"),
|
|
3203
3944
|
{ checkoutMethod: "paypal" }
|
|
3204
3945
|
);
|
|
3205
3946
|
}
|
|
3206
3947
|
const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
|
|
3207
3948
|
if (error) {
|
|
3208
3949
|
throw Object.assign(
|
|
3209
|
-
new
|
|
3950
|
+
new import_shared8.FloPayError(
|
|
3210
3951
|
error.message ?? "Failed to retrieve PayPal payment status.",
|
|
3211
3952
|
"api_error",
|
|
3212
3953
|
{ code: error.code }
|
|
@@ -3217,14 +3958,14 @@ function FloPayCheckout({
|
|
|
3217
3958
|
const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
|
|
3218
3959
|
if (!paymentIntent || resultStatus === "failed") {
|
|
3219
3960
|
throw Object.assign(
|
|
3220
|
-
new
|
|
3961
|
+
new import_shared8.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
|
|
3221
3962
|
{ checkoutMethod: "paypal" }
|
|
3222
3963
|
);
|
|
3223
3964
|
}
|
|
3224
3965
|
const paymentMethodId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
3225
3966
|
let finalResultStatus = resultStatus;
|
|
3226
3967
|
if (resumeState.sessionId) {
|
|
3227
|
-
const resumeApi = new
|
|
3968
|
+
const resumeApi = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3228
3969
|
const resumeSessionResult = await resumeApi.getUnifiedCheckoutSession(resumeState.sessionId);
|
|
3229
3970
|
const resumeSession = resumeSessionResult.data.session;
|
|
3230
3971
|
if (resumeSession && resumeSession.status !== "complete") {
|
|
@@ -3241,7 +3982,7 @@ function FloPayCheckout({
|
|
|
3241
3982
|
});
|
|
3242
3983
|
if (processResult.type !== "success") {
|
|
3243
3984
|
throw Object.assign(
|
|
3244
|
-
new
|
|
3985
|
+
new import_shared8.FloPayError("Failed to finalize PayPal payment.", "api_error"),
|
|
3245
3986
|
{ checkoutMethod: "paypal" }
|
|
3246
3987
|
);
|
|
3247
3988
|
}
|
|
@@ -3278,7 +4019,7 @@ function FloPayCheckout({
|
|
|
3278
4019
|
}
|
|
3279
4020
|
})();
|
|
3280
4021
|
}, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
|
|
3281
|
-
const initializedHashRef = (0,
|
|
4022
|
+
const initializedHashRef = (0, import_react9.useRef)(null);
|
|
3282
4023
|
function hashCreateParams(params) {
|
|
3283
4024
|
const key = JSON.stringify({
|
|
3284
4025
|
c: params?.clientId,
|
|
@@ -3303,23 +4044,23 @@ function FloPayCheckout({
|
|
|
3303
4044
|
}
|
|
3304
4045
|
return `flopay_session_${Math.abs(h).toString(36)}`;
|
|
3305
4046
|
}
|
|
3306
|
-
const createSessionHash = (0,
|
|
4047
|
+
const createSessionHash = (0, import_react9.useMemo)(
|
|
3307
4048
|
() => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
|
|
3308
4049
|
[effectiveCreateSession]
|
|
3309
4050
|
);
|
|
3310
|
-
const createSessionParamsRef = (0,
|
|
4051
|
+
const createSessionParamsRef = (0, import_react9.useRef)(effectiveCreateSession);
|
|
3311
4052
|
createSessionParamsRef.current = effectiveCreateSession;
|
|
3312
|
-
(0,
|
|
4053
|
+
(0, import_react9.useEffect)(() => {
|
|
3313
4054
|
setResolvedSessionId(sessionIdProp ?? "");
|
|
3314
4055
|
}, [sessionIdProp]);
|
|
3315
|
-
(0,
|
|
4056
|
+
(0, import_react9.useEffect)(() => {
|
|
3316
4057
|
autoCheckoutAttempted.current = false;
|
|
3317
4058
|
setModeError(initialErrorMessage);
|
|
3318
4059
|
setModeOverlayError(null);
|
|
3319
4060
|
setModeOverlayStatus(null);
|
|
3320
4061
|
}, [createSessionHash, initialErrorMessage, sessionIdProp]);
|
|
3321
4062
|
async function resolveInlineSession(params, cacheKey) {
|
|
3322
|
-
const api = new
|
|
4063
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3323
4064
|
let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
|
|
3324
4065
|
let realResult = null;
|
|
3325
4066
|
if (sid) {
|
|
@@ -3355,11 +4096,11 @@ function FloPayCheckout({
|
|
|
3355
4096
|
}
|
|
3356
4097
|
return { sid: sid ?? "", result: realResult };
|
|
3357
4098
|
}
|
|
3358
|
-
const bootstrapInlineSession = (0,
|
|
4099
|
+
const bootstrapInlineSession = (0, import_react9.useCallback)(
|
|
3359
4100
|
async (patch) => {
|
|
3360
4101
|
const baseParams = createSessionParamsRef.current;
|
|
3361
4102
|
if (!baseParams) {
|
|
3362
|
-
throw new
|
|
4103
|
+
throw new import_shared8.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
|
|
3363
4104
|
}
|
|
3364
4105
|
const mergedParams = mergeInlineSessionPatch(baseParams, patch);
|
|
3365
4106
|
const cacheKey = hashCreateParams(mergedParams);
|
|
@@ -3416,7 +4157,7 @@ function FloPayCheckout({
|
|
|
3416
4157
|
},
|
|
3417
4158
|
[locale, resolvedBillingUrl]
|
|
3418
4159
|
);
|
|
3419
|
-
const handleInlineSessionPatch = (0,
|
|
4160
|
+
const handleInlineSessionPatch = (0, import_react9.useCallback)(async (patch) => {
|
|
3420
4161
|
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
|
|
3421
4162
|
return {
|
|
3422
4163
|
sessionId: resolvedSessionId,
|
|
@@ -3439,7 +4180,7 @@ function FloPayCheckout({
|
|
|
3439
4180
|
resolvedSessionId,
|
|
3440
4181
|
session
|
|
3441
4182
|
]);
|
|
3442
|
-
(0,
|
|
4183
|
+
(0, import_react9.useEffect)(() => {
|
|
3443
4184
|
let cancelled = false;
|
|
3444
4185
|
setLoadError(null);
|
|
3445
4186
|
if (createSessionHash) {
|
|
@@ -3483,7 +4224,7 @@ function FloPayCheckout({
|
|
|
3483
4224
|
}
|
|
3484
4225
|
} catch (err) {
|
|
3485
4226
|
if (cancelled) return;
|
|
3486
|
-
const errorCode = err instanceof
|
|
4227
|
+
const errorCode = err instanceof import_shared8.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
3487
4228
|
if (shouldAutoProcessInlineSession && errorCode === "session_auto_completed") {
|
|
3488
4229
|
autoCheckoutAttempted.current = true;
|
|
3489
4230
|
setModeOverlayStatus("success");
|
|
@@ -3499,7 +4240,7 @@ function FloPayCheckout({
|
|
|
3499
4240
|
setModeOverlayStatus(null);
|
|
3500
4241
|
setModeOverlayError(null);
|
|
3501
4242
|
}
|
|
3502
|
-
const floPayErr = err instanceof
|
|
4243
|
+
const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
|
|
3503
4244
|
setLoadError(floPayErr);
|
|
3504
4245
|
}
|
|
3505
4246
|
})();
|
|
@@ -3510,14 +4251,14 @@ function FloPayCheckout({
|
|
|
3510
4251
|
setIsLoading(true);
|
|
3511
4252
|
async function init() {
|
|
3512
4253
|
try {
|
|
3513
|
-
const api = new
|
|
4254
|
+
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
3514
4255
|
const result = await api.getUnifiedCheckoutSession(activeSessionId);
|
|
3515
4256
|
if (cancelled) return;
|
|
3516
4257
|
setUnified(result);
|
|
3517
4258
|
const sess = result.data.session ?? null;
|
|
3518
4259
|
setSession(sess);
|
|
3519
4260
|
if (!sess) {
|
|
3520
|
-
throw new
|
|
4261
|
+
throw new import_shared8.FloPayError("No session data returned", "api_error");
|
|
3521
4262
|
}
|
|
3522
4263
|
if (sess.status === "complete") {
|
|
3523
4264
|
setIsLoading(false);
|
|
@@ -3525,7 +4266,7 @@ function FloPayCheckout({
|
|
|
3525
4266
|
return;
|
|
3526
4267
|
}
|
|
3527
4268
|
if (sess.status === "expired") {
|
|
3528
|
-
throw new
|
|
4269
|
+
throw new import_shared8.FloPayError("Checkout session has expired.", "api_error", {
|
|
3529
4270
|
code: "checkout_session_expired"
|
|
3530
4271
|
});
|
|
3531
4272
|
}
|
|
@@ -3559,7 +4300,7 @@ function FloPayCheckout({
|
|
|
3559
4300
|
if (!cancelled) setIsLoading(false);
|
|
3560
4301
|
} catch (err) {
|
|
3561
4302
|
if (cancelled) return;
|
|
3562
|
-
const floPayErr = err instanceof
|
|
4303
|
+
const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
|
|
3563
4304
|
setLoadError(floPayErr);
|
|
3564
4305
|
setIsLoading(false);
|
|
3565
4306
|
}
|
|
@@ -3599,7 +4340,7 @@ function FloPayCheckout({
|
|
|
3599
4340
|
initSessionDependency,
|
|
3600
4341
|
runSavedPaymentFlow
|
|
3601
4342
|
]);
|
|
3602
|
-
const handleConfirmCheckout = (0,
|
|
4343
|
+
const handleConfirmCheckout = (0, import_react9.useCallback)(async () => {
|
|
3603
4344
|
if (confirmProcessing || !session) return;
|
|
3604
4345
|
setConfirmProcessing(true);
|
|
3605
4346
|
setModeError(null);
|
|
@@ -3612,17 +4353,17 @@ function FloPayCheckout({
|
|
|
3612
4353
|
setConfirmProcessing(false);
|
|
3613
4354
|
}
|
|
3614
4355
|
}, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
|
|
3615
|
-
const providerOptions = (0,
|
|
4356
|
+
const providerOptions = (0, import_react9.useMemo)(() => {
|
|
3616
4357
|
if (!unified || !session) return void 0;
|
|
3617
4358
|
const opts = {
|
|
3618
4359
|
appearance,
|
|
3619
4360
|
paymentMethodCreation: "manual",
|
|
3620
4361
|
billingApiUrl: resolvedBillingUrl
|
|
3621
4362
|
};
|
|
3622
|
-
if (unified.
|
|
4363
|
+
if (unified.data.stripe?.clientSecret) {
|
|
3623
4364
|
opts.clientSecret = unified.data.stripe.clientSecret;
|
|
3624
4365
|
} else {
|
|
3625
|
-
const displayTotal = (0,
|
|
4366
|
+
const displayTotal = (0, import_shared8.buildCheckoutDisplayData)(session).total;
|
|
3626
4367
|
opts.amount = Math.round(displayTotal * 100) || session.amount;
|
|
3627
4368
|
opts.currency = session.currency?.toLowerCase();
|
|
3628
4369
|
}
|
|
@@ -3631,7 +4372,7 @@ function FloPayCheckout({
|
|
|
3631
4372
|
const shouldHandleInlineSessionPatch = Boolean(
|
|
3632
4373
|
createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && effectiveCreateSessionMode === "full"
|
|
3633
4374
|
);
|
|
3634
|
-
const checkoutValue = (0,
|
|
4375
|
+
const checkoutValue = (0, import_react9.useMemo)(
|
|
3635
4376
|
() => ({
|
|
3636
4377
|
session,
|
|
3637
4378
|
loading: isLoading,
|
|
@@ -3653,7 +4394,7 @@ function FloPayCheckout({
|
|
|
3653
4394
|
]
|
|
3654
4395
|
);
|
|
3655
4396
|
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
|
|
3656
|
-
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0,
|
|
4397
|
+
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3657
4398
|
ProcessingOverlay,
|
|
3658
4399
|
{
|
|
3659
4400
|
status: modeOverlayStatus,
|
|
@@ -3662,31 +4403,31 @@ function FloPayCheckout({
|
|
|
3662
4403
|
) : null;
|
|
3663
4404
|
if (isLoading) {
|
|
3664
4405
|
if (loadingNode) {
|
|
3665
|
-
return /* @__PURE__ */ (0,
|
|
4406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3666
4407
|
loadingNode,
|
|
3667
4408
|
modeOverlay
|
|
3668
4409
|
] });
|
|
3669
4410
|
}
|
|
3670
4411
|
if (layout === "buttons") {
|
|
3671
|
-
const skeletonBar = (h) => /* @__PURE__ */ (0,
|
|
4412
|
+
const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3672
4413
|
height: h,
|
|
3673
4414
|
borderRadius: 8,
|
|
3674
4415
|
background: "#e5e7eb",
|
|
3675
4416
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
3676
4417
|
} });
|
|
3677
|
-
return /* @__PURE__ */ (0,
|
|
3678
|
-
/* @__PURE__ */ (0,
|
|
4418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4419
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
3679
4420
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3680
4421
|
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3681
4422
|
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
3682
|
-
/* @__PURE__ */ (0,
|
|
4423
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
3683
4424
|
] }),
|
|
3684
4425
|
modeOverlay
|
|
3685
4426
|
] });
|
|
3686
4427
|
}
|
|
3687
|
-
return /* @__PURE__ */ (0,
|
|
3688
|
-
/* @__PURE__ */ (0,
|
|
3689
|
-
/* @__PURE__ */ (0,
|
|
4428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4429
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
|
|
4430
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3690
4431
|
width: 24,
|
|
3691
4432
|
height: 24,
|
|
3692
4433
|
border: "2px solid #e5e7eb",
|
|
@@ -3694,16 +4435,16 @@ function FloPayCheckout({
|
|
|
3694
4435
|
borderRadius: "50%",
|
|
3695
4436
|
animation: "spin 0.6s linear infinite"
|
|
3696
4437
|
} }),
|
|
3697
|
-
/* @__PURE__ */ (0,
|
|
4438
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
3698
4439
|
] }),
|
|
3699
4440
|
modeOverlay
|
|
3700
4441
|
] });
|
|
3701
4442
|
}
|
|
3702
4443
|
if (loadError) {
|
|
3703
4444
|
if (errorNode) {
|
|
3704
|
-
return /* @__PURE__ */ (0,
|
|
4445
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
|
|
3705
4446
|
}
|
|
3706
|
-
return /* @__PURE__ */ (0,
|
|
4447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3707
4448
|
"div",
|
|
3708
4449
|
{
|
|
3709
4450
|
style: {
|
|
@@ -3717,8 +4458,8 @@ function FloPayCheckout({
|
|
|
3717
4458
|
) });
|
|
3718
4459
|
}
|
|
3719
4460
|
if (shouldShowInterimButtons) {
|
|
3720
|
-
return /* @__PURE__ */ (0,
|
|
3721
|
-
/* @__PURE__ */ (0,
|
|
4461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4462
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3722
4463
|
InterimButtonsView,
|
|
3723
4464
|
{
|
|
3724
4465
|
onButtonClick,
|
|
@@ -3736,12 +4477,12 @@ function FloPayCheckout({
|
|
|
3736
4477
|
] });
|
|
3737
4478
|
}
|
|
3738
4479
|
if (!flopay || !providerOptions) {
|
|
3739
|
-
return /* @__PURE__ */ (0,
|
|
4480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: modeOverlay });
|
|
3740
4481
|
}
|
|
3741
4482
|
if (currentMode === "confirm") {
|
|
3742
|
-
return /* @__PURE__ */ (0,
|
|
3743
|
-
/* @__PURE__ */ (0,
|
|
3744
|
-
modeError && /* @__PURE__ */ (0,
|
|
4483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4484
|
+
/* @__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: [
|
|
4485
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3745
4486
|
"div",
|
|
3746
4487
|
{
|
|
3747
4488
|
style: {
|
|
@@ -3756,7 +4497,7 @@ function FloPayCheckout({
|
|
|
3756
4497
|
renderConfirmButton ? renderConfirmButton({
|
|
3757
4498
|
onConfirm: handleConfirmCheckout,
|
|
3758
4499
|
isProcessing: confirmProcessing
|
|
3759
|
-
}) : /* @__PURE__ */ (0,
|
|
4500
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3760
4501
|
"button",
|
|
3761
4502
|
{
|
|
3762
4503
|
type: "button",
|
|
@@ -3781,9 +4522,9 @@ function FloPayCheckout({
|
|
|
3781
4522
|
modeOverlay
|
|
3782
4523
|
] });
|
|
3783
4524
|
}
|
|
3784
|
-
return /* @__PURE__ */ (0,
|
|
3785
|
-
/* @__PURE__ */ (0,
|
|
3786
|
-
modeError && /* @__PURE__ */ (0,
|
|
4525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4526
|
+
/* @__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: [
|
|
4527
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3787
4528
|
"div",
|
|
3788
4529
|
{
|
|
3789
4530
|
style: {
|
|
@@ -3798,7 +4539,7 @@ function FloPayCheckout({
|
|
|
3798
4539
|
children: modeError
|
|
3799
4540
|
}
|
|
3800
4541
|
),
|
|
3801
|
-
/* @__PURE__ */ (0,
|
|
4542
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3802
4543
|
SessionInjector,
|
|
3803
4544
|
{
|
|
3804
4545
|
sessionId: activeSessionId,
|
|
@@ -3807,7 +4548,7 @@ function FloPayCheckout({
|
|
|
3807
4548
|
children
|
|
3808
4549
|
}
|
|
3809
4550
|
)
|
|
3810
|
-
] }) : /* @__PURE__ */ (0,
|
|
4551
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3811
4552
|
SplitCardForm,
|
|
3812
4553
|
{
|
|
3813
4554
|
sessionId: activeSessionId,
|
|
@@ -3815,7 +4556,7 @@ function FloPayCheckout({
|
|
|
3815
4556
|
userId: session?.customer?.id,
|
|
3816
4557
|
firstName: session?.customer?.firstName,
|
|
3817
4558
|
lastName: session?.customer?.lastName,
|
|
3818
|
-
totalAmount: session ? Math.round((0,
|
|
4559
|
+
totalAmount: session ? Math.round((0, import_shared8.buildCheckoutDisplayData)(session).total * 100) : 0,
|
|
3819
4560
|
currency: session?.currency?.toLowerCase() ?? "usd",
|
|
3820
4561
|
onComplete,
|
|
3821
4562
|
onError,
|
|
@@ -3846,7 +4587,11 @@ function FloPayCheckout({
|
|
|
3846
4587
|
checkoutType: createSessionParams ? "embedded_checkout" : "standard_checkout",
|
|
3847
4588
|
checkoutLayout: children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout",
|
|
3848
4589
|
submitLabel,
|
|
3849
|
-
className
|
|
4590
|
+
className,
|
|
4591
|
+
directPaypal: resolveDirectPaypalConfig(unified),
|
|
4592
|
+
isSubscription: session?.mode === "subscription",
|
|
4593
|
+
session,
|
|
4594
|
+
debug
|
|
3850
4595
|
}
|
|
3851
4596
|
) }) }),
|
|
3852
4597
|
modeOverlay
|
|
@@ -3858,8 +4603,8 @@ function SessionInjector({
|
|
|
3858
4603
|
session,
|
|
3859
4604
|
children
|
|
3860
4605
|
}) {
|
|
3861
|
-
return /* @__PURE__ */ (0,
|
|
3862
|
-
if (!
|
|
4606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: import_react9.default.Children.map(children, (child) => {
|
|
4607
|
+
if (!import_react9.default.isValidElement(child)) return child;
|
|
3863
4608
|
const existing = child.props;
|
|
3864
4609
|
const injected = {};
|
|
3865
4610
|
if (!existing.sessionId) injected.sessionId = sessionId;
|
|
@@ -3873,7 +4618,7 @@ function SessionInjector({
|
|
|
3873
4618
|
injected.lastName = session.customer.lastName;
|
|
3874
4619
|
}
|
|
3875
4620
|
if (Object.keys(injected).length === 0) return child;
|
|
3876
|
-
return
|
|
4621
|
+
return import_react9.default.cloneElement(child, injected);
|
|
3877
4622
|
}) });
|
|
3878
4623
|
}
|
|
3879
4624
|
function InterimButtonsView({
|
|
@@ -3891,15 +4636,15 @@ function InterimButtonsView({
|
|
|
3891
4636
|
cardBackButtonContent,
|
|
3892
4637
|
cardTitleContent
|
|
3893
4638
|
}) {
|
|
3894
|
-
const [showCardForm, setShowCardForm] = (0,
|
|
4639
|
+
const [showCardForm, setShowCardForm] = (0, import_react9.useState)(false);
|
|
3895
4640
|
const isCardOpenControlled = typeof cardOpen === "boolean";
|
|
3896
|
-
(0,
|
|
4641
|
+
(0, import_react9.useEffect)(() => {
|
|
3897
4642
|
if (isCardOpenControlled) {
|
|
3898
4643
|
setShowCardForm(cardOpen);
|
|
3899
4644
|
}
|
|
3900
4645
|
}, [cardOpen, isCardOpenControlled]);
|
|
3901
|
-
const bStyles = (0,
|
|
3902
|
-
const base = (0,
|
|
4646
|
+
const bStyles = (0, import_react9.useMemo)(() => {
|
|
4647
|
+
const base = (0, import_shared8.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
3903
4648
|
if (!stylesOverride) return base;
|
|
3904
4649
|
return {
|
|
3905
4650
|
...base,
|
|
@@ -3912,7 +4657,7 @@ function InterimButtonsView({
|
|
|
3912
4657
|
title: { ...base.title, ...stylesOverride.title }
|
|
3913
4658
|
};
|
|
3914
4659
|
}, [buttonsTheme, stylesOverride]);
|
|
3915
|
-
const skeleton = (h) => /* @__PURE__ */ (0,
|
|
4660
|
+
const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3916
4661
|
height: h,
|
|
3917
4662
|
borderRadius: 8,
|
|
3918
4663
|
background: "#e5e7eb",
|
|
@@ -3924,15 +4669,15 @@ function InterimButtonsView({
|
|
|
3924
4669
|
const inputBg = bStyles.cardInputBackground ?? "white";
|
|
3925
4670
|
const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
|
|
3926
4671
|
const hideTitle = isEmptySlotContent(cardTitleContent);
|
|
3927
|
-
return /* @__PURE__ */ (0,
|
|
4672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
|
|
3928
4673
|
backgroundColor: bStyles.cardFormContainer?.backgroundColor ?? "white",
|
|
3929
4674
|
borderRadius: "8px",
|
|
3930
4675
|
animation: "flopay-interim-expand 0.35s cubic-bezier(0.4, 0, 0.2, 1) both",
|
|
3931
4676
|
overflow: "hidden",
|
|
3932
4677
|
...bStyles.cardFormContainer
|
|
3933
4678
|
}, children: [
|
|
3934
|
-
/* @__PURE__ */ (0,
|
|
3935
|
-
/* @__PURE__ */ (0,
|
|
4679
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
|
|
4680
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3936
4681
|
"button",
|
|
3937
4682
|
{
|
|
3938
4683
|
type: "button",
|
|
@@ -3959,7 +4704,7 @@ function InterimButtonsView({
|
|
|
3959
4704
|
...bStyles.backButton
|
|
3960
4705
|
},
|
|
3961
4706
|
children: [
|
|
3962
|
-
/* @__PURE__ */ (0,
|
|
4707
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: {
|
|
3963
4708
|
display: "inline-flex",
|
|
3964
4709
|
alignItems: "center",
|
|
3965
4710
|
justifyContent: "center",
|
|
@@ -3968,12 +4713,12 @@ function InterimButtonsView({
|
|
|
3968
4713
|
borderRadius: "50%",
|
|
3969
4714
|
backgroundColor: "#f3f4f6",
|
|
3970
4715
|
...bStyles.backButtonIcon
|
|
3971
|
-
}, children: /* @__PURE__ */ (0,
|
|
3972
|
-
/* @__PURE__ */ (0,
|
|
4716
|
+
}, 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" }) }) }),
|
|
4717
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3973
4718
|
]
|
|
3974
4719
|
}
|
|
3975
4720
|
),
|
|
3976
|
-
hideTitle ? /* @__PURE__ */ (0,
|
|
4721
|
+
hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3977
4722
|
flex: 1,
|
|
3978
4723
|
textAlign: "center",
|
|
3979
4724
|
fontWeight: 600,
|
|
@@ -3981,15 +4726,15 @@ function InterimButtonsView({
|
|
|
3981
4726
|
color: "#262833",
|
|
3982
4727
|
paddingRight: 80,
|
|
3983
4728
|
...bStyles.title
|
|
3984
|
-
}, children: /* @__PURE__ */ (0,
|
|
4729
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TitleContentSlot, { content: cardTitleContent }) })
|
|
3985
4730
|
] }),
|
|
3986
|
-
/* @__PURE__ */ (0,
|
|
3987
|
-
/* @__PURE__ */ (0,
|
|
3988
|
-
/* @__PURE__ */ (0,
|
|
3989
|
-
/* @__PURE__ */ (0,
|
|
4731
|
+
/* @__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" } }) }),
|
|
4732
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex" }, children: [
|
|
4733
|
+
/* @__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" } }) }),
|
|
4734
|
+
/* @__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
4735
|
] }),
|
|
3991
|
-
/* @__PURE__ */ (0,
|
|
3992
|
-
/* @__PURE__ */ (0,
|
|
4736
|
+
/* @__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" } }) }),
|
|
4737
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
3993
4738
|
height: 50,
|
|
3994
4739
|
borderRadius: 8,
|
|
3995
4740
|
marginTop: 16,
|
|
@@ -3998,7 +4743,7 @@ function InterimButtonsView({
|
|
|
3998
4743
|
...bStyles.submitButton,
|
|
3999
4744
|
opacity: 0.5
|
|
4000
4745
|
} }),
|
|
4001
|
-
/* @__PURE__ */ (0,
|
|
4746
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
4002
4747
|
@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
4003
4748
|
@keyframes flopay-interim-expand {
|
|
4004
4749
|
0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
|
|
@@ -4008,10 +4753,10 @@ function InterimButtonsView({
|
|
|
4008
4753
|
` })
|
|
4009
4754
|
] });
|
|
4010
4755
|
}
|
|
4011
|
-
return /* @__PURE__ */ (0,
|
|
4756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4012
4757
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4013
4758
|
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4014
|
-
/* @__PURE__ */ (0,
|
|
4759
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4015
4760
|
"button",
|
|
4016
4761
|
{
|
|
4017
4762
|
type: "button",
|
|
@@ -4051,10 +4796,10 @@ function InterimButtonsView({
|
|
|
4051
4796
|
onMouseUp: (e) => {
|
|
4052
4797
|
e.currentTarget.style.transform = "scale(1)";
|
|
4053
4798
|
},
|
|
4054
|
-
children: /* @__PURE__ */ (0,
|
|
4799
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardButtonContentSlot, { content: cardButtonContent })
|
|
4055
4800
|
}
|
|
4056
4801
|
),
|
|
4057
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4802
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
|
|
4058
4803
|
margin: "0.25rem 0",
|
|
4059
4804
|
padding: "0.625rem 0.875rem",
|
|
4060
4805
|
background: "#FEF2F2",
|
|
@@ -4068,22 +4813,22 @@ function InterimButtonsView({
|
|
|
4068
4813
|
gap: "0.5rem",
|
|
4069
4814
|
...bStyles.errorBanner
|
|
4070
4815
|
}, children: [
|
|
4071
|
-
/* @__PURE__ */ (0,
|
|
4816
|
+
/* @__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
4817
|
errorMessage
|
|
4073
4818
|
] }),
|
|
4074
|
-
/* @__PURE__ */ (0,
|
|
4819
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
4075
4820
|
] });
|
|
4076
4821
|
}
|
|
4077
4822
|
|
|
4078
4823
|
// src/checkout-form.tsx
|
|
4079
|
-
var
|
|
4080
|
-
var
|
|
4081
|
-
var
|
|
4082
|
-
var
|
|
4824
|
+
var import_js5 = require("@flopay/js");
|
|
4825
|
+
var import_shared9 = require("@flopay/shared");
|
|
4826
|
+
var import_react10 = require("react");
|
|
4827
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4083
4828
|
var WALLET_RESUME_KEY2 = "flopay_wallet_resume";
|
|
4084
|
-
var CheckoutForm = (0,
|
|
4829
|
+
var CheckoutForm = (0, import_react10.forwardRef)(
|
|
4085
4830
|
function CheckoutForm2(props, ref) {
|
|
4086
|
-
return /* @__PURE__ */ (0,
|
|
4831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
|
|
4087
4832
|
}
|
|
4088
4833
|
);
|
|
4089
4834
|
function CheckoutFormInner({
|
|
@@ -4112,34 +4857,34 @@ function CheckoutFormInner({
|
|
|
4112
4857
|
const paypalFlopay = usePayPalFloPay();
|
|
4113
4858
|
const elements = useElements();
|
|
4114
4859
|
const contextBillingUrl = useBillingApiUrl();
|
|
4115
|
-
const [processing, setProcessing] = (0,
|
|
4116
|
-
const [error, setError] = (0,
|
|
4117
|
-
const [is3DSActive, setIs3DSActive] = (0,
|
|
4860
|
+
const [processing, setProcessing] = (0, import_react10.useState)(false);
|
|
4861
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
4862
|
+
const [is3DSActive, setIs3DSActive] = (0, import_react10.useState)(false);
|
|
4118
4863
|
const displayError = externalError ?? error;
|
|
4119
4864
|
const isSubmitting = externalProcessing ?? processing;
|
|
4120
4865
|
const isSelfContained = !onTokenizedBody;
|
|
4121
4866
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
4122
|
-
const updateError = (0,
|
|
4867
|
+
const updateError = (0, import_react10.useCallback)(
|
|
4123
4868
|
(err) => {
|
|
4124
4869
|
setError(err);
|
|
4125
4870
|
onErrorChange?.(err);
|
|
4126
4871
|
},
|
|
4127
4872
|
[onErrorChange]
|
|
4128
4873
|
);
|
|
4129
|
-
const emitDecline = (0,
|
|
4874
|
+
const emitDecline = (0, import_react10.useCallback)(
|
|
4130
4875
|
(input, overrides) => {
|
|
4131
4876
|
onDecline?.(buildDeclineEvent("card", input, overrides));
|
|
4132
4877
|
},
|
|
4133
4878
|
[onDecline]
|
|
4134
4879
|
);
|
|
4135
|
-
const processPaymentInternal = (0,
|
|
4880
|
+
const processPaymentInternal = (0, import_react10.useCallback)(
|
|
4136
4881
|
async (tokenizedBody, completionPaymentMethodId) => {
|
|
4137
4882
|
setProcessing(true);
|
|
4138
4883
|
updateError(null);
|
|
4139
4884
|
const resolvedCompletionPaymentMethodId = completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
|
|
4140
4885
|
const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
|
|
4141
4886
|
try {
|
|
4142
|
-
const api = new
|
|
4887
|
+
const api = new import_js5.PaymentAPI(baseUrl);
|
|
4143
4888
|
const response = await api.processPayment(userId ?? "", {
|
|
4144
4889
|
sessionId,
|
|
4145
4890
|
tokenizedData: requestTokenizedBody,
|
|
@@ -4243,7 +4988,7 @@ function CheckoutFormInner({
|
|
|
4243
4988
|
},
|
|
4244
4989
|
[baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
|
|
4245
4990
|
);
|
|
4246
|
-
const dispatchTokenizedBody = (0,
|
|
4991
|
+
const dispatchTokenizedBody = (0, import_react10.useCallback)(
|
|
4247
4992
|
(tokenizedBody) => {
|
|
4248
4993
|
if (onTokenizedBody) {
|
|
4249
4994
|
onTokenizedBody(tokenizedBody);
|
|
@@ -4253,7 +4998,7 @@ function CheckoutFormInner({
|
|
|
4253
4998
|
},
|
|
4254
4999
|
[onTokenizedBody, processPaymentInternal]
|
|
4255
5000
|
);
|
|
4256
|
-
(0,
|
|
5001
|
+
(0, import_react10.useImperativeHandle)(innerRef, () => ({
|
|
4257
5002
|
async handleNextAction(secret) {
|
|
4258
5003
|
if (!flopay) return;
|
|
4259
5004
|
setIs3DSActive(true);
|
|
@@ -4280,7 +5025,7 @@ function CheckoutFormInner({
|
|
|
4280
5025
|
}
|
|
4281
5026
|
}
|
|
4282
5027
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
4283
|
-
(0,
|
|
5028
|
+
(0, import_react10.useEffect)(() => {
|
|
4284
5029
|
if (typeof window === "undefined") return;
|
|
4285
5030
|
const stored = localStorage.getItem(WALLET_RESUME_KEY2);
|
|
4286
5031
|
if (!stored) return;
|
|
@@ -4298,7 +5043,7 @@ function CheckoutFormInner({
|
|
|
4298
5043
|
localStorage.removeItem(WALLET_RESUME_KEY2);
|
|
4299
5044
|
}
|
|
4300
5045
|
}, [sessionId, dispatchTokenizedBody]);
|
|
4301
|
-
const handleSubmit = (0,
|
|
5046
|
+
const handleSubmit = (0, import_react10.useCallback)(
|
|
4302
5047
|
async (e) => {
|
|
4303
5048
|
e.preventDefault();
|
|
4304
5049
|
if (!flopay || !elements || isSubmitting) return;
|
|
@@ -4322,7 +5067,7 @@ function CheckoutFormInner({
|
|
|
4322
5067
|
return;
|
|
4323
5068
|
}
|
|
4324
5069
|
if (!sessionId || !email) {
|
|
4325
|
-
throw new
|
|
5070
|
+
throw new import_shared9.FloPayError("Missing sessionId or email", "validation_error");
|
|
4326
5071
|
}
|
|
4327
5072
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
4328
5073
|
method: "POST",
|
|
@@ -4346,7 +5091,7 @@ function CheckoutFormInner({
|
|
|
4346
5091
|
}
|
|
4347
5092
|
const intentJson = await intentResponse.json();
|
|
4348
5093
|
const intentClientSecret = intentJson.data?.id;
|
|
4349
|
-
if (!intentClientSecret) throw new
|
|
5094
|
+
if (!intentClientSecret) throw new import_shared9.FloPayError("No client_secret in payment intent response", "api_error");
|
|
4350
5095
|
const confirmResult = await flopay.confirmCardPayment({
|
|
4351
5096
|
clientSecret: intentClientSecret,
|
|
4352
5097
|
paymentMethodId: pmResult.paymentMethodId
|
|
@@ -4365,7 +5110,7 @@ function CheckoutFormInner({
|
|
|
4365
5110
|
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
4366
5111
|
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
4367
5112
|
if (!paymentIntentId) {
|
|
4368
|
-
const error2 = new
|
|
5113
|
+
const error2 = new import_shared9.FloPayError("No payment intent returned after confirmation.", "api_error");
|
|
4369
5114
|
updateError(error2.message);
|
|
4370
5115
|
onError?.(error2);
|
|
4371
5116
|
return;
|
|
@@ -4388,8 +5133,8 @@ function CheckoutFormInner({
|
|
|
4388
5133
|
[flopay, elements, isSubmitting, sessionId, email, baseUrl, isSelfContained, dispatchTokenizedBody, onError, updateError, emitDecline]
|
|
4389
5134
|
);
|
|
4390
5135
|
const isReady = flopay !== null && elements !== null;
|
|
4391
|
-
return /* @__PURE__ */ (0,
|
|
4392
|
-
(is3DSActive || isSubmitting) && /* @__PURE__ */ (0,
|
|
5136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5137
|
+
(is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-overlay", style: {
|
|
4393
5138
|
position: "absolute",
|
|
4394
5139
|
inset: 0,
|
|
4395
5140
|
background: "rgba(255,255,255,0.7)",
|
|
@@ -4398,12 +5143,12 @@ function CheckoutFormInner({
|
|
|
4398
5143
|
justifyContent: "center",
|
|
4399
5144
|
zIndex: 10
|
|
4400
5145
|
}, 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,
|
|
5146
|
+
!isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
|
|
5147
|
+
isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
5148
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaymentElement, { options: { layout } }),
|
|
5149
|
+
showAddress && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
|
|
5150
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
|
|
5151
|
+
children ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4407
5152
|
"button",
|
|
4408
5153
|
{
|
|
4409
5154
|
type: "submit",
|
|
@@ -4417,10 +5162,10 @@ function CheckoutFormInner({
|
|
|
4417
5162
|
}
|
|
4418
5163
|
|
|
4419
5164
|
// src/paypal-button.tsx
|
|
4420
|
-
var
|
|
4421
|
-
var
|
|
4422
|
-
var
|
|
4423
|
-
var
|
|
5165
|
+
var import_js6 = require("@flopay/js");
|
|
5166
|
+
var import_shared10 = require("@flopay/shared");
|
|
5167
|
+
var import_react11 = require("react");
|
|
5168
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4424
5169
|
function PayPalButton({
|
|
4425
5170
|
sessionId,
|
|
4426
5171
|
billingApiUrl,
|
|
@@ -4437,14 +5182,14 @@ function PayPalButton({
|
|
|
4437
5182
|
const flopay = useFloPay();
|
|
4438
5183
|
const elements = useElements();
|
|
4439
5184
|
const contextBillingUrl = useBillingApiUrl();
|
|
4440
|
-
const [ready, setReady] = (0,
|
|
4441
|
-
const [submitting, setSubmitting] = (0,
|
|
4442
|
-
const paypalResumeAttempted = (0,
|
|
5185
|
+
const [ready, setReady] = (0, import_react11.useState)(false);
|
|
5186
|
+
const [submitting, setSubmitting] = (0, import_react11.useState)(false);
|
|
5187
|
+
const paypalResumeAttempted = (0, import_react11.useRef)(false);
|
|
4443
5188
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
4444
|
-
const processPaymentInternal = (0,
|
|
5189
|
+
const processPaymentInternal = (0, import_react11.useCallback)(
|
|
4445
5190
|
async (tokenizedBody) => {
|
|
4446
5191
|
try {
|
|
4447
|
-
const api = new
|
|
5192
|
+
const api = new import_js6.PaymentAPI(baseUrl);
|
|
4448
5193
|
const response = await api.processPayment(userId ?? "", {
|
|
4449
5194
|
sessionId,
|
|
4450
5195
|
tokenizedData: tokenizedBody,
|
|
@@ -4468,7 +5213,7 @@ function PayPalButton({
|
|
|
4468
5213
|
},
|
|
4469
5214
|
[baseUrl, sessionId, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
|
|
4470
5215
|
);
|
|
4471
|
-
const dispatchTokenizedBody = (0,
|
|
5216
|
+
const dispatchTokenizedBody = (0, import_react11.useCallback)(
|
|
4472
5217
|
(body) => {
|
|
4473
5218
|
if (onTokenizedBody) {
|
|
4474
5219
|
onTokenizedBody(body);
|
|
@@ -4478,7 +5223,7 @@ function PayPalButton({
|
|
|
4478
5223
|
},
|
|
4479
5224
|
[onTokenizedBody, processPaymentInternal]
|
|
4480
5225
|
);
|
|
4481
|
-
(0,
|
|
5226
|
+
(0, import_react11.useEffect)(() => {
|
|
4482
5227
|
if (!flopay || paypalResumeAttempted.current) return;
|
|
4483
5228
|
const params = new URLSearchParams(window.location.search);
|
|
4484
5229
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -4526,13 +5271,13 @@ function PayPalButton({
|
|
|
4526
5271
|
}
|
|
4527
5272
|
})();
|
|
4528
5273
|
}, [flopay, dispatchTokenizedBody, onErrorChange]);
|
|
4529
|
-
const handlePayPalConfirm = (0,
|
|
5274
|
+
const handlePayPalConfirm = (0, import_react11.useCallback)(async () => {
|
|
4530
5275
|
if (!flopay || !elements) return;
|
|
4531
5276
|
try {
|
|
4532
5277
|
setSubmitting(true);
|
|
4533
5278
|
onErrorChange?.(null);
|
|
4534
5279
|
if (!sessionId || !email) {
|
|
4535
|
-
throw new
|
|
5280
|
+
throw new import_shared10.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
|
|
4536
5281
|
}
|
|
4537
5282
|
const result = await flopay.confirmPayPalPayment({
|
|
4538
5283
|
billingApiUrl: baseUrl,
|
|
@@ -4559,11 +5304,11 @@ function PayPalButton({
|
|
|
4559
5304
|
}
|
|
4560
5305
|
}, [flopay, elements, sessionId, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
|
|
4561
5306
|
if (!flopay || !elements) {
|
|
4562
|
-
return /* @__PURE__ */ (0,
|
|
5307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
|
|
4563
5308
|
}
|
|
4564
|
-
return /* @__PURE__ */ (0,
|
|
4565
|
-
!ready && /* @__PURE__ */ (0,
|
|
4566
|
-
/* @__PURE__ */ (0,
|
|
5309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
5310
|
+
!ready && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
|
|
5311
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4567
5312
|
"button",
|
|
4568
5313
|
{
|
|
4569
5314
|
type: "button",
|
|
@@ -4585,7 +5330,7 @@ function PayPalButton({
|
|
|
4585
5330
|
children: submitting ? "Processing..." : "PayPal"
|
|
4586
5331
|
}
|
|
4587
5332
|
) }),
|
|
4588
|
-
(submitting || isProcessing) && /* @__PURE__ */ (0,
|
|
5333
|
+
(submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
|
|
4589
5334
|
position: "fixed",
|
|
4590
5335
|
inset: 0,
|
|
4591
5336
|
background: "rgba(0,0,0,0.4)",
|
|
@@ -4593,7 +5338,7 @@ function PayPalButton({
|
|
|
4593
5338
|
alignItems: "center",
|
|
4594
5339
|
justifyContent: "center",
|
|
4595
5340
|
zIndex: 1e3
|
|
4596
|
-
}, children: /* @__PURE__ */ (0,
|
|
5341
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
|
|
4597
5342
|
background: "white",
|
|
4598
5343
|
borderRadius: 8,
|
|
4599
5344
|
padding: "1.5rem",
|
|
@@ -4605,20 +5350,20 @@ function PayPalButton({
|
|
|
4605
5350
|
}
|
|
4606
5351
|
|
|
4607
5352
|
// src/automatic-payment-button.tsx
|
|
4608
|
-
var
|
|
4609
|
-
var
|
|
4610
|
-
var
|
|
4611
|
-
var
|
|
5353
|
+
var import_react12 = require("react");
|
|
5354
|
+
var import_js7 = require("@flopay/js");
|
|
5355
|
+
var import_shared11 = require("@flopay/shared");
|
|
5356
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4612
5357
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
|
|
4613
5358
|
var PAYPAL_RESUME_STORAGE_KEY2 = "flopay_automatic_payment_button_resume";
|
|
4614
5359
|
function sleep2(ms) {
|
|
4615
5360
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4616
5361
|
}
|
|
4617
5362
|
function coerceError(err, fallbackMessage) {
|
|
4618
|
-
if (err instanceof
|
|
5363
|
+
if (err instanceof import_shared11.FloPayError) {
|
|
4619
5364
|
return err;
|
|
4620
5365
|
}
|
|
4621
|
-
return new
|
|
5366
|
+
return new import_shared11.FloPayError(
|
|
4622
5367
|
err instanceof Error ? err.message : fallbackMessage,
|
|
4623
5368
|
"api_error"
|
|
4624
5369
|
);
|
|
@@ -4725,11 +5470,11 @@ function FloPayAutomaticPaymentButton({
|
|
|
4725
5470
|
style,
|
|
4726
5471
|
...buttonProps
|
|
4727
5472
|
}) {
|
|
4728
|
-
const resolvedBillingUrl = (0,
|
|
4729
|
-
() => (0,
|
|
5473
|
+
const resolvedBillingUrl = (0, import_react12.useMemo)(
|
|
5474
|
+
() => (0, import_shared11.resolveBillingApiUrl)(billingApiUrl),
|
|
4730
5475
|
[billingApiUrl]
|
|
4731
5476
|
);
|
|
4732
|
-
const createSessionDraft = (0,
|
|
5477
|
+
const createSessionDraft = (0, import_react12.useMemo)(
|
|
4733
5478
|
() => resolveCreateSessionDraft({
|
|
4734
5479
|
createSession,
|
|
4735
5480
|
clientId,
|
|
@@ -4755,43 +5500,47 @@ function FloPayAutomaticPaymentButton({
|
|
|
4755
5500
|
utmMetadata
|
|
4756
5501
|
]
|
|
4757
5502
|
);
|
|
4758
|
-
const [isProcessing, setIsProcessing] = (0,
|
|
4759
|
-
const [overlayStatus, setOverlayStatus] = (0,
|
|
4760
|
-
const [overlayError, setOverlayError] = (0,
|
|
4761
|
-
const [fallbackSession, setFallbackSession] = (0,
|
|
4762
|
-
const automaticPaymentToken = (0,
|
|
5503
|
+
const [isProcessing, setIsProcessing] = (0, import_react12.useState)(false);
|
|
5504
|
+
const [overlayStatus, setOverlayStatus] = (0, import_react12.useState)(null);
|
|
5505
|
+
const [overlayError, setOverlayError] = (0, import_react12.useState)(null);
|
|
5506
|
+
const [fallbackSession, setFallbackSession] = (0, import_react12.useState)(null);
|
|
5507
|
+
const automaticPaymentToken = (0, import_react12.useMemo)(
|
|
4763
5508
|
() => paymentMethodId ? {
|
|
4764
5509
|
id: paymentMethodId,
|
|
4765
|
-
|
|
5510
|
+
// Saved PayPal `user_payment_method` records are submitted with
|
|
5511
|
+
// `type: 'paypal'` so the backend routes the upsell through the
|
|
5512
|
+
// direct PayPal gateway's vaulted-token flow. Card and wallet PMs
|
|
5513
|
+
// continue to use `type: 'card'`.
|
|
5514
|
+
type: checkoutMethod === "paypal" ? "paypal" : "card",
|
|
4766
5515
|
...checkoutMethod === "paypal" ? { isPaypal: true } : {}
|
|
4767
5516
|
} : void 0,
|
|
4768
5517
|
[checkoutMethod, paymentMethodId]
|
|
4769
5518
|
);
|
|
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,
|
|
5519
|
+
const isMountedRef = (0, import_react12.useRef)(true);
|
|
5520
|
+
const resumeAttemptedRef = (0, import_react12.useRef)(false);
|
|
5521
|
+
const fallbackSessionRef = (0, import_react12.useRef)(fallbackSession);
|
|
5522
|
+
const onSuccessRef = (0, import_react12.useRef)(onSuccess);
|
|
5523
|
+
const onErrorRef = (0, import_react12.useRef)(onError);
|
|
5524
|
+
const onDeclineRef = (0, import_react12.useRef)(onDecline);
|
|
5525
|
+
(0, import_react12.useEffect)(() => {
|
|
4777
5526
|
fallbackSessionRef.current = fallbackSession;
|
|
4778
5527
|
}, [fallbackSession]);
|
|
4779
|
-
(0,
|
|
5528
|
+
(0, import_react12.useEffect)(() => {
|
|
4780
5529
|
onSuccessRef.current = onSuccess;
|
|
4781
5530
|
}, [onSuccess]);
|
|
4782
|
-
(0,
|
|
5531
|
+
(0, import_react12.useEffect)(() => {
|
|
4783
5532
|
onErrorRef.current = onError;
|
|
4784
5533
|
}, [onError]);
|
|
4785
|
-
(0,
|
|
5534
|
+
(0, import_react12.useEffect)(() => {
|
|
4786
5535
|
onDeclineRef.current = onDecline;
|
|
4787
5536
|
}, [onDecline]);
|
|
4788
|
-
(0,
|
|
5537
|
+
(0, import_react12.useEffect)(() => {
|
|
4789
5538
|
isMountedRef.current = true;
|
|
4790
5539
|
return () => {
|
|
4791
5540
|
isMountedRef.current = false;
|
|
4792
5541
|
};
|
|
4793
5542
|
}, []);
|
|
4794
|
-
(0,
|
|
5543
|
+
(0, import_react12.useEffect)(() => {
|
|
4795
5544
|
if (!fallbackSession || typeof window === "undefined") {
|
|
4796
5545
|
return;
|
|
4797
5546
|
}
|
|
@@ -4805,13 +5554,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
4805
5554
|
window.removeEventListener("keydown", handleKeyDown);
|
|
4806
5555
|
};
|
|
4807
5556
|
}, [fallbackSession]);
|
|
4808
|
-
const emitDecline = (0,
|
|
5557
|
+
const emitDecline = (0, import_react12.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
|
|
4809
5558
|
onDeclineRef.current?.(buildDeclineEvent(method, error, {
|
|
4810
5559
|
code: error.code,
|
|
4811
5560
|
declineCode: error.declineCode
|
|
4812
5561
|
}));
|
|
4813
5562
|
}, []);
|
|
4814
|
-
const showSuccess = (0,
|
|
5563
|
+
const showSuccess = (0, import_react12.useCallback)(async (event) => {
|
|
4815
5564
|
if (!isMountedRef.current) return;
|
|
4816
5565
|
setOverlayError(null);
|
|
4817
5566
|
setOverlayStatus("success");
|
|
@@ -4819,7 +5568,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4819
5568
|
if (!isMountedRef.current) return;
|
|
4820
5569
|
onSuccessRef.current?.(event);
|
|
4821
5570
|
}, []);
|
|
4822
|
-
const showError = (0,
|
|
5571
|
+
const showError = (0, import_react12.useCallback)(async (error, options) => {
|
|
4823
5572
|
if (!isMountedRef.current) return;
|
|
4824
5573
|
onErrorRef.current?.(error);
|
|
4825
5574
|
if (options?.emitDecline) {
|
|
@@ -4829,10 +5578,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
4829
5578
|
setOverlayStatus("error");
|
|
4830
5579
|
await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
|
|
4831
5580
|
}, [emitDecline]);
|
|
4832
|
-
const processResolvedSession = (0,
|
|
5581
|
+
const processResolvedSession = (0, import_react12.useCallback)(async (apiResult, resolvedSessionId, options) => {
|
|
4833
5582
|
const session = apiResult.data.session ?? null;
|
|
4834
5583
|
if (!session) {
|
|
4835
|
-
throw new
|
|
5584
|
+
throw new import_shared11.FloPayError("No session data returned", "api_error");
|
|
4836
5585
|
}
|
|
4837
5586
|
if (session.status === "complete") {
|
|
4838
5587
|
await showSuccess({
|
|
@@ -4844,7 +5593,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
4844
5593
|
return;
|
|
4845
5594
|
}
|
|
4846
5595
|
if (session.status === "expired") {
|
|
4847
|
-
throw new
|
|
5596
|
+
throw new import_shared11.FloPayError("Checkout session has expired.", "api_error", {
|
|
4848
5597
|
code: "checkout_session_expired"
|
|
4849
5598
|
});
|
|
4850
5599
|
}
|
|
@@ -4854,13 +5603,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
4854
5603
|
const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
|
|
4855
5604
|
const shouldRetryPayPalClientSide = checkoutMethod === "paypal" && automaticPaymentToken?.isPaypal === true && options?.fromCreateSession === true;
|
|
4856
5605
|
if (apiResult.autoProcessingPending) {
|
|
4857
|
-
const api = new
|
|
5606
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
4858
5607
|
const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
|
|
4859
5608
|
initialDelayMs: apiResult.autoProcessingPending.retryAfterMs
|
|
4860
5609
|
});
|
|
4861
5610
|
const completedSession = completed.data.session;
|
|
4862
5611
|
if (!completedSession || completedSession.status !== "complete") {
|
|
4863
|
-
throw new
|
|
5612
|
+
throw new import_shared11.FloPayError("Automatic payment failed. Please try again.", "api_error", {
|
|
4864
5613
|
code: completedSession?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
4865
5614
|
});
|
|
4866
5615
|
}
|
|
@@ -5052,14 +5801,14 @@ function FloPayAutomaticPaymentButton({
|
|
|
5052
5801
|
showError,
|
|
5053
5802
|
showSuccess
|
|
5054
5803
|
]);
|
|
5055
|
-
const handleButtonClick = (0,
|
|
5804
|
+
const handleButtonClick = (0, import_react12.useCallback)(async (event) => {
|
|
5056
5805
|
buttonProps.onClick?.(event);
|
|
5057
5806
|
if (event.defaultPrevented || disabled || isProcessing) {
|
|
5058
5807
|
return;
|
|
5059
5808
|
}
|
|
5060
5809
|
setFallbackSession(null);
|
|
5061
5810
|
if (sessionId && createSessionDraft) {
|
|
5062
|
-
const error = new
|
|
5811
|
+
const error = new import_shared11.FloPayError(
|
|
5063
5812
|
"Provide either sessionId or create-session props, not both.",
|
|
5064
5813
|
"validation_error"
|
|
5065
5814
|
);
|
|
@@ -5071,7 +5820,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5071
5820
|
return;
|
|
5072
5821
|
}
|
|
5073
5822
|
if (!sessionId && !createSessionDraft) {
|
|
5074
|
-
const error = new
|
|
5823
|
+
const error = new import_shared11.FloPayError(
|
|
5075
5824
|
"Provide a sessionId or the props required to create an automatic payment session.",
|
|
5076
5825
|
"validation_error"
|
|
5077
5826
|
);
|
|
@@ -5086,7 +5835,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5086
5835
|
setOverlayError(null);
|
|
5087
5836
|
setOverlayStatus("processing");
|
|
5088
5837
|
try {
|
|
5089
|
-
const api = new
|
|
5838
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
5090
5839
|
if (sessionId) {
|
|
5091
5840
|
const result = await api.getUnifiedCheckoutSession(sessionId);
|
|
5092
5841
|
await processResolvedSession(result, sessionId);
|
|
@@ -5101,7 +5850,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5101
5850
|
fromCreateSession: true
|
|
5102
5851
|
});
|
|
5103
5852
|
} catch (err) {
|
|
5104
|
-
if (err instanceof
|
|
5853
|
+
if (err instanceof import_shared11.FloPayError && err.code === "session_auto_completed") {
|
|
5105
5854
|
await showSuccess({
|
|
5106
5855
|
result: { status: "succeeded" },
|
|
5107
5856
|
session: null,
|
|
@@ -5134,7 +5883,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5134
5883
|
showError,
|
|
5135
5884
|
showSuccess
|
|
5136
5885
|
]);
|
|
5137
|
-
const handleFallbackComplete = (0,
|
|
5886
|
+
const handleFallbackComplete = (0, import_react12.useCallback)((result) => {
|
|
5138
5887
|
const activeFallback = fallbackSessionRef.current;
|
|
5139
5888
|
setFallbackSession(null);
|
|
5140
5889
|
onSuccessRef.current?.({
|
|
@@ -5144,13 +5893,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
5144
5893
|
autoCompleted: false
|
|
5145
5894
|
});
|
|
5146
5895
|
}, []);
|
|
5147
|
-
const handleFallbackError = (0,
|
|
5896
|
+
const handleFallbackError = (0, import_react12.useCallback)((error) => {
|
|
5148
5897
|
onErrorRef.current?.(error);
|
|
5149
5898
|
}, []);
|
|
5150
|
-
const handleFallbackDecline = (0,
|
|
5899
|
+
const handleFallbackDecline = (0, import_react12.useCallback)((decline) => {
|
|
5151
5900
|
onDeclineRef.current?.(decline);
|
|
5152
5901
|
}, []);
|
|
5153
|
-
(0,
|
|
5902
|
+
(0, import_react12.useEffect)(() => {
|
|
5154
5903
|
if (typeof window === "undefined" || resumeAttemptedRef.current) {
|
|
5155
5904
|
return;
|
|
5156
5905
|
}
|
|
@@ -5171,7 +5920,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5171
5920
|
try {
|
|
5172
5921
|
if (params.get("redirect_status") === "failed") {
|
|
5173
5922
|
throw Object.assign(
|
|
5174
|
-
new
|
|
5923
|
+
new import_shared11.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
|
|
5175
5924
|
{ checkoutMethod: "paypal" }
|
|
5176
5925
|
);
|
|
5177
5926
|
}
|
|
@@ -5187,14 +5936,14 @@ function FloPayAutomaticPaymentButton({
|
|
|
5187
5936
|
const paypalStripe = (paypalFlopay ?? flopay).getRawProvider();
|
|
5188
5937
|
if (!paypalStripe) {
|
|
5189
5938
|
throw Object.assign(
|
|
5190
|
-
new
|
|
5939
|
+
new import_shared11.FloPayError("PayPal is not available.", "api_error"),
|
|
5191
5940
|
{ checkoutMethod: "paypal" }
|
|
5192
5941
|
);
|
|
5193
5942
|
}
|
|
5194
5943
|
const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
|
|
5195
5944
|
if (error) {
|
|
5196
5945
|
throw Object.assign(
|
|
5197
|
-
new
|
|
5946
|
+
new import_shared11.FloPayError(
|
|
5198
5947
|
error.message ?? "Failed to retrieve PayPal payment status.",
|
|
5199
5948
|
"api_error",
|
|
5200
5949
|
{ code: error.code }
|
|
@@ -5205,23 +5954,23 @@ function FloPayAutomaticPaymentButton({
|
|
|
5205
5954
|
const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
|
|
5206
5955
|
if (!paymentIntent || resultStatus === "failed") {
|
|
5207
5956
|
throw Object.assign(
|
|
5208
|
-
new
|
|
5957
|
+
new import_shared11.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
|
|
5209
5958
|
{ checkoutMethod: "paypal" }
|
|
5210
5959
|
);
|
|
5211
5960
|
}
|
|
5212
5961
|
const paymentMethodId2 = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
5213
5962
|
if (!resumeState.sessionId) {
|
|
5214
5963
|
throw Object.assign(
|
|
5215
|
-
new
|
|
5964
|
+
new import_shared11.FloPayError("Missing session id on PayPal resume.", "api_error"),
|
|
5216
5965
|
{ checkoutMethod: "paypal" }
|
|
5217
5966
|
);
|
|
5218
5967
|
}
|
|
5219
|
-
const api = new
|
|
5968
|
+
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
5220
5969
|
const sessionResult = await api.getUnifiedCheckoutSession(resumeState.sessionId);
|
|
5221
5970
|
let resumeSession = sessionResult.data.session;
|
|
5222
5971
|
if (!resumeSession) {
|
|
5223
5972
|
throw Object.assign(
|
|
5224
|
-
new
|
|
5973
|
+
new import_shared11.FloPayError("Could not load session to capture PayPal payment.", "api_error"),
|
|
5225
5974
|
{ checkoutMethod: "paypal" }
|
|
5226
5975
|
);
|
|
5227
5976
|
}
|
|
@@ -5240,7 +5989,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5240
5989
|
});
|
|
5241
5990
|
if (processResult.type !== "success") {
|
|
5242
5991
|
throw Object.assign(
|
|
5243
|
-
new
|
|
5992
|
+
new import_shared11.FloPayError("Failed to finalize PayPal payment.", "api_error"),
|
|
5244
5993
|
{ checkoutMethod: "paypal" }
|
|
5245
5994
|
);
|
|
5246
5995
|
}
|
|
@@ -5281,8 +6030,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
5281
6030
|
}
|
|
5282
6031
|
})();
|
|
5283
6032
|
}, [locale, resolvedBillingUrl, showError, showSuccess]);
|
|
5284
|
-
const bStyles = (0,
|
|
5285
|
-
const base = (0,
|
|
6033
|
+
const bStyles = (0, import_react12.useMemo)(() => {
|
|
6034
|
+
const base = (0, import_shared11.resolveButtonsLayoutTheme)(buttonsTheme);
|
|
5286
6035
|
if (!stylesOverride) return base;
|
|
5287
6036
|
return {
|
|
5288
6037
|
...base,
|
|
@@ -5291,8 +6040,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
5291
6040
|
};
|
|
5292
6041
|
}, [buttonsTheme, stylesOverride]);
|
|
5293
6042
|
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,
|
|
6043
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6044
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5296
6045
|
"button",
|
|
5297
6046
|
{
|
|
5298
6047
|
...buttonProps,
|
|
@@ -5333,17 +6082,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
5333
6082
|
e.currentTarget.style.transform = "scale(1)";
|
|
5334
6083
|
}
|
|
5335
6084
|
},
|
|
5336
|
-
children: /* @__PURE__ */ (0,
|
|
6085
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CardButtonContentSlot, { content: children })
|
|
5337
6086
|
}
|
|
5338
6087
|
),
|
|
5339
|
-
overlayStatus && /* @__PURE__ */ (0,
|
|
6088
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5340
6089
|
ProcessingOverlay,
|
|
5341
6090
|
{
|
|
5342
6091
|
status: overlayStatus,
|
|
5343
6092
|
errorMessage: overlayError
|
|
5344
6093
|
}
|
|
5345
6094
|
),
|
|
5346
|
-
fallbackSession && /* @__PURE__ */ (0,
|
|
6095
|
+
fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5347
6096
|
"div",
|
|
5348
6097
|
{
|
|
5349
6098
|
"data-testid": "flopay-automatic-payment-fallback",
|
|
@@ -5364,7 +6113,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5364
6113
|
padding: "1.5rem",
|
|
5365
6114
|
zIndex: 1100
|
|
5366
6115
|
},
|
|
5367
|
-
children: /* @__PURE__ */ (0,
|
|
6116
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5368
6117
|
"div",
|
|
5369
6118
|
{
|
|
5370
6119
|
style: {
|
|
@@ -5380,7 +6129,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5380
6129
|
flexDirection: "column",
|
|
5381
6130
|
gap: "1rem"
|
|
5382
6131
|
},
|
|
5383
|
-
children: /* @__PURE__ */ (0,
|
|
6132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5384
6133
|
FloPayCheckout,
|
|
5385
6134
|
{
|
|
5386
6135
|
sessionId: fallbackSession.sessionId,
|
|
@@ -5408,6 +6157,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5408
6157
|
CardExpiryElement,
|
|
5409
6158
|
CardNumberElement,
|
|
5410
6159
|
CheckoutForm,
|
|
6160
|
+
DirectPayPalButton,
|
|
5411
6161
|
FloPayAutomaticPaymentButton,
|
|
5412
6162
|
FloPayCheckout,
|
|
5413
6163
|
FloPayProvider,
|