@flopay/react 1.2.8 → 1.3.1
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 +76 -1
- package/dist/index.cjs +1455 -637
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -4
- package/dist/index.d.ts +104 -4
- package/dist/index.mjs +1258 -440
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -100,7 +100,7 @@ function FloPayProvider({
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// src/flopay-checkout.tsx
|
|
103
|
-
import
|
|
103
|
+
import React8, { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
|
|
104
104
|
import { PaymentAPI as PaymentAPI4 } from "@flopay/js";
|
|
105
105
|
import { SDK_VERSION, FloPayError as FloPayError5, resolveBillingApiUrl as resolveBillingApiUrl3, buildCheckoutDisplayData, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme2, resolveTheme as resolveTheme2 } from "@flopay/shared";
|
|
106
106
|
|
|
@@ -248,9 +248,10 @@ import {
|
|
|
248
248
|
resolveAVSConfig,
|
|
249
249
|
isAVSFieldVisible,
|
|
250
250
|
getStateFromPostalCode,
|
|
251
|
-
|
|
251
|
+
isPostalCodeSupported,
|
|
252
|
+
isValidPostalCode,
|
|
253
|
+
getPostalCodeExample,
|
|
252
254
|
filterStripeMethodsByCountry,
|
|
253
|
-
filterStripeMethodsByAmount,
|
|
254
255
|
getStripeMethodDisplayName,
|
|
255
256
|
hasVendoredStripeMethodLogo,
|
|
256
257
|
needsStripeMethodExplicitConfirm,
|
|
@@ -259,7 +260,80 @@ import {
|
|
|
259
260
|
stripeExpressMethodToOptionKey
|
|
260
261
|
} from "@flopay/shared";
|
|
261
262
|
import { PaymentAPI as PaymentAPI2 } from "@flopay/js";
|
|
262
|
-
|
|
263
|
+
|
|
264
|
+
// src/vault-card-fields.tsx
|
|
265
|
+
import { useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
266
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
267
|
+
function VaultCardFields({
|
|
268
|
+
capture,
|
|
269
|
+
html,
|
|
270
|
+
messageToken,
|
|
271
|
+
expectedOrigin,
|
|
272
|
+
theme,
|
|
273
|
+
containerStyle,
|
|
274
|
+
onReady,
|
|
275
|
+
onError,
|
|
276
|
+
onValidation
|
|
277
|
+
}) {
|
|
278
|
+
const containerRef = useRef2(null);
|
|
279
|
+
const onReadyRef = useRef2(onReady);
|
|
280
|
+
const onErrorRef = useRef2(onError);
|
|
281
|
+
const onValidationRef = useRef2(onValidation);
|
|
282
|
+
onReadyRef.current = onReady;
|
|
283
|
+
onErrorRef.current = onError;
|
|
284
|
+
onValidationRef.current = onValidation;
|
|
285
|
+
const themeRef = useRef2(theme);
|
|
286
|
+
themeRef.current = theme;
|
|
287
|
+
useEffect3(() => {
|
|
288
|
+
const el = containerRef.current;
|
|
289
|
+
if (!el) return;
|
|
290
|
+
let active = true;
|
|
291
|
+
let readyEmitted = false;
|
|
292
|
+
const emitReadyOnce = () => {
|
|
293
|
+
if (!active || readyEmitted) return;
|
|
294
|
+
readyEmitted = true;
|
|
295
|
+
onReadyRef.current?.();
|
|
296
|
+
};
|
|
297
|
+
const offReady = capture.on("ready", () => {
|
|
298
|
+
emitReadyOnce();
|
|
299
|
+
});
|
|
300
|
+
const offError = capture.on("error", (event) => {
|
|
301
|
+
onErrorRef.current?.(event.message ?? "There was a problem loading the secure card form.");
|
|
302
|
+
});
|
|
303
|
+
const offValidation = capture.on("validation", (event) => {
|
|
304
|
+
onValidationRef.current?.(event.message ?? null);
|
|
305
|
+
});
|
|
306
|
+
const mountOptions = {
|
|
307
|
+
html,
|
|
308
|
+
...messageToken ? { messageToken } : {},
|
|
309
|
+
...expectedOrigin ? { expectedOrigin } : {},
|
|
310
|
+
...themeRef.current ? { theme: themeRef.current } : {}
|
|
311
|
+
};
|
|
312
|
+
capture.mount(el, mountOptions).then(() => {
|
|
313
|
+
emitReadyOnce();
|
|
314
|
+
}).catch((err) => {
|
|
315
|
+
if (active) {
|
|
316
|
+
onErrorRef.current?.(
|
|
317
|
+
err instanceof Error ? err.message : "Failed to load the secure card form."
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
return () => {
|
|
322
|
+
active = false;
|
|
323
|
+
offReady();
|
|
324
|
+
offError();
|
|
325
|
+
offValidation();
|
|
326
|
+
capture.unmount();
|
|
327
|
+
};
|
|
328
|
+
}, [capture, html, messageToken, expectedOrigin]);
|
|
329
|
+
useEffect3(() => {
|
|
330
|
+
if (theme) capture.applyTheme?.(theme);
|
|
331
|
+
}, [capture, theme]);
|
|
332
|
+
return /* @__PURE__ */ jsx4("div", { ref: containerRef, "data-testid": "flopay-vault-card-fields", style: containerStyle });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/split-card-form.tsx
|
|
336
|
+
import React7, { forwardRef, useCallback, useContext as useContext3, useEffect as useEffect5, useImperativeHandle, useMemo as useMemo3, useRef as useRef4, useState as useState3 } from "react";
|
|
263
337
|
|
|
264
338
|
// src/hooks.ts
|
|
265
339
|
import { useContext as useContext2 } from "react";
|
|
@@ -286,14 +360,14 @@ function useBillingApiUrl() {
|
|
|
286
360
|
|
|
287
361
|
// src/processing-overlay.tsx
|
|
288
362
|
import "react";
|
|
289
|
-
import { jsx as
|
|
363
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
290
364
|
var PROCESSING_OVERLAY_SUCCESS_DELAY_MS = 1200;
|
|
291
365
|
var PROCESSING_OVERLAY_ERROR_DELAY_MS = 1500;
|
|
292
366
|
function ProcessingOverlay({
|
|
293
367
|
status,
|
|
294
368
|
errorMessage
|
|
295
369
|
}) {
|
|
296
|
-
return /* @__PURE__ */
|
|
370
|
+
return /* @__PURE__ */ jsx5(
|
|
297
371
|
"div",
|
|
298
372
|
{
|
|
299
373
|
"data-testid": "flopay-processing-overlay",
|
|
@@ -337,14 +411,14 @@ function ProcessingOverlay({
|
|
|
337
411
|
xmlns: "http://www.w3.org/2000/svg",
|
|
338
412
|
style: { animation: "flopay-spin 0.8s linear infinite" },
|
|
339
413
|
children: [
|
|
340
|
-
/* @__PURE__ */
|
|
341
|
-
/* @__PURE__ */
|
|
414
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "10", stroke: "#e5e7eb", strokeWidth: "3" }),
|
|
415
|
+
/* @__PURE__ */ jsx5("path", { d: "M4 12a8 8 0 018-8v3a5 5 0 00-5 5H4z", fill: "#4A49FF" })
|
|
342
416
|
]
|
|
343
417
|
}
|
|
344
418
|
),
|
|
345
|
-
status === "success" && /* @__PURE__ */
|
|
346
|
-
/* @__PURE__ */
|
|
347
|
-
/* @__PURE__ */
|
|
419
|
+
status === "success" && /* @__PURE__ */ jsx5("div", { style: { animation: "flopay-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)" }, children: /* @__PURE__ */ jsxs2("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
420
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "11", fill: "#22c55e" }),
|
|
421
|
+
/* @__PURE__ */ jsx5(
|
|
348
422
|
"path",
|
|
349
423
|
{
|
|
350
424
|
d: "M7 12.5l3 3 7-7",
|
|
@@ -360,9 +434,9 @@ function ProcessingOverlay({
|
|
|
360
434
|
}
|
|
361
435
|
)
|
|
362
436
|
] }) }),
|
|
363
|
-
status === "error" && /* @__PURE__ */
|
|
364
|
-
/* @__PURE__ */
|
|
365
|
-
/* @__PURE__ */
|
|
437
|
+
status === "error" && /* @__PURE__ */ jsx5("div", { style: { animation: "flopay-shake 0.4s ease" }, children: /* @__PURE__ */ jsxs2("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
438
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "11", fill: "#ef4444" }),
|
|
439
|
+
/* @__PURE__ */ jsx5(
|
|
366
440
|
"path",
|
|
367
441
|
{
|
|
368
442
|
d: "M8 8l8 8M16 8l-8 8",
|
|
@@ -394,7 +468,7 @@ function ProcessingOverlay({
|
|
|
394
468
|
]
|
|
395
469
|
}
|
|
396
470
|
),
|
|
397
|
-
status === "success" && /* @__PURE__ */
|
|
471
|
+
status === "success" && /* @__PURE__ */ jsx5(
|
|
398
472
|
"p",
|
|
399
473
|
{
|
|
400
474
|
style: {
|
|
@@ -408,7 +482,7 @@ function ProcessingOverlay({
|
|
|
408
482
|
children: "You will be automatically redirected, do not close or navigate away from this window."
|
|
409
483
|
}
|
|
410
484
|
),
|
|
411
|
-
status === "error" && errorMessage && /* @__PURE__ */
|
|
485
|
+
status === "error" && errorMessage && /* @__PURE__ */ jsx5(
|
|
412
486
|
"p",
|
|
413
487
|
{
|
|
414
488
|
style: {
|
|
@@ -422,7 +496,7 @@ function ProcessingOverlay({
|
|
|
422
496
|
children: errorMessage
|
|
423
497
|
}
|
|
424
498
|
),
|
|
425
|
-
/* @__PURE__ */
|
|
499
|
+
/* @__PURE__ */ jsx5("style", { children: `
|
|
426
500
|
@keyframes flopay-spin { to { transform: rotate(360deg); } }
|
|
427
501
|
@keyframes flopay-pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
|
|
428
502
|
@keyframes flopay-draw { to { stroke-dashoffset: 0; } }
|
|
@@ -696,11 +770,11 @@ function isInAppBrowser(userAgent) {
|
|
|
696
770
|
}
|
|
697
771
|
|
|
698
772
|
// src/direct-paypal-button.tsx
|
|
699
|
-
import { useEffect as
|
|
773
|
+
import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState2 } from "react";
|
|
700
774
|
import { loadScript } from "@paypal/paypal-js";
|
|
701
775
|
import { PaymentAPI } from "@flopay/js";
|
|
702
776
|
import { FloPayError as FloPayError2, normalizeGatewayEnvironment } from "@flopay/shared";
|
|
703
|
-
import { jsx as
|
|
777
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
704
778
|
var DEFAULT_BUTTON_HEIGHT = 45;
|
|
705
779
|
function DirectPayPalButton({
|
|
706
780
|
sessionId,
|
|
@@ -723,7 +797,7 @@ function DirectPayPalButton({
|
|
|
723
797
|
existingOrderId,
|
|
724
798
|
debug = false
|
|
725
799
|
}) {
|
|
726
|
-
const containerRef =
|
|
800
|
+
const containerRef = useRef3(null);
|
|
727
801
|
const [ready, setReady] = useState2(false);
|
|
728
802
|
const [failed, setFailed] = useState2(false);
|
|
729
803
|
const [submitting, setSubmitting] = useState2(false);
|
|
@@ -733,52 +807,52 @@ function DirectPayPalButton({
|
|
|
733
807
|
if (!debug) return;
|
|
734
808
|
setDebugLines((prev) => [...prev, `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 23)} ${line}`]);
|
|
735
809
|
};
|
|
736
|
-
const onTokenizedBodyRef =
|
|
737
|
-
const onCompleteRef =
|
|
738
|
-
const onErrorChangeRef =
|
|
739
|
-
const onDeclineRef =
|
|
740
|
-
const onButtonClickRef =
|
|
741
|
-
const onLoadStateChangeRef =
|
|
742
|
-
const runBeforeButtonClickRef =
|
|
743
|
-
const sessionRef =
|
|
744
|
-
const emailRef =
|
|
745
|
-
const nonceRef =
|
|
746
|
-
const beforeClickRef =
|
|
747
|
-
|
|
810
|
+
const onTokenizedBodyRef = useRef3(onTokenizedBody);
|
|
811
|
+
const onCompleteRef = useRef3(onComplete);
|
|
812
|
+
const onErrorChangeRef = useRef3(onErrorChange);
|
|
813
|
+
const onDeclineRef = useRef3(onDecline);
|
|
814
|
+
const onButtonClickRef = useRef3(onButtonClick);
|
|
815
|
+
const onLoadStateChangeRef = useRef3(onLoadStateChange);
|
|
816
|
+
const runBeforeButtonClickRef = useRef3(runBeforeButtonClick);
|
|
817
|
+
const sessionRef = useRef3(session);
|
|
818
|
+
const emailRef = useRef3(email);
|
|
819
|
+
const nonceRef = useRef3(nonce);
|
|
820
|
+
const beforeClickRef = useRef3(null);
|
|
821
|
+
useEffect4(() => {
|
|
748
822
|
onTokenizedBodyRef.current = onTokenizedBody;
|
|
749
823
|
}, [onTokenizedBody]);
|
|
750
|
-
|
|
824
|
+
useEffect4(() => {
|
|
751
825
|
onCompleteRef.current = onComplete;
|
|
752
826
|
}, [onComplete]);
|
|
753
|
-
|
|
827
|
+
useEffect4(() => {
|
|
754
828
|
onErrorChangeRef.current = onErrorChange;
|
|
755
829
|
}, [onErrorChange]);
|
|
756
|
-
|
|
830
|
+
useEffect4(() => {
|
|
757
831
|
onDeclineRef.current = onDecline;
|
|
758
832
|
}, [onDecline]);
|
|
759
|
-
|
|
833
|
+
useEffect4(() => {
|
|
760
834
|
onButtonClickRef.current = onButtonClick;
|
|
761
835
|
}, [onButtonClick]);
|
|
762
|
-
|
|
836
|
+
useEffect4(() => {
|
|
763
837
|
onLoadStateChangeRef.current = onLoadStateChange;
|
|
764
838
|
}, [onLoadStateChange]);
|
|
765
|
-
|
|
839
|
+
useEffect4(() => {
|
|
766
840
|
runBeforeButtonClickRef.current = runBeforeButtonClick;
|
|
767
841
|
}, [runBeforeButtonClick]);
|
|
768
|
-
|
|
842
|
+
useEffect4(() => {
|
|
769
843
|
sessionRef.current = session;
|
|
770
844
|
}, [session]);
|
|
771
|
-
|
|
845
|
+
useEffect4(() => {
|
|
772
846
|
emailRef.current = email;
|
|
773
847
|
}, [email]);
|
|
774
|
-
|
|
848
|
+
useEffect4(() => {
|
|
775
849
|
nonceRef.current = nonce;
|
|
776
850
|
}, [nonce]);
|
|
777
|
-
|
|
851
|
+
useEffect4(() => {
|
|
778
852
|
onLoadStateChangeRef.current?.(ready && !failed);
|
|
779
853
|
}, [ready, failed]);
|
|
780
854
|
const normalizedEnv = normalizeGatewayEnvironment(environment);
|
|
781
|
-
|
|
855
|
+
useEffect4(() => {
|
|
782
856
|
const maskedClient = clientId ? `${clientId.slice(0, 6)}\u2026(len ${clientId.length})` : "(empty)";
|
|
783
857
|
const ua = typeof navigator !== "undefined" ? navigator.userAgent : "(no navigator)";
|
|
784
858
|
appendDebug(`mount clientId=${maskedClient} env=${environment ?? "(unset)"}\u2192${normalizedEnv ?? "live"} ccy=${currency} sub=${isSubscription}`);
|
|
@@ -1215,7 +1289,7 @@ ${debugLines.join("\n")}`
|
|
|
1215
1289
|
}
|
|
1216
1290
|
) : null;
|
|
1217
1291
|
if (failed) {
|
|
1218
|
-
return debug ? /* @__PURE__ */
|
|
1292
|
+
return debug ? /* @__PURE__ */ jsx6("div", { children: debugPanel }) : null;
|
|
1219
1293
|
}
|
|
1220
1294
|
return (
|
|
1221
1295
|
// Single wrapper so the parent flex container sees exactly one flex item
|
|
@@ -1225,7 +1299,7 @@ ${debugLines.join("\n")}`
|
|
|
1225
1299
|
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1226
1300
|
debugPanel,
|
|
1227
1301
|
/* @__PURE__ */ jsxs3("div", { style: { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT }, children: [
|
|
1228
|
-
!ready && /* @__PURE__ */
|
|
1302
|
+
!ready && /* @__PURE__ */ jsx6(
|
|
1229
1303
|
"div",
|
|
1230
1304
|
{
|
|
1231
1305
|
"data-testid": "flopay-direct-paypal-placeholder",
|
|
@@ -1239,7 +1313,7 @@ ${debugLines.join("\n")}`
|
|
|
1239
1313
|
}
|
|
1240
1314
|
}
|
|
1241
1315
|
),
|
|
1242
|
-
/* @__PURE__ */
|
|
1316
|
+
/* @__PURE__ */ jsx6(
|
|
1243
1317
|
"div",
|
|
1244
1318
|
{
|
|
1245
1319
|
ref: containerRef,
|
|
@@ -1259,10 +1333,28 @@ ${debugLines.join("\n")}`
|
|
|
1259
1333
|
|
|
1260
1334
|
// src/split-card-form.tsx
|
|
1261
1335
|
import { FloPayError as FloPayError3, isSetupIntentClientSecret as isSetupIntentClientSecret2, resolveTheme } from "@flopay/shared";
|
|
1262
|
-
import { Fragment as Fragment2, jsx as
|
|
1336
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1263
1337
|
var STRIPE_RESUME_KEY = "flopay_stripe_resume";
|
|
1264
1338
|
var LEGACY_WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
1265
1339
|
var PAYPAL_RESUME_KEY = "flopay_paypal_resume";
|
|
1340
|
+
function toVaultMount(block) {
|
|
1341
|
+
if (!block?.html) return null;
|
|
1342
|
+
return {
|
|
1343
|
+
html: block.html,
|
|
1344
|
+
...block.messageToken ? { messageToken: block.messageToken } : {},
|
|
1345
|
+
...block.expectedOrigin ? { expectedOrigin: block.expectedOrigin } : {}
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
function darkenHex(hex, amount = 0.12) {
|
|
1349
|
+
const match = /^#?([0-9a-fA-F]{6})$/.exec(hex.trim());
|
|
1350
|
+
if (!match) return hex;
|
|
1351
|
+
const value = parseInt(match[1], 16);
|
|
1352
|
+
const scale = Math.max(0, Math.min(1, 1 - amount));
|
|
1353
|
+
const r = Math.round((value >> 16 & 255) * scale);
|
|
1354
|
+
const g = Math.round((value >> 8 & 255) * scale);
|
|
1355
|
+
const b = Math.round((value & 255) * scale);
|
|
1356
|
+
return `#${(1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)}`;
|
|
1357
|
+
}
|
|
1266
1358
|
var FLOPAY_KEYFRAMES = `
|
|
1267
1359
|
.paypal-buttons { margin: 0 !important; vertical-align: top !important; }
|
|
1268
1360
|
@keyframes flopay-spin { to { transform: rotate(360deg); } }
|
|
@@ -1287,18 +1379,20 @@ var FLOPAY_KEYFRAMES = `
|
|
|
1287
1379
|
`;
|
|
1288
1380
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
|
|
1289
1381
|
function derivePrimaryTileStyle(opts) {
|
|
1290
|
-
if (!opts.themeBundle) {
|
|
1382
|
+
if (!opts.themeBundle && !opts.explicitPrimaryColor) {
|
|
1291
1383
|
return {
|
|
1292
1384
|
backgroundColor: "white",
|
|
1293
1385
|
color: "#262833",
|
|
1294
1386
|
border: "1px solid #d1d5db",
|
|
1295
|
-
borderRadius:
|
|
1387
|
+
borderRadius: opts.resolvedBorderRadius,
|
|
1296
1388
|
boxShadow: "0 1px 2px rgba(0,0,0,0.04)"
|
|
1297
1389
|
};
|
|
1298
1390
|
}
|
|
1299
|
-
const submit = opts.submitButtonStyle ?? {};
|
|
1391
|
+
const submit = opts.themeBundle ? opts.submitButtonStyle ?? {} : {};
|
|
1300
1392
|
return {
|
|
1301
|
-
|
|
1393
|
+
// `colorPrimary` wins so a per-checkout override re-skins the card / auto-pay
|
|
1394
|
+
// buttons in lock-step with the submit CTA (which also keys off it).
|
|
1395
|
+
backgroundColor: opts.resolvedPrimaryColor,
|
|
1302
1396
|
color: submit.color ?? "white",
|
|
1303
1397
|
border: submit.border ?? "none",
|
|
1304
1398
|
borderRadius: submit.borderRadius ?? opts.resolvedBorderRadius,
|
|
@@ -1325,6 +1419,18 @@ function getButtonMethodLabel(method) {
|
|
|
1325
1419
|
return "Card";
|
|
1326
1420
|
}
|
|
1327
1421
|
}
|
|
1422
|
+
function malformedPostcodeMessage(country) {
|
|
1423
|
+
const example = getPostalCodeExample(country);
|
|
1424
|
+
return `Enter a valid ${getPostalCodeLabel(country)}${example ? ` (e.g. ${example})` : ""}`;
|
|
1425
|
+
}
|
|
1426
|
+
function computePostalCodeState(country, zip, visible) {
|
|
1427
|
+
const supported = isPostalCodeSupported(country);
|
|
1428
|
+
const trimmed = zip.trim();
|
|
1429
|
+
const required = visible && supported;
|
|
1430
|
+
const empty = required && !trimmed;
|
|
1431
|
+
const malformed = required && !!trimmed && !isValidPostalCode(country, trimmed);
|
|
1432
|
+
return { visible, supported, required, empty, malformed };
|
|
1433
|
+
}
|
|
1328
1434
|
function normalizeBeforeButtonClickError(method, err) {
|
|
1329
1435
|
return err instanceof FloPayError3 ? err : new FloPayError3(
|
|
1330
1436
|
err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
|
|
@@ -1332,7 +1438,7 @@ function normalizeBeforeButtonClickError(method, err) {
|
|
|
1332
1438
|
);
|
|
1333
1439
|
}
|
|
1334
1440
|
function FloPayKeyframes() {
|
|
1335
|
-
return /* @__PURE__ */
|
|
1441
|
+
return /* @__PURE__ */ jsx7("style", { children: FLOPAY_KEYFRAMES });
|
|
1336
1442
|
}
|
|
1337
1443
|
function toCssSize(value) {
|
|
1338
1444
|
if (typeof value === "number") return `${value}px`;
|
|
@@ -1355,7 +1461,7 @@ function ExpressCheckoutReadySwap({
|
|
|
1355
1461
|
}) {
|
|
1356
1462
|
if (state === "unavailable" || state === "load_error") return null;
|
|
1357
1463
|
return /* @__PURE__ */ jsxs4("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
1358
|
-
/* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsx7(
|
|
1359
1465
|
"div",
|
|
1360
1466
|
{
|
|
1361
1467
|
"data-testid": placeholderTestId,
|
|
@@ -1374,7 +1480,7 @@ function ExpressCheckoutReadySwap({
|
|
|
1374
1480
|
}
|
|
1375
1481
|
}
|
|
1376
1482
|
),
|
|
1377
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ jsx7(
|
|
1378
1484
|
"div",
|
|
1379
1485
|
{
|
|
1380
1486
|
style: {
|
|
@@ -1394,7 +1500,7 @@ function isExpressCheckoutRowVisible(state) {
|
|
|
1394
1500
|
}
|
|
1395
1501
|
var SplitCardForm = forwardRef(
|
|
1396
1502
|
function SplitCardForm2(props, ref) {
|
|
1397
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsx7(SplitCardFormInner, { ...props, innerRef: ref });
|
|
1398
1504
|
}
|
|
1399
1505
|
);
|
|
1400
1506
|
function PayPalButtonInner({
|
|
@@ -1414,14 +1520,14 @@ function PayPalButtonInner({
|
|
|
1414
1520
|
const stripe = useStripeRaw();
|
|
1415
1521
|
const elements = useStripeElements();
|
|
1416
1522
|
const [loadState, setLoadState] = useState3("loading");
|
|
1417
|
-
|
|
1523
|
+
useEffect5(() => {
|
|
1418
1524
|
onLoadStateChange?.(loadState);
|
|
1419
1525
|
}, [loadState, onLoadStateChange]);
|
|
1420
1526
|
const [submitting, setSubmitting] = useState3(false);
|
|
1421
|
-
const paypalResumeAttempted =
|
|
1422
|
-
const beforeClickRef =
|
|
1527
|
+
const paypalResumeAttempted = useRef4(false);
|
|
1528
|
+
const beforeClickRef = useRef4(null);
|
|
1423
1529
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1424
|
-
|
|
1530
|
+
useEffect5(() => {
|
|
1425
1531
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
1426
1532
|
const params = new URLSearchParams(window.location.search);
|
|
1427
1533
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -1627,13 +1733,13 @@ function PayPalButtonInner({
|
|
|
1627
1733
|
}
|
|
1628
1734
|
}, [stripe, elements, sessionId, nonce, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
|
|
1629
1735
|
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1630
|
-
/* @__PURE__ */
|
|
1736
|
+
/* @__PURE__ */ jsx7(
|
|
1631
1737
|
ExpressCheckoutReadySwap,
|
|
1632
1738
|
{
|
|
1633
1739
|
state: loadState,
|
|
1634
1740
|
placeholderTestId: "flopay-paypal-placeholder",
|
|
1635
1741
|
borderRadius: placeholderBorderRadius,
|
|
1636
|
-
children: /* @__PURE__ */
|
|
1742
|
+
children: /* @__PURE__ */ jsx7(
|
|
1637
1743
|
ExpressCheckoutElement,
|
|
1638
1744
|
{
|
|
1639
1745
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
@@ -1660,7 +1766,7 @@ function PayPalButtonInner({
|
|
|
1660
1766
|
)
|
|
1661
1767
|
}
|
|
1662
1768
|
),
|
|
1663
|
-
submitting && /* @__PURE__ */
|
|
1769
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
1664
1770
|
] });
|
|
1665
1771
|
}
|
|
1666
1772
|
function WalletButtonInner({
|
|
@@ -1680,13 +1786,13 @@ function WalletButtonInner({
|
|
|
1680
1786
|
const stripe = useStripeRaw();
|
|
1681
1787
|
const elements = useStripeElements();
|
|
1682
1788
|
const [loadState, setLoadState] = useState3("loading");
|
|
1683
|
-
|
|
1789
|
+
useEffect5(() => {
|
|
1684
1790
|
onLoadStateChange?.(loadState);
|
|
1685
1791
|
}, [loadState, onLoadStateChange]);
|
|
1686
1792
|
const [submitting, setSubmitting] = useState3(false);
|
|
1687
1793
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1688
|
-
const lastWalletMethodRef =
|
|
1689
|
-
const beforeClickRef =
|
|
1794
|
+
const lastWalletMethodRef = useRef4("card");
|
|
1795
|
+
const beforeClickRef = useRef4(null);
|
|
1690
1796
|
const handleWalletConfirm = useCallback(
|
|
1691
1797
|
async (event) => {
|
|
1692
1798
|
if (!stripe || !elements) return;
|
|
@@ -1796,13 +1902,13 @@ function WalletButtonInner({
|
|
|
1796
1902
|
[expressMethods]
|
|
1797
1903
|
);
|
|
1798
1904
|
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1799
|
-
/* @__PURE__ */
|
|
1905
|
+
/* @__PURE__ */ jsx7(
|
|
1800
1906
|
ExpressCheckoutReadySwap,
|
|
1801
1907
|
{
|
|
1802
1908
|
state: loadState,
|
|
1803
1909
|
placeholderTestId: "flopay-wallet-placeholder",
|
|
1804
1910
|
borderRadius: placeholderBorderRadius,
|
|
1805
|
-
children: /* @__PURE__ */
|
|
1911
|
+
children: /* @__PURE__ */ jsx7(
|
|
1806
1912
|
ExpressCheckoutElement,
|
|
1807
1913
|
{
|
|
1808
1914
|
onReady: (event) => {
|
|
@@ -1841,7 +1947,7 @@ function WalletButtonInner({
|
|
|
1841
1947
|
)
|
|
1842
1948
|
}
|
|
1843
1949
|
),
|
|
1844
|
-
submitting && /* @__PURE__ */
|
|
1950
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
1845
1951
|
] });
|
|
1846
1952
|
}
|
|
1847
1953
|
function StripeMethodButton({
|
|
@@ -1862,7 +1968,7 @@ function StripeMethodButton({
|
|
|
1862
1968
|
const resolvedBackground = brand?.backgroundColor ?? backgroundColor ?? "#ffffff";
|
|
1863
1969
|
const resolvedBorder = brand?.borderColor ?? borderColor ?? "#d1d5db";
|
|
1864
1970
|
const resolvedTextColor = brand?.textColor ?? textColor ?? "#262833";
|
|
1865
|
-
return /* @__PURE__ */
|
|
1971
|
+
return /* @__PURE__ */ jsx7(
|
|
1866
1972
|
"button",
|
|
1867
1973
|
{
|
|
1868
1974
|
type: "button",
|
|
@@ -1909,7 +2015,7 @@ function StripeMethodButton({
|
|
|
1909
2015
|
// Pulse-skeleton parity with the wallet ECE: no spinner, just the
|
|
1910
2016
|
// status text on top of the pulsing background. Keeps the loading
|
|
1911
2017
|
// affordance shape-equivalent across both kinds of tile.
|
|
1912
|
-
/* @__PURE__ */
|
|
2018
|
+
/* @__PURE__ */ jsx7("span", { style: { margin: "0 auto" }, children: `Connecting to ${getStripeMethodDisplayName(method)}\u2026` })
|
|
1913
2019
|
) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1914
2020
|
/* @__PURE__ */ jsxs4(
|
|
1915
2021
|
"span",
|
|
@@ -1924,7 +2030,7 @@ function StripeMethodButton({
|
|
|
1924
2030
|
gap: hasVendoredStripeMethodLogo(method) ? 8 : 0
|
|
1925
2031
|
},
|
|
1926
2032
|
children: [
|
|
1927
|
-
brand?.logoSvg && /* @__PURE__ */
|
|
2033
|
+
brand?.logoSvg && /* @__PURE__ */ jsx7(
|
|
1928
2034
|
"span",
|
|
1929
2035
|
{
|
|
1930
2036
|
"aria-hidden": "true",
|
|
@@ -1943,11 +2049,11 @@ function StripeMethodButton({
|
|
|
1943
2049
|
dangerouslySetInnerHTML: { __html: brand.logoSvg }
|
|
1944
2050
|
}
|
|
1945
2051
|
),
|
|
1946
|
-
/* @__PURE__ */
|
|
2052
|
+
/* @__PURE__ */ jsx7("span", { children: getStripeMethodDisplayName(method) })
|
|
1947
2053
|
]
|
|
1948
2054
|
}
|
|
1949
2055
|
),
|
|
1950
|
-
hasNextStep && /* @__PURE__ */
|
|
2056
|
+
hasNextStep && /* @__PURE__ */ jsx7(
|
|
1951
2057
|
"svg",
|
|
1952
2058
|
{
|
|
1953
2059
|
width: "14",
|
|
@@ -1967,7 +2073,7 @@ function StripeMethodButton({
|
|
|
1967
2073
|
opacity: 0.7
|
|
1968
2074
|
},
|
|
1969
2075
|
"aria-hidden": "true",
|
|
1970
|
-
children: /* @__PURE__ */
|
|
2076
|
+
children: /* @__PURE__ */ jsx7("path", { d: "M9 18l6-6-6-6" })
|
|
1971
2077
|
}
|
|
1972
2078
|
)
|
|
1973
2079
|
] })
|
|
@@ -1990,12 +2096,13 @@ function StripeMethodInlineForm({
|
|
|
1990
2096
|
isProcessing,
|
|
1991
2097
|
submitButtonColor,
|
|
1992
2098
|
submitButtonBorderRadius,
|
|
1993
|
-
submitButtonStyle
|
|
2099
|
+
submitButtonStyle,
|
|
2100
|
+
errorText
|
|
1994
2101
|
}) {
|
|
1995
2102
|
const stripe = useStripeRaw();
|
|
1996
2103
|
const elements = useStripeElements();
|
|
1997
2104
|
const [submitting, setSubmitting] = useState3(false);
|
|
1998
|
-
const submittingRef =
|
|
2105
|
+
const submittingRef = useRef4(false);
|
|
1999
2106
|
const [isMethodComplete, setIsMethodComplete] = useState3(false);
|
|
2000
2107
|
const [loadState, setLoadState] = useState3("loading");
|
|
2001
2108
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
@@ -2140,7 +2247,7 @@ function StripeMethodInlineForm({
|
|
|
2140
2247
|
]);
|
|
2141
2248
|
void onCancel;
|
|
2142
2249
|
return /* @__PURE__ */ jsxs4("div", { "data-testid": `flopay-stripe-method-form-${method}`, style: { display: "flex", flexDirection: "column" }, children: [
|
|
2143
|
-
/* @__PURE__ */
|
|
2250
|
+
/* @__PURE__ */ jsx7(
|
|
2144
2251
|
PaymentElement2,
|
|
2145
2252
|
{
|
|
2146
2253
|
onReady: () => setLoadState("ready"),
|
|
@@ -2160,7 +2267,7 @@ function StripeMethodInlineForm({
|
|
|
2160
2267
|
}
|
|
2161
2268
|
}
|
|
2162
2269
|
),
|
|
2163
|
-
/* @__PURE__ */
|
|
2270
|
+
/* @__PURE__ */ jsx7(
|
|
2164
2271
|
"button",
|
|
2165
2272
|
{
|
|
2166
2273
|
type: "button",
|
|
@@ -2186,7 +2293,23 @@ function StripeMethodInlineForm({
|
|
|
2186
2293
|
},
|
|
2187
2294
|
children: submitting ? "Processing\u2026" : `Pay with ${getStripeMethodDisplayName(method)}`
|
|
2188
2295
|
}
|
|
2189
|
-
)
|
|
2296
|
+
),
|
|
2297
|
+
errorText && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
2298
|
+
margin: "0.75rem 0 0",
|
|
2299
|
+
padding: "0.625rem 0.875rem",
|
|
2300
|
+
background: "#FEF2F2",
|
|
2301
|
+
border: "1px solid #FECACA",
|
|
2302
|
+
borderRadius: "8px",
|
|
2303
|
+
color: "#991B1B",
|
|
2304
|
+
fontSize: "0.85rem",
|
|
2305
|
+
fontWeight: 600,
|
|
2306
|
+
display: "flex",
|
|
2307
|
+
alignItems: "center",
|
|
2308
|
+
gap: "0.5rem"
|
|
2309
|
+
}, children: [
|
|
2310
|
+
/* @__PURE__ */ jsx7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx7("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" }) }),
|
|
2311
|
+
errorText
|
|
2312
|
+
] })
|
|
2190
2313
|
] });
|
|
2191
2314
|
}
|
|
2192
2315
|
function StripePaymentElementInner({
|
|
@@ -2216,8 +2339,8 @@ function StripePaymentElementInner({
|
|
|
2216
2339
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
2217
2340
|
const [expandedMethod, setExpandedMethod] = useState3(null);
|
|
2218
2341
|
const [submittingMethod, setSubmittingMethod] = useState3(null);
|
|
2219
|
-
const submittingRef =
|
|
2220
|
-
|
|
2342
|
+
const submittingRef = useRef4(false);
|
|
2343
|
+
useEffect5(() => {
|
|
2221
2344
|
if (paymentElementMethods.length > 0 && stripeInstance) {
|
|
2222
2345
|
onLoadStateChange?.("ready");
|
|
2223
2346
|
} else if (!stripeInstance) {
|
|
@@ -2385,7 +2508,7 @@ function StripePaymentElementInner({
|
|
|
2385
2508
|
paymentMethodTypes: [localExpandedMethod]
|
|
2386
2509
|
};
|
|
2387
2510
|
}, [localExpandedMethod, paymentElementBaseOptions]);
|
|
2388
|
-
return /* @__PURE__ */
|
|
2511
|
+
return /* @__PURE__ */ jsx7(
|
|
2389
2512
|
"div",
|
|
2390
2513
|
{
|
|
2391
2514
|
"data-testid": "flopay-stripe-payment-element-region",
|
|
@@ -2394,8 +2517,8 @@ function StripePaymentElementInner({
|
|
|
2394
2517
|
const isExpanded = expandedApmMethod === method;
|
|
2395
2518
|
const isSubmittingThis = submittingMethod === method;
|
|
2396
2519
|
const otherInProgress = submittingMethod !== null && submittingMethod !== method || expandedApmMethod !== null && expandedApmMethod !== void 0 && expandedApmMethod !== method;
|
|
2397
|
-
return /* @__PURE__ */ jsxs4(
|
|
2398
|
-
/* @__PURE__ */
|
|
2520
|
+
return /* @__PURE__ */ jsxs4(React7.Fragment, { children: [
|
|
2521
|
+
/* @__PURE__ */ jsx7(
|
|
2399
2522
|
StripeMethodButton,
|
|
2400
2523
|
{
|
|
2401
2524
|
method,
|
|
@@ -2412,12 +2535,12 @@ function StripePaymentElementInner({
|
|
|
2412
2535
|
fontFamily: buttonAppearance?.fontFamily
|
|
2413
2536
|
}
|
|
2414
2537
|
),
|
|
2415
|
-
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */
|
|
2538
|
+
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */ jsx7(
|
|
2416
2539
|
StripeElements,
|
|
2417
2540
|
{
|
|
2418
2541
|
stripe: stripeInstance,
|
|
2419
2542
|
options: localInlineElementsOptions,
|
|
2420
|
-
children: /* @__PURE__ */
|
|
2543
|
+
children: /* @__PURE__ */ jsx7(
|
|
2421
2544
|
StripeMethodInlineForm,
|
|
2422
2545
|
{
|
|
2423
2546
|
method,
|
|
@@ -2470,6 +2593,7 @@ function SplitCardFormInner({
|
|
|
2470
2593
|
showPayPal = true,
|
|
2471
2594
|
showStripe = true,
|
|
2472
2595
|
enabledPaymentMethods,
|
|
2596
|
+
enabledPaymentMethodCountries,
|
|
2473
2597
|
showApplePay = true,
|
|
2474
2598
|
showGooglePay = true,
|
|
2475
2599
|
layout = "default",
|
|
@@ -2484,6 +2608,8 @@ function SplitCardFormInner({
|
|
|
2484
2608
|
onButtonClick,
|
|
2485
2609
|
onBeforeButtonClick,
|
|
2486
2610
|
enableAVS: enableAVSProp,
|
|
2611
|
+
cardFieldOrder,
|
|
2612
|
+
cardPreFormSlot,
|
|
2487
2613
|
avsLayout: avsLayoutProp = "row",
|
|
2488
2614
|
country: countryProp,
|
|
2489
2615
|
zip: zipProp,
|
|
@@ -2520,14 +2646,49 @@ function SplitCardFormInner({
|
|
|
2520
2646
|
const [city, setCity] = useState3(cityProp ?? "");
|
|
2521
2647
|
const [stateValue, setStateValue] = useState3(stateProp ?? "");
|
|
2522
2648
|
const [accountPatch, setAccountPatch] = useState3({});
|
|
2523
|
-
const zipCodeRef =
|
|
2524
|
-
const selectedCountryRef =
|
|
2525
|
-
const addressLine1Ref =
|
|
2526
|
-
const addressLine2Ref =
|
|
2527
|
-
const cityRef =
|
|
2528
|
-
const stateRef =
|
|
2649
|
+
const zipCodeRef = useRef4(zipProp ?? "");
|
|
2650
|
+
const selectedCountryRef = useRef4(countryProp ?? "US");
|
|
2651
|
+
const addressLine1Ref = useRef4(addressLine1Prop ?? "");
|
|
2652
|
+
const addressLine2Ref = useRef4(addressLine2Prop ?? "");
|
|
2653
|
+
const cityRef = useRef4(cityProp ?? "");
|
|
2654
|
+
const stateRef = useRef4(stateProp ?? "");
|
|
2529
2655
|
const avsConfig = useMemo3(() => resolveAVSConfig(enableAVSProp), [enableAVSProp]);
|
|
2530
2656
|
const enableAVS = avsConfig !== null;
|
|
2657
|
+
const vaultBlockReady = Boolean(session?.vault?.html);
|
|
2658
|
+
const vaultGatewayAdvertised = Boolean(session?.gateways?.pcivault);
|
|
2659
|
+
const vaultActive = Boolean(
|
|
2660
|
+
showStripe && (vaultBlockReady || vaultGatewayAdvertised) && flopay && sessionId
|
|
2661
|
+
);
|
|
2662
|
+
const cardCapture = useMemo3(() => {
|
|
2663
|
+
if (!flopay || !vaultActive || !sessionId) return null;
|
|
2664
|
+
return flopay.cardCapture({ sessionId });
|
|
2665
|
+
}, [flopay, vaultActive, sessionId]);
|
|
2666
|
+
const postalCodeState = useMemo3(() => {
|
|
2667
|
+
const cc = selectedCountry;
|
|
2668
|
+
const visible = avsConfig ? isAVSFieldVisible(avsConfig.postal_code, cc) : false;
|
|
2669
|
+
return computePostalCodeState(cc, zipCode, visible);
|
|
2670
|
+
}, [avsConfig, selectedCountry, zipCode]);
|
|
2671
|
+
const { avsInvalid, invalidAvsFields } = useMemo3(() => {
|
|
2672
|
+
const none = { line1: false, city: false, state: false, zip: false };
|
|
2673
|
+
if (!vaultActive || !avsConfig) return { avsInvalid: false, invalidAvsFields: none };
|
|
2674
|
+
const cc = selectedCountry;
|
|
2675
|
+
const isEmpty = (field, value) => isAVSFieldVisible(field, cc) && !value.trim();
|
|
2676
|
+
const invalidAvsFields2 = {
|
|
2677
|
+
line1: isEmpty(avsConfig.address_line_1, addressLine1),
|
|
2678
|
+
city: isEmpty(avsConfig.city, city),
|
|
2679
|
+
state: isEmpty(avsConfig.state, stateValue),
|
|
2680
|
+
// Empty (required) or malformed both block; unsupported/no-postcode
|
|
2681
|
+
// locales never block (`postalCodeState` fails open above).
|
|
2682
|
+
zip: postalCodeState.empty || postalCodeState.malformed
|
|
2683
|
+
};
|
|
2684
|
+
const avsInvalid2 = invalidAvsFields2.line1 || invalidAvsFields2.city || invalidAvsFields2.state || invalidAvsFields2.zip;
|
|
2685
|
+
return { avsInvalid: avsInvalid2, invalidAvsFields: invalidAvsFields2 };
|
|
2686
|
+
}, [vaultActive, avsConfig, selectedCountry, addressLine1, city, stateValue, postalCodeState]);
|
|
2687
|
+
const [hasAttemptedSubmit, setHasAttemptedSubmit] = useState3(false);
|
|
2688
|
+
const [zipTouched, setZipTouched] = useState3(false);
|
|
2689
|
+
const [vaultMount, setVaultMount] = useState3(
|
|
2690
|
+
() => toVaultMount(session?.vault)
|
|
2691
|
+
);
|
|
2531
2692
|
const [viewState, setViewState] = useState3(initialCardOpen ? "card" : "buttons");
|
|
2532
2693
|
const [expandedApmMethod, setExpandedApmMethod] = useState3(null);
|
|
2533
2694
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
@@ -2552,7 +2713,7 @@ function SplitCardFormInner({
|
|
|
2552
2713
|
setExpandedApmMethod(null);
|
|
2553
2714
|
}, TRANSITION_MS);
|
|
2554
2715
|
}, []);
|
|
2555
|
-
|
|
2716
|
+
useEffect5(() => {
|
|
2556
2717
|
if (layout === "buttons" && initialCardOpen) {
|
|
2557
2718
|
setViewState("card");
|
|
2558
2719
|
}
|
|
@@ -2560,10 +2721,10 @@ function SplitCardFormInner({
|
|
|
2560
2721
|
const [fullName, setFullName] = useState3("");
|
|
2561
2722
|
const [formReady, setFormReady] = useState3(false);
|
|
2562
2723
|
const [overlayStatus, setOverlayStatus] = useState3(null);
|
|
2563
|
-
const processingRef =
|
|
2724
|
+
const processingRef = useRef4(false);
|
|
2564
2725
|
const [paypalDirectRetry, setPaypalDirectRetry] = useState3(null);
|
|
2565
|
-
const paypalDirectRetryRef =
|
|
2566
|
-
|
|
2726
|
+
const paypalDirectRetryRef = useRef4(paypalDirectRetry);
|
|
2727
|
+
useEffect5(() => {
|
|
2567
2728
|
paypalDirectRetryRef.current = paypalDirectRetry;
|
|
2568
2729
|
}, [paypalDirectRetry]);
|
|
2569
2730
|
const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
|
|
@@ -2584,6 +2745,31 @@ function SplitCardFormInner({
|
|
|
2584
2745
|
};
|
|
2585
2746
|
}, [themeBundle, buttonsTheme, buttonsStylesOverride]);
|
|
2586
2747
|
const appearance = appearanceOverride ?? themeBundle?.appearance;
|
|
2748
|
+
const vaultThemeColors = useMemo3(() => {
|
|
2749
|
+
const vars = appearance?.variables;
|
|
2750
|
+
const asString = (value) => typeof value === "string" && value ? value : void 0;
|
|
2751
|
+
const submitButtonStyle = bStyles.submitButton;
|
|
2752
|
+
const primary = asString(vars?.colorPrimary) ?? asString(submitButtonStyle?.backgroundColor) ?? "#4A49FF";
|
|
2753
|
+
const isButtonsLayout = layout === "buttons";
|
|
2754
|
+
const nameInput = bStyles.nameInput;
|
|
2755
|
+
return {
|
|
2756
|
+
primaryColor: primary,
|
|
2757
|
+
primaryHoverColor: asString(vars?.colorPrimaryHover) ?? darkenHex(primary, 0.12),
|
|
2758
|
+
inputBackgroundColor: asString(bStyles.cardInputBackground) ?? asString(vars?.colorBackground) ?? "#ffffff",
|
|
2759
|
+
textColor: asString(bStyles.cardInputColor) ?? asString(nameInput?.color) ?? asString(vars?.colorText) ?? "#262833",
|
|
2760
|
+
borderColor: asString(bStyles.cardInputBorder) ?? (isButtonsLayout ? "#e5e7eb" : "#A4A4FF"),
|
|
2761
|
+
placeholderColor: asString(bStyles.cardInputPlaceholderColor) ?? "#9ca3af",
|
|
2762
|
+
errorColor: asString(vars?.colorDanger) ?? "#dc2626",
|
|
2763
|
+
successColor: "#16a34a",
|
|
2764
|
+
fontFamily: asString(nameInput?.fontFamily) ?? asString(vars?.fontFamily) ?? "Poppins, sans-serif",
|
|
2765
|
+
fontSize: asString(bStyles.cardInputFontSize) ?? asString(vars?.fontSizeBase) ?? "16px",
|
|
2766
|
+
// `resolvedInputFontWeight` equivalent — sent as a string (the widget's
|
|
2767
|
+
// theme applier only honors string values) so vault inputs/placeholders
|
|
2768
|
+
// match the AVS fields' weight per theme (default 400).
|
|
2769
|
+
fontWeight: String(toCssWeight(nameInput?.fontWeight) ?? 400),
|
|
2770
|
+
borderRadius: asString(vars?.borderRadius) ?? "8px"
|
|
2771
|
+
};
|
|
2772
|
+
}, [appearance, bStyles, layout]);
|
|
2587
2773
|
const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
|
|
2588
2774
|
const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
|
|
2589
2775
|
const isSelfContained = !onTokenizedBody;
|
|
@@ -2652,12 +2838,174 @@ function SplitCardFormInner({
|
|
|
2652
2838
|
},
|
|
2653
2839
|
[onErrorChange]
|
|
2654
2840
|
);
|
|
2841
|
+
useEffect5(() => {
|
|
2842
|
+
if (!vaultActive || !cardCapture) return;
|
|
2843
|
+
cardCapture.setSubmitGate?.(avsInvalid);
|
|
2844
|
+
}, [vaultActive, cardCapture, avsInvalid]);
|
|
2845
|
+
useEffect5(() => {
|
|
2846
|
+
if (!vaultActive || !cardCapture) return;
|
|
2847
|
+
cardCapture.setCardFieldOrder?.(cardFieldOrder ?? null, avsConfig == null);
|
|
2848
|
+
}, [vaultActive, cardCapture, cardFieldOrder, avsConfig]);
|
|
2849
|
+
useEffect5(() => {
|
|
2850
|
+
if (viewState === "expanding" || viewState === "collapsing" || viewState === "apm-expanding" || viewState === "apm-collapsing") {
|
|
2851
|
+
updateError(null);
|
|
2852
|
+
}
|
|
2853
|
+
}, [viewState, updateError]);
|
|
2655
2854
|
const emitDecline = useCallback(
|
|
2656
2855
|
(method, input, overrides) => {
|
|
2657
2856
|
onDecline?.(buildDeclineEvent(method, input, overrides));
|
|
2658
2857
|
},
|
|
2659
2858
|
[onDecline]
|
|
2660
2859
|
);
|
|
2860
|
+
useEffect5(() => {
|
|
2861
|
+
if (!vaultActive || !sessionId) {
|
|
2862
|
+
setVaultMount(null);
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
const embedded = toVaultMount(session?.vault);
|
|
2866
|
+
if (embedded) {
|
|
2867
|
+
setVaultMount(embedded);
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
setVaultMount(null);
|
|
2871
|
+
let active = true;
|
|
2872
|
+
new PaymentAPI2(baseUrl).getVaultCapture(sessionId, nonce).then((block) => {
|
|
2873
|
+
if (!active) return;
|
|
2874
|
+
const mount = toVaultMount(block);
|
|
2875
|
+
if (mount) {
|
|
2876
|
+
setVaultMount(mount);
|
|
2877
|
+
} else {
|
|
2878
|
+
updateError("Failed to load the secure card form.");
|
|
2879
|
+
}
|
|
2880
|
+
}).catch((err) => {
|
|
2881
|
+
if (active) {
|
|
2882
|
+
updateError(err instanceof Error ? err.message : "Failed to load the secure card form.");
|
|
2883
|
+
}
|
|
2884
|
+
});
|
|
2885
|
+
return () => {
|
|
2886
|
+
active = false;
|
|
2887
|
+
};
|
|
2888
|
+
}, [
|
|
2889
|
+
vaultActive,
|
|
2890
|
+
sessionId,
|
|
2891
|
+
session?.vault?.html,
|
|
2892
|
+
session?.vault?.messageToken,
|
|
2893
|
+
session?.vault?.expectedOrigin,
|
|
2894
|
+
baseUrl,
|
|
2895
|
+
nonce,
|
|
2896
|
+
updateError
|
|
2897
|
+
]);
|
|
2898
|
+
const vaultOutcomeRef = useRef4({
|
|
2899
|
+
onComplete,
|
|
2900
|
+
onError,
|
|
2901
|
+
updateError,
|
|
2902
|
+
emitDecline,
|
|
2903
|
+
resolvedAccount,
|
|
2904
|
+
fullName,
|
|
2905
|
+
avsConfig,
|
|
2906
|
+
avsCheckProp,
|
|
2907
|
+
sessionId,
|
|
2908
|
+
nonce,
|
|
2909
|
+
baseUrl
|
|
2910
|
+
});
|
|
2911
|
+
vaultOutcomeRef.current = {
|
|
2912
|
+
onComplete,
|
|
2913
|
+
onError,
|
|
2914
|
+
updateError,
|
|
2915
|
+
emitDecline,
|
|
2916
|
+
resolvedAccount,
|
|
2917
|
+
fullName,
|
|
2918
|
+
avsConfig,
|
|
2919
|
+
avsCheckProp,
|
|
2920
|
+
sessionId,
|
|
2921
|
+
nonce,
|
|
2922
|
+
baseUrl
|
|
2923
|
+
};
|
|
2924
|
+
const vaultCompletedRef = useRef4(false);
|
|
2925
|
+
useEffect5(() => {
|
|
2926
|
+
if (!vaultActive || !cardCapture) return;
|
|
2927
|
+
vaultCompletedRef.current = false;
|
|
2928
|
+
let cancelled = false;
|
|
2929
|
+
const offSubmitting = cardCapture.on("submitting", () => {
|
|
2930
|
+
setHasAttemptedSubmit(true);
|
|
2931
|
+
setOverlayStatus("processing");
|
|
2932
|
+
const { resolvedAccount: resolvedAccount2, avsConfig: avsConfig2, fullName: fullName2, avsCheckProp: avsCheckProp2, baseUrl: baseUrl2, sessionId: sessionId2, nonce: nonce2 } = vaultOutcomeRef.current;
|
|
2933
|
+
if (!sessionId2 || !nonce2) return;
|
|
2934
|
+
const cc = selectedCountryRef.current || resolvedAccount2.country || "US";
|
|
2935
|
+
const stateVisible = avsConfig2 ? isAVSFieldVisible(avsConfig2.state, cc) : false;
|
|
2936
|
+
const line1Visible = avsConfig2 ? isAVSFieldVisible(avsConfig2.address_line_1, cc) : false;
|
|
2937
|
+
const zipVisible = avsConfig2 ? isAVSFieldVisible(avsConfig2.postal_code, cc) : false;
|
|
2938
|
+
const cityVisible = avsConfig2 ? isAVSFieldVisible(avsConfig2.city, cc) : false;
|
|
2939
|
+
const line2Visible = avsConfig2 ? isAVSFieldVisible(avsConfig2.address_line_2, cc) : false;
|
|
2940
|
+
const derivedState = line1Visible && !stateVisible && zipVisible ? getStateFromPostalCode(cc, zipCodeRef.current ?? "") : null;
|
|
2941
|
+
const stateValue2 = stateVisible ? stateRef.current : derivedState;
|
|
2942
|
+
void new PaymentAPI2(baseUrl2).patchAccountSnapshot(sessionId2, nonce2, {
|
|
2943
|
+
accountData: {
|
|
2944
|
+
userId: resolvedAccount2.userId ?? "",
|
|
2945
|
+
email: resolvedAccount2.email ?? "",
|
|
2946
|
+
firstName: resolvedAccount2.firstName ?? fullName2.trim().split(/\s+/)[0] ?? "",
|
|
2947
|
+
lastName: resolvedAccount2.lastName ?? fullName2.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
2948
|
+
...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
|
|
2949
|
+
...cityVisible && cityRef.current ? { city: cityRef.current } : {},
|
|
2950
|
+
...stateValue2 ? { state: stateValue2 } : {},
|
|
2951
|
+
...line1Visible && addressLine1Ref.current ? { addressLine1: addressLine1Ref.current } : {},
|
|
2952
|
+
...line2Visible && addressLine2Ref.current ? { addressLine2: addressLine2Ref.current } : {},
|
|
2953
|
+
country: cc
|
|
2954
|
+
},
|
|
2955
|
+
...avsCheckProp2 !== void 0 ? { avsCheck: avsCheckProp2 } : {},
|
|
2956
|
+
...avsConfig2 ? {
|
|
2957
|
+
avsConfig: {
|
|
2958
|
+
country: isAVSFieldVisible(avsConfig2.country, cc),
|
|
2959
|
+
postal_code: zipVisible,
|
|
2960
|
+
address_line_1: line1Visible,
|
|
2961
|
+
address_line_2: line2Visible,
|
|
2962
|
+
city: cityVisible,
|
|
2963
|
+
state: stateVisible
|
|
2964
|
+
}
|
|
2965
|
+
} : {}
|
|
2966
|
+
}).catch(() => {
|
|
2967
|
+
});
|
|
2968
|
+
});
|
|
2969
|
+
const offComplete = cardCapture.on("complete", async (event) => {
|
|
2970
|
+
markSessionRecentlyCompleted(event.sessionId ?? vaultOutcomeRef.current.sessionId);
|
|
2971
|
+
setOverlayStatus("success");
|
|
2972
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
|
|
2973
|
+
if (vaultCompletedRef.current) return;
|
|
2974
|
+
vaultCompletedRef.current = true;
|
|
2975
|
+
vaultOutcomeRef.current.onComplete?.({
|
|
2976
|
+
status: "succeeded",
|
|
2977
|
+
paymentIntentId: event.intentId,
|
|
2978
|
+
checkoutMethod: "card"
|
|
2979
|
+
});
|
|
2980
|
+
});
|
|
2981
|
+
const offDecline = cardCapture.on("decline", async (event) => {
|
|
2982
|
+
const { updateError: updateError2, emitDecline: emitDecline2 } = vaultOutcomeRef.current;
|
|
2983
|
+
const message = event.message ?? "Your payment was declined. Please try another card or contact your bank.";
|
|
2984
|
+
updateError2(message);
|
|
2985
|
+
setOverlayStatus("error");
|
|
2986
|
+
emitDecline2("card", message, event.declineReason ? { declineCode: event.declineReason } : void 0);
|
|
2987
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
2988
|
+
if (cancelled) return;
|
|
2989
|
+
setOverlayStatus(null);
|
|
2990
|
+
});
|
|
2991
|
+
const offError = cardCapture.on("error", async (event) => {
|
|
2992
|
+
const { updateError: updateError2, onError: onError2 } = vaultOutcomeRef.current;
|
|
2993
|
+
const message = event.message ?? "There was a problem processing your payment. Please try again.";
|
|
2994
|
+
updateError2(message);
|
|
2995
|
+
setOverlayStatus("error");
|
|
2996
|
+
onError2?.(new FloPayError3(message, "api_error"));
|
|
2997
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
2998
|
+
if (cancelled) return;
|
|
2999
|
+
setOverlayStatus(null);
|
|
3000
|
+
});
|
|
3001
|
+
return () => {
|
|
3002
|
+
cancelled = true;
|
|
3003
|
+
offSubmitting();
|
|
3004
|
+
offComplete();
|
|
3005
|
+
offDecline();
|
|
3006
|
+
offError();
|
|
3007
|
+
};
|
|
3008
|
+
}, [vaultActive, cardCapture]);
|
|
2661
3009
|
const directPaypalConfigured = !!directPaypal?.clientId;
|
|
2662
3010
|
const hasEnabledMethodsPayload = Array.isArray(enabledPaymentMethods);
|
|
2663
3011
|
const hasEnabledMethods = hasEnabledMethodsPayload && enabledPaymentMethods.length > 0;
|
|
@@ -2681,17 +3029,18 @@ function SplitCardFormInner({
|
|
|
2681
3029
|
}, [showApplePay, showGooglePay]);
|
|
2682
3030
|
const walletExpressMethods = hasEnabledMethodsPayload ? expressMethodsForWalletRow : legacyExpressMethods;
|
|
2683
3031
|
const showWallets = showStripe && walletExpressMethods.length > 0;
|
|
2684
|
-
const
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
)
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
3032
|
+
const apmCountry = enableAVS ? selectedCountry : countryProp;
|
|
3033
|
+
const paymentElementMethodsForCurrency = useMemo3(() => {
|
|
3034
|
+
const target = apmCountry?.trim().toUpperCase();
|
|
3035
|
+
if (!target) return paymentElementMethods;
|
|
3036
|
+
if (!enabledPaymentMethodCountries) {
|
|
3037
|
+
return filterStripeMethodsByCountry(paymentElementMethods, apmCountry);
|
|
3038
|
+
}
|
|
3039
|
+
return paymentElementMethods.filter((method) => {
|
|
3040
|
+
const allowed = enabledPaymentMethodCountries[method];
|
|
3041
|
+
return !allowed || allowed.length === 0 || allowed.includes(target);
|
|
3042
|
+
});
|
|
3043
|
+
}, [paymentElementMethods, apmCountry, enabledPaymentMethodCountries]);
|
|
2695
3044
|
const paymentElementBaseOptions = useMemo3(() => ({
|
|
2696
3045
|
mode: "payment",
|
|
2697
3046
|
amount: amountInCents,
|
|
@@ -2704,7 +3053,7 @@ function SplitCardFormInner({
|
|
|
2704
3053
|
const [paymentElementLoadState, setPaymentElementLoadState] = useState3("loading");
|
|
2705
3054
|
const [directPaypalReady, setDirectPaypalReady] = useState3(false);
|
|
2706
3055
|
const [inAppBrowserDetected, setInAppBrowserDetected] = useState3();
|
|
2707
|
-
|
|
3056
|
+
useEffect5(() => {
|
|
2708
3057
|
setInAppBrowserDetected(isInAppBrowser());
|
|
2709
3058
|
}, []);
|
|
2710
3059
|
const shouldShowPayPal = showPayPal && (directPaypalConfigured || (hasEnabledMethodsPayload ? paypalEnabled : inAppBrowserDetected === false));
|
|
@@ -2716,8 +3065,8 @@ function SplitCardFormInner({
|
|
|
2716
3065
|
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
2717
3066
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
2718
3067
|
const shouldDisplayPaymentElementRow = shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
2719
|
-
const validationFiredRef =
|
|
2720
|
-
|
|
3068
|
+
const validationFiredRef = useRef4(false);
|
|
3069
|
+
useEffect5(() => {
|
|
2721
3070
|
if (validationFiredRef.current) return;
|
|
2722
3071
|
if (!showStripe && !showPayPal) {
|
|
2723
3072
|
validationFiredRef.current = true;
|
|
@@ -2737,8 +3086,8 @@ function SplitCardFormInner({
|
|
|
2737
3086
|
updateError(err.message);
|
|
2738
3087
|
}
|
|
2739
3088
|
}, [showStripe, showPayPal, directPaypalConfigured, paypalStripeInstance, onError, updateError]);
|
|
2740
|
-
const deprecationLoggedRef =
|
|
2741
|
-
|
|
3089
|
+
const deprecationLoggedRef = useRef4(false);
|
|
3090
|
+
useEffect5(() => {
|
|
2742
3091
|
if (deprecationLoggedRef.current) return;
|
|
2743
3092
|
if (!hasEnabledMethods) return;
|
|
2744
3093
|
const stale = [];
|
|
@@ -3064,8 +3413,8 @@ function SplitCardFormInner({
|
|
|
3064
3413
|
}
|
|
3065
3414
|
}
|
|
3066
3415
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
3067
|
-
const stripeResumeAttemptedRef =
|
|
3068
|
-
|
|
3416
|
+
const stripeResumeAttemptedRef = useRef4(false);
|
|
3417
|
+
useEffect5(() => {
|
|
3069
3418
|
if (typeof window === "undefined" || stripeResumeAttemptedRef.current) return;
|
|
3070
3419
|
const params = new URLSearchParams(window.location.search);
|
|
3071
3420
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -3147,6 +3496,7 @@ function SplitCardFormInner({
|
|
|
3147
3496
|
async (e) => {
|
|
3148
3497
|
e.preventDefault();
|
|
3149
3498
|
if (!flopay || !elements || isSubmitting || processingRef.current) return;
|
|
3499
|
+
if (vaultActive) return;
|
|
3150
3500
|
if (layout !== "buttons") {
|
|
3151
3501
|
onButtonClick?.("card");
|
|
3152
3502
|
}
|
|
@@ -3157,10 +3507,21 @@ function SplitCardFormInner({
|
|
|
3157
3507
|
try {
|
|
3158
3508
|
if (avsConfig) {
|
|
3159
3509
|
const country = selectedCountryRef.current;
|
|
3160
|
-
|
|
3510
|
+
const postal = computePostalCodeState(
|
|
3511
|
+
country,
|
|
3512
|
+
zipCodeRef.current,
|
|
3513
|
+
isAVSFieldVisible(avsConfig.postal_code, country)
|
|
3514
|
+
);
|
|
3515
|
+
if (postal.empty) {
|
|
3516
|
+
setZipTouched(true);
|
|
3161
3517
|
updateError(getPostalCodeLabel(country) + " is required");
|
|
3162
3518
|
return;
|
|
3163
3519
|
}
|
|
3520
|
+
if (postal.malformed) {
|
|
3521
|
+
setZipTouched(true);
|
|
3522
|
+
updateError(malformedPostcodeMessage(country));
|
|
3523
|
+
return;
|
|
3524
|
+
}
|
|
3164
3525
|
if (isAVSFieldVisible(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
|
|
3165
3526
|
updateError("Street address is required");
|
|
3166
3527
|
return;
|
|
@@ -3174,11 +3535,13 @@ function SplitCardFormInner({
|
|
|
3174
3535
|
return;
|
|
3175
3536
|
}
|
|
3176
3537
|
}
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3538
|
+
if (!vaultActive) {
|
|
3539
|
+
const submitResult = await flopay.submitElements();
|
|
3540
|
+
if (submitResult.error) {
|
|
3541
|
+
updateError(submitResult.error.message);
|
|
3542
|
+
onError?.(submitResult.error);
|
|
3543
|
+
return;
|
|
3544
|
+
}
|
|
3182
3545
|
}
|
|
3183
3546
|
const billingAddress = {};
|
|
3184
3547
|
const cc = selectedCountryRef.current;
|
|
@@ -3203,75 +3566,77 @@ function SplitCardFormInner({
|
|
|
3203
3566
|
...fullName.trim() ? { name: fullName.trim() } : {},
|
|
3204
3567
|
...Object.keys(billingAddress).length > 0 ? { address: billingAddress } : {}
|
|
3205
3568
|
};
|
|
3206
|
-
const pmResult = await flopay.createPaymentMethod(billingDetails);
|
|
3207
|
-
if (pmResult.error || !pmResult.paymentMethodId) {
|
|
3208
|
-
updateError(pmResult.error?.message ?? "Failed to create payment method.");
|
|
3209
|
-
return;
|
|
3210
|
-
}
|
|
3211
3569
|
if (!sessionId || !resolvedAccount.email) {
|
|
3212
3570
|
throw new FloPayError3("Missing sessionId or email", "validation_error");
|
|
3213
3571
|
}
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3572
|
+
{
|
|
3573
|
+
const pmResult = await flopay.createPaymentMethod(billingDetails);
|
|
3574
|
+
if (pmResult.error || !pmResult.paymentMethodId) {
|
|
3575
|
+
updateError(pmResult.error?.message ?? "Failed to create payment method.");
|
|
3576
|
+
return;
|
|
3577
|
+
}
|
|
3578
|
+
const intentHeaders = { "Content-Type": "application/json" };
|
|
3579
|
+
if (nonce) intentHeaders["x-checkout-session-token"] = nonce;
|
|
3580
|
+
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
3581
|
+
method: "POST",
|
|
3582
|
+
headers: intentHeaders,
|
|
3583
|
+
body: JSON.stringify({
|
|
3584
|
+
sessionId,
|
|
3585
|
+
email: resolvedAccount.email,
|
|
3586
|
+
paymentMethodType: pmResult.paymentMethodId,
|
|
3587
|
+
isPaypal: false
|
|
3588
|
+
})
|
|
3589
|
+
});
|
|
3590
|
+
if (!intentResponse.ok) {
|
|
3591
|
+
const intentError = await buildFloPayApiErrorFromResponse(
|
|
3592
|
+
intentResponse,
|
|
3593
|
+
"Failed to create payment intent"
|
|
3594
|
+
);
|
|
3595
|
+
setOverlayStatus("error");
|
|
3596
|
+
updateError(intentError.message);
|
|
3597
|
+
onError?.(intentError);
|
|
3598
|
+
emitDecline("card", intentError);
|
|
3599
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
const intentJson = await intentResponse.json();
|
|
3603
|
+
const intentClientSecret = intentJson.data?.id;
|
|
3604
|
+
if (!intentClientSecret) throw new FloPayError3("No client_secret in payment intent response", "api_error");
|
|
3605
|
+
const confirmResult = await flopay.confirmCardPayment({
|
|
3606
|
+
clientSecret: intentClientSecret,
|
|
3607
|
+
paymentMethodId: pmResult.paymentMethodId
|
|
3608
|
+
});
|
|
3609
|
+
if (confirmResult.error) {
|
|
3610
|
+
setOverlayStatus("error");
|
|
3611
|
+
updateError(confirmResult.error.message);
|
|
3612
|
+
onError?.(confirmResult.error);
|
|
3613
|
+
emitDecline("card", confirmResult.error);
|
|
3614
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
3618
|
+
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
3619
|
+
rawProvider,
|
|
3620
|
+
intentClientSecret
|
|
3230
3621
|
);
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
onError?.(confirmResult.error);
|
|
3249
|
-
emitDecline("card", confirmResult.error);
|
|
3250
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
3251
|
-
return;
|
|
3252
|
-
}
|
|
3253
|
-
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
3254
|
-
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
3255
|
-
rawProvider,
|
|
3256
|
-
intentClientSecret
|
|
3257
|
-
);
|
|
3258
|
-
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
3259
|
-
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
3260
|
-
if (!paymentIntentId) {
|
|
3261
|
-
const error2 = new FloPayError3("No payment intent returned after confirmation.", "api_error");
|
|
3262
|
-
setOverlayStatus("error");
|
|
3263
|
-
updateError(error2.message);
|
|
3264
|
-
onError?.(error2);
|
|
3265
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
3266
|
-
return;
|
|
3622
|
+
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
3623
|
+
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
3624
|
+
if (!paymentIntentId) {
|
|
3625
|
+
const error2 = new FloPayError3("No payment intent returned after confirmation.", "api_error");
|
|
3626
|
+
setOverlayStatus("error");
|
|
3627
|
+
updateError(error2.message);
|
|
3628
|
+
onError?.(error2);
|
|
3629
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
3630
|
+
return;
|
|
3631
|
+
}
|
|
3632
|
+
handedOff = isSelfContained;
|
|
3633
|
+
dispatchTokenizedBody({
|
|
3634
|
+
id: paymentMethodId,
|
|
3635
|
+
type: "card",
|
|
3636
|
+
threeDSecureActionResultTokenId: paymentIntentId,
|
|
3637
|
+
originalPaymentMethodId: pmResult.paymentMethodId
|
|
3638
|
+
});
|
|
3267
3639
|
}
|
|
3268
|
-
handedOff = isSelfContained;
|
|
3269
|
-
dispatchTokenizedBody({
|
|
3270
|
-
id: paymentMethodId,
|
|
3271
|
-
type: "card",
|
|
3272
|
-
threeDSecureActionResultTokenId: paymentIntentId,
|
|
3273
|
-
originalPaymentMethodId: pmResult.paymentMethodId
|
|
3274
|
-
});
|
|
3275
3640
|
} catch (err) {
|
|
3276
3641
|
setOverlayStatus("error");
|
|
3277
3642
|
updateError(err instanceof Error ? err.message : "An unexpected error occurred");
|
|
@@ -3283,11 +3648,11 @@ function SplitCardFormInner({
|
|
|
3283
3648
|
}
|
|
3284
3649
|
}
|
|
3285
3650
|
},
|
|
3286
|
-
[flopay, elements, isSubmitting, sessionId, nonce, resolvedAccount.email, baseUrl, isSelfContained, dispatchTokenizedBody, onButtonClick, onError, updateError, emitDecline, layout]
|
|
3651
|
+
[flopay, elements, isSubmitting, sessionId, nonce, resolvedAccount.email, baseUrl, isSelfContained, vaultActive, dispatchTokenizedBody, onButtonClick, onError, updateError, emitDecline, layout]
|
|
3287
3652
|
);
|
|
3288
|
-
const isReady = flopay !== null && elements !== null;
|
|
3653
|
+
const isReady = flopay !== null && (vaultActive || elements !== null);
|
|
3289
3654
|
if (!isReady) {
|
|
3290
|
-
return /* @__PURE__ */
|
|
3655
|
+
return /* @__PURE__ */ jsx7("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
|
|
3291
3656
|
}
|
|
3292
3657
|
const isButtons = layout === "buttons";
|
|
3293
3658
|
const appearanceVars = appearance?.variables;
|
|
@@ -3295,6 +3660,10 @@ function SplitCardFormInner({
|
|
|
3295
3660
|
const appearanceColorBg = appearanceVars?.colorBackground;
|
|
3296
3661
|
const themedWrapperBg = appearanceColorBg && !SDK_DEFAULT_WHITES.has(appearanceColorBg) ? appearanceColorBg : void 0;
|
|
3297
3662
|
const resolvedBorder = bStyles.cardInputBorder ?? (isButtons ? "#e5e7eb" : "#A4A4FF");
|
|
3663
|
+
const resolvedDangerColor = appearanceVars?.colorDanger ?? "#dc2626";
|
|
3664
|
+
const avsBorderColor = (fieldInvalid) => hasAttemptedSubmit && fieldInvalid ? resolvedDangerColor : resolvedBorder;
|
|
3665
|
+
const showPostcodeError = (postalCodeState.malformed || postalCodeState.empty) && (zipTouched || hasAttemptedSubmit);
|
|
3666
|
+
const zipBorderColor = showPostcodeError ? resolvedDangerColor : avsBorderColor(invalidAvsFields.zip);
|
|
3298
3667
|
const cardBg = bStyles.cardFormContainer?.backgroundColor ?? themedWrapperBg ?? (isButtons ? "white" : "#EDEDFF");
|
|
3299
3668
|
const cardInputBg = bStyles.cardInputBackground ?? appearanceVars?.colorBackground ?? "white";
|
|
3300
3669
|
const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
|
|
@@ -3306,7 +3675,9 @@ function SplitCardFormInner({
|
|
|
3306
3675
|
const resolvedInputColor = bStyles.cardInputColor ?? (typeof nameInputOverrides?.color === "string" ? nameInputOverrides.color : void 0) ?? appearanceVars?.colorText ?? "#262833";
|
|
3307
3676
|
const resolvedPlaceholderColor = bStyles.cardInputPlaceholderColor ?? "#9ca3af";
|
|
3308
3677
|
const resolvedBorderRadius = appearanceVars?.borderRadius ?? "8px";
|
|
3678
|
+
const buttonBorderRadius = appearanceVars?.borderRadius ?? bStyles.cardButton?.borderRadius ?? resolvedBorderRadius;
|
|
3309
3679
|
const resolvedPrimaryColor = appearanceVars?.colorPrimary ?? "#4A49FF";
|
|
3680
|
+
const resolvedPrimaryHoverColor = appearanceVars?.colorPrimaryHover ?? darkenHex(resolvedPrimaryColor, 0.12);
|
|
3310
3681
|
const resolvedTitleColor = appearanceVars?.colorText ?? "#262833";
|
|
3311
3682
|
const sharedInputTypography = {
|
|
3312
3683
|
fontSize: resolvedInputFontSize,
|
|
@@ -3340,14 +3711,73 @@ function SplitCardFormInner({
|
|
|
3340
3711
|
const containerOverrides = bStyles.cardFormContainer ?? {};
|
|
3341
3712
|
const containerPadding = containerOverrides.padding ?? (isButtons ? "0" : "1rem");
|
|
3342
3713
|
const containerRadius = containerOverrides.borderRadius ?? resolvedBorderRadius;
|
|
3714
|
+
const vaultCardFieldsNode = cardCapture && vaultMount ? /* @__PURE__ */ jsx7(
|
|
3715
|
+
VaultCardFields,
|
|
3716
|
+
{
|
|
3717
|
+
capture: cardCapture,
|
|
3718
|
+
html: vaultMount.html,
|
|
3719
|
+
messageToken: vaultMount.messageToken,
|
|
3720
|
+
expectedOrigin: vaultMount.expectedOrigin,
|
|
3721
|
+
theme: vaultThemeColors,
|
|
3722
|
+
onReady: () => {
|
|
3723
|
+
setFormReady(true);
|
|
3724
|
+
if (!avsConfig || typeof document === "undefined") return;
|
|
3725
|
+
const focusFirstAvs = () => {
|
|
3726
|
+
const block = document.querySelector('[data-testid="flopay-avs-fields"]');
|
|
3727
|
+
const first = block?.querySelector(
|
|
3728
|
+
"input:not([disabled]), select:not([disabled])"
|
|
3729
|
+
);
|
|
3730
|
+
first?.focus();
|
|
3731
|
+
};
|
|
3732
|
+
focusFirstAvs();
|
|
3733
|
+
let tries = 0;
|
|
3734
|
+
const timer = window.setInterval(() => {
|
|
3735
|
+
tries += 1;
|
|
3736
|
+
const active = document.activeElement;
|
|
3737
|
+
const onIframe = !!active && active.tagName === "IFRAME" && active.id === "flopay_vault_form_iframe";
|
|
3738
|
+
if (onIframe) {
|
|
3739
|
+
focusFirstAvs();
|
|
3740
|
+
window.clearInterval(timer);
|
|
3741
|
+
} else if (tries >= 50) {
|
|
3742
|
+
window.clearInterval(timer);
|
|
3743
|
+
}
|
|
3744
|
+
}, 100);
|
|
3745
|
+
},
|
|
3746
|
+
onError: (message) => updateError(message),
|
|
3747
|
+
onValidation: (message) => {
|
|
3748
|
+
updateError(message);
|
|
3749
|
+
if (message) setOverlayStatus(null);
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
) : /* @__PURE__ */ jsx7(
|
|
3753
|
+
"div",
|
|
3754
|
+
{
|
|
3755
|
+
"data-testid": "flopay-vault-loading",
|
|
3756
|
+
style: {
|
|
3757
|
+
minHeight: 120,
|
|
3758
|
+
display: "flex",
|
|
3759
|
+
alignItems: "center",
|
|
3760
|
+
justifyContent: "center",
|
|
3761
|
+
color: "#6b7280",
|
|
3762
|
+
fontSize: 14
|
|
3763
|
+
},
|
|
3764
|
+
children: "Loading secure card form\u2026"
|
|
3765
|
+
}
|
|
3766
|
+
);
|
|
3343
3767
|
const cardFormBlock = /* @__PURE__ */ jsxs4("div", { style: {
|
|
3344
3768
|
backgroundColor: cardBg,
|
|
3345
3769
|
borderRadius: containerRadius,
|
|
3346
3770
|
...containerOverrides,
|
|
3347
3771
|
padding: containerPadding,
|
|
3348
|
-
...sharedInputPlaceholderVars
|
|
3772
|
+
...sharedInputPlaceholderVars,
|
|
3773
|
+
// Flex column (BOTH layouts, so default and buttons>card never diverge) so
|
|
3774
|
+
// AVS can be ordered above the vault widget — its submit lives inside the
|
|
3775
|
+
// iframe, so AVS can't sit between fields and button; it goes above the
|
|
3776
|
+
// card form instead of after the button.
|
|
3777
|
+
display: "flex",
|
|
3778
|
+
flexDirection: "column"
|
|
3349
3779
|
}, children: [
|
|
3350
|
-
/* @__PURE__ */
|
|
3780
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
3351
3781
|
.flopay-shared-input::placeholder {
|
|
3352
3782
|
color: var(--flopay-input-placeholder-color);
|
|
3353
3783
|
opacity: 1;
|
|
@@ -3359,7 +3789,9 @@ function SplitCardFormInner({
|
|
|
3359
3789
|
isButtons && showCardForm && /* @__PURE__ */ jsxs4("div", { style: {
|
|
3360
3790
|
display: "flex",
|
|
3361
3791
|
alignItems: "center",
|
|
3362
|
-
padding: "0.75rem 0 0.625rem"
|
|
3792
|
+
padding: "0.75rem 0 0.625rem",
|
|
3793
|
+
// Keep the header on top when AVS is ordered above the card on vault.
|
|
3794
|
+
order: vaultActive ? -2 : 0
|
|
3363
3795
|
}, children: [
|
|
3364
3796
|
/* @__PURE__ */ jsxs4(
|
|
3365
3797
|
"button",
|
|
@@ -3383,7 +3815,7 @@ function SplitCardFormInner({
|
|
|
3383
3815
|
},
|
|
3384
3816
|
"aria-label": "Back to payment methods",
|
|
3385
3817
|
children: [
|
|
3386
|
-
/* @__PURE__ */
|
|
3818
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
3387
3819
|
display: "inline-flex",
|
|
3388
3820
|
alignItems: "center",
|
|
3389
3821
|
justifyContent: "center",
|
|
@@ -3393,12 +3825,12 @@ function SplitCardFormInner({
|
|
|
3393
3825
|
backgroundColor: "#f3f4f6",
|
|
3394
3826
|
transition: "background-color 0.15s",
|
|
3395
3827
|
...bStyles.backButtonIcon
|
|
3396
|
-
}, children: /* @__PURE__ */
|
|
3397
|
-
/* @__PURE__ */
|
|
3828
|
+
}, children: /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
3829
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3398
3830
|
]
|
|
3399
3831
|
}
|
|
3400
3832
|
),
|
|
3401
|
-
hideTitle ? /* @__PURE__ */
|
|
3833
|
+
hideTitle ? /* @__PURE__ */ jsx7("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx7("div", { style: {
|
|
3402
3834
|
flex: 1,
|
|
3403
3835
|
textAlign: "center",
|
|
3404
3836
|
fontWeight: 600,
|
|
@@ -3406,58 +3838,65 @@ function SplitCardFormInner({
|
|
|
3406
3838
|
color: "#262833",
|
|
3407
3839
|
paddingRight: 80,
|
|
3408
3840
|
...bStyles.title
|
|
3409
|
-
}, children: /* @__PURE__ */
|
|
3841
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) })
|
|
3410
3842
|
] }),
|
|
3411
|
-
!isButtons && !hideTitle && /* @__PURE__ */
|
|
3843
|
+
!isButtons && !hideTitle && /* @__PURE__ */ jsx7("div", { style: {
|
|
3412
3844
|
textAlign: "center",
|
|
3413
3845
|
fontWeight: 600,
|
|
3414
3846
|
fontSize: "1.1rem",
|
|
3415
3847
|
padding: "0.5rem 0",
|
|
3416
3848
|
color: resolvedTitleColor,
|
|
3849
|
+
// Keep the title at the very top on the vault path. The card-form slot
|
|
3850
|
+
// (-2) and AVS block (-1) are ordered below it but above the card form.
|
|
3851
|
+
order: vaultActive ? -3 : 0,
|
|
3417
3852
|
...bStyles.title
|
|
3418
|
-
}, children: /* @__PURE__ */
|
|
3419
|
-
/* @__PURE__ */
|
|
3420
|
-
|
|
3421
|
-
border: `1px solid ${resolvedBorder}`,
|
|
3422
|
-
borderTopLeftRadius: "8px",
|
|
3423
|
-
borderTopRightRadius: "8px",
|
|
3424
|
-
padding: "10px"
|
|
3425
|
-
}, children: /* @__PURE__ */ jsx6(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
|
|
3426
|
-
/* @__PURE__ */ jsxs4("div", { style: { display: "flex" }, children: [
|
|
3427
|
-
/* @__PURE__ */ jsx6("div", { style: {
|
|
3428
|
-
flex: 1,
|
|
3429
|
-
backgroundColor: cardInputBg,
|
|
3430
|
-
// Longhand only — mixing `border` shorthand with per-side
|
|
3431
|
-
// overrides triggers React's "shorthand vs longhand" warning
|
|
3432
|
-
// because render order isn't deterministic.
|
|
3433
|
-
borderTop: "none",
|
|
3434
|
-
borderRight: "none",
|
|
3435
|
-
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3436
|
-
borderLeft: `1px solid ${resolvedBorder}`,
|
|
3437
|
-
borderBottomLeftRadius: "8px",
|
|
3438
|
-
padding: "10px"
|
|
3439
|
-
}, children: /* @__PURE__ */ jsx6(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
3440
|
-
/* @__PURE__ */ jsx6("div", { style: {
|
|
3441
|
-
flex: 1,
|
|
3853
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) }),
|
|
3854
|
+
!vaultActive && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3855
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
3442
3856
|
backgroundColor: cardInputBg,
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
borderLeft: `1px solid ${resolvedBorder}`,
|
|
3447
|
-
borderBottomRightRadius: "8px",
|
|
3857
|
+
border: `1px solid ${resolvedBorder}`,
|
|
3858
|
+
borderTopLeftRadius: resolvedBorderRadius,
|
|
3859
|
+
borderTopRightRadius: resolvedBorderRadius,
|
|
3448
3860
|
padding: "10px"
|
|
3449
|
-
}, children: /* @__PURE__ */
|
|
3861
|
+
}, children: /* @__PURE__ */ jsx7(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
|
|
3862
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex" }, children: [
|
|
3863
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
3864
|
+
flex: 1,
|
|
3865
|
+
backgroundColor: cardInputBg,
|
|
3866
|
+
// Longhand only — mixing `border` shorthand with per-side
|
|
3867
|
+
// overrides triggers React's "shorthand vs longhand" warning
|
|
3868
|
+
// because render order isn't deterministic.
|
|
3869
|
+
borderTop: "none",
|
|
3870
|
+
borderRight: "none",
|
|
3871
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3872
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
3873
|
+
borderBottomLeftRadius: resolvedBorderRadius,
|
|
3874
|
+
padding: "10px"
|
|
3875
|
+
}, children: /* @__PURE__ */ jsx7(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
3876
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
3877
|
+
flex: 1,
|
|
3878
|
+
backgroundColor: cardInputBg,
|
|
3879
|
+
borderTop: "none",
|
|
3880
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3881
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3882
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
3883
|
+
borderBottomRightRadius: resolvedBorderRadius,
|
|
3884
|
+
padding: "10px"
|
|
3885
|
+
}, children: /* @__PURE__ */ jsx7(CardCvcElement, { options: stripeElementStyle }) })
|
|
3886
|
+
] })
|
|
3450
3887
|
] }),
|
|
3451
|
-
/* @__PURE__ */
|
|
3888
|
+
!vaultActive && /* @__PURE__ */ jsx7("div", { style: {
|
|
3452
3889
|
backgroundColor: cardInputBg,
|
|
3453
3890
|
border: `1px solid ${resolvedBorder}`,
|
|
3454
|
-
borderRadius:
|
|
3891
|
+
borderRadius: resolvedBorderRadius,
|
|
3455
3892
|
marginTop: "0.5rem",
|
|
3456
3893
|
padding: "10px"
|
|
3457
|
-
}, children: /* @__PURE__ */
|
|
3894
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
3458
3895
|
"input",
|
|
3459
3896
|
{
|
|
3460
3897
|
className: "flopay-shared-input",
|
|
3898
|
+
id: "flopay-cc-name",
|
|
3899
|
+
name: "cc-name",
|
|
3461
3900
|
placeholder: "Full Name on Card",
|
|
3462
3901
|
autoComplete: "cc-name",
|
|
3463
3902
|
value: fullName,
|
|
@@ -3474,32 +3913,32 @@ function SplitCardFormInner({
|
|
|
3474
3913
|
}
|
|
3475
3914
|
}
|
|
3476
3915
|
) }),
|
|
3477
|
-
avsConfig && (() => {
|
|
3916
|
+
avsConfig && /* @__PURE__ */ jsx7("div", { style: { order: vaultActive ? -1 : 0 }, "data-testid": "flopay-avs-fields", children: (() => {
|
|
3478
3917
|
const cc = selectedCountry;
|
|
3479
|
-
const inputWrapStyle = (
|
|
3918
|
+
const inputWrapStyle = (invalid = false) => ({
|
|
3480
3919
|
backgroundColor: cardInputBg,
|
|
3481
|
-
border: `1px solid ${
|
|
3482
|
-
borderRadius:
|
|
3920
|
+
border: `1px solid ${avsBorderColor(invalid)}`,
|
|
3921
|
+
borderRadius: resolvedBorderRadius,
|
|
3483
3922
|
marginTop: "0.5rem",
|
|
3484
|
-
padding: "10px"
|
|
3485
|
-
...isButtons && extraStyle ? extraStyle : {}
|
|
3923
|
+
padding: "10px"
|
|
3486
3924
|
});
|
|
3487
3925
|
const inputFieldStyle = () => ({
|
|
3488
3926
|
width: "100%",
|
|
3489
3927
|
border: "none",
|
|
3490
3928
|
outline: "none",
|
|
3491
3929
|
background: "transparent",
|
|
3492
|
-
...sharedInputTypography
|
|
3493
|
-
...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
|
|
3930
|
+
...sharedInputTypography
|
|
3494
3931
|
});
|
|
3495
3932
|
const stateOpts = getStateOptions(cc);
|
|
3496
3933
|
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3497
|
-
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */
|
|
3934
|
+
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(invalidAvsFields.line1), children: /* @__PURE__ */ jsx7(
|
|
3498
3935
|
"input",
|
|
3499
3936
|
{
|
|
3500
3937
|
className: "flopay-shared-input",
|
|
3938
|
+
id: "flopay-billing-address-line1",
|
|
3939
|
+
name: "billing-address-line1",
|
|
3501
3940
|
placeholder: "Street Address (e.g. 123 Main St)",
|
|
3502
|
-
autoComplete: "address-line1",
|
|
3941
|
+
autoComplete: "billing address-line1",
|
|
3503
3942
|
value: addressLine1,
|
|
3504
3943
|
onChange: (e) => {
|
|
3505
3944
|
addressLine1Ref.current = e.target.value;
|
|
@@ -3511,12 +3950,14 @@ function SplitCardFormInner({
|
|
|
3511
3950
|
style: inputFieldStyle()
|
|
3512
3951
|
}
|
|
3513
3952
|
) }),
|
|
3514
|
-
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */
|
|
3953
|
+
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(), children: /* @__PURE__ */ jsx7(
|
|
3515
3954
|
"input",
|
|
3516
3955
|
{
|
|
3517
3956
|
className: "flopay-shared-input",
|
|
3957
|
+
id: "flopay-billing-address-line2",
|
|
3958
|
+
name: "billing-address-line2",
|
|
3518
3959
|
placeholder: "Apt, Suite, Unit (optional)",
|
|
3519
|
-
autoComplete: "address-line2",
|
|
3960
|
+
autoComplete: "billing address-line2",
|
|
3520
3961
|
value: addressLine2,
|
|
3521
3962
|
onChange: (e) => {
|
|
3522
3963
|
addressLine2Ref.current = e.target.value;
|
|
@@ -3532,24 +3973,25 @@ function SplitCardFormInner({
|
|
|
3532
3973
|
gap: "0",
|
|
3533
3974
|
marginTop: "0.5rem"
|
|
3534
3975
|
}, children: [
|
|
3535
|
-
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */
|
|
3976
|
+
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
3536
3977
|
flex: 1,
|
|
3537
3978
|
backgroundColor: cardInputBg,
|
|
3538
|
-
borderTop: `1px solid ${
|
|
3539
|
-
borderRight: `1px solid ${
|
|
3540
|
-
borderBottom: `1px solid ${
|
|
3541
|
-
borderLeft: `1px solid ${
|
|
3979
|
+
borderTop: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
3980
|
+
borderRight: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
3981
|
+
borderBottom: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
3982
|
+
borderLeft: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
3542
3983
|
padding: "10px",
|
|
3543
|
-
borderTopLeftRadius:
|
|
3544
|
-
borderBottomLeftRadius:
|
|
3545
|
-
...isAVSFieldVisible(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius:
|
|
3546
|
-
|
|
3547
|
-
}, children: /* @__PURE__ */ jsx6(
|
|
3984
|
+
borderTopLeftRadius: resolvedBorderRadius,
|
|
3985
|
+
borderBottomLeftRadius: resolvedBorderRadius,
|
|
3986
|
+
...isAVSFieldVisible(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: resolvedBorderRadius }
|
|
3987
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
3548
3988
|
"input",
|
|
3549
3989
|
{
|
|
3550
3990
|
className: "flopay-shared-input",
|
|
3991
|
+
id: "flopay-billing-city",
|
|
3992
|
+
name: "billing-city",
|
|
3551
3993
|
placeholder: "City",
|
|
3552
|
-
autoComplete: "address-level2",
|
|
3994
|
+
autoComplete: "billing address-level2",
|
|
3553
3995
|
value: city,
|
|
3554
3996
|
onChange: (e) => {
|
|
3555
3997
|
cityRef.current = e.target.value;
|
|
@@ -3561,39 +4003,42 @@ function SplitCardFormInner({
|
|
|
3561
4003
|
style: inputFieldStyle()
|
|
3562
4004
|
}
|
|
3563
4005
|
) }),
|
|
3564
|
-
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */
|
|
4006
|
+
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
3565
4007
|
flex: 1,
|
|
3566
4008
|
backgroundColor: cardInputBg,
|
|
3567
|
-
border: `1px solid ${
|
|
4009
|
+
border: `1px solid ${avsBorderColor(invalidAvsFields.state)}`,
|
|
3568
4010
|
padding: "10px",
|
|
3569
|
-
borderTopRightRadius:
|
|
3570
|
-
borderBottomRightRadius:
|
|
3571
|
-
...isAVSFieldVisible(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius:
|
|
3572
|
-
...isButtons && bStyles.stateInput ? bStyles.stateInput : {}
|
|
4011
|
+
borderTopRightRadius: resolvedBorderRadius,
|
|
4012
|
+
borderBottomRightRadius: resolvedBorderRadius,
|
|
4013
|
+
...isAVSFieldVisible(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius: resolvedBorderRadius }
|
|
3573
4014
|
}, children: stateOpts ? /* @__PURE__ */ jsxs4(
|
|
3574
4015
|
"select",
|
|
3575
4016
|
{
|
|
4017
|
+
id: "flopay-billing-state",
|
|
4018
|
+
name: "billing-state",
|
|
3576
4019
|
value: stateValue,
|
|
3577
4020
|
onChange: (e) => {
|
|
3578
4021
|
stateRef.current = e.target.value;
|
|
3579
4022
|
setStateValue(e.target.value);
|
|
3580
4023
|
},
|
|
3581
4024
|
disabled: isSubmitting,
|
|
3582
|
-
autoComplete: "address-level1",
|
|
4025
|
+
autoComplete: "billing address-level1",
|
|
3583
4026
|
required: true,
|
|
3584
4027
|
"data-testid": "flopay-state",
|
|
3585
4028
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
3586
4029
|
children: [
|
|
3587
|
-
/* @__PURE__ */
|
|
3588
|
-
stateOpts.map((s) => /* @__PURE__ */
|
|
4030
|
+
/* @__PURE__ */ jsx7("option", { value: "", children: getStateLabel(cc) }),
|
|
4031
|
+
stateOpts.map((s) => /* @__PURE__ */ jsx7("option", { value: s.code, children: s.name }, s.code))
|
|
3589
4032
|
]
|
|
3590
4033
|
}
|
|
3591
|
-
) : /* @__PURE__ */
|
|
4034
|
+
) : /* @__PURE__ */ jsx7(
|
|
3592
4035
|
"input",
|
|
3593
4036
|
{
|
|
3594
4037
|
className: "flopay-shared-input",
|
|
4038
|
+
id: "flopay-billing-state",
|
|
4039
|
+
name: "billing-state",
|
|
3595
4040
|
placeholder: getStateLabel(cc),
|
|
3596
|
-
autoComplete: "address-level1",
|
|
4041
|
+
autoComplete: "billing address-level1",
|
|
3597
4042
|
value: stateValue,
|
|
3598
4043
|
onChange: (e) => {
|
|
3599
4044
|
stateRef.current = e.target.value;
|
|
@@ -3612,7 +4057,7 @@ function SplitCardFormInner({
|
|
|
3612
4057
|
gap: avsLayoutProp === "column" ? "0.5rem" : "0",
|
|
3613
4058
|
marginTop: "0.5rem"
|
|
3614
4059
|
}, children: [
|
|
3615
|
-
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */
|
|
4060
|
+
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
3616
4061
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
3617
4062
|
backgroundColor: cardInputBg,
|
|
3618
4063
|
borderTop: `1px solid ${resolvedBorder}`,
|
|
@@ -3620,11 +4065,12 @@ function SplitCardFormInner({
|
|
|
3620
4065
|
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3621
4066
|
borderLeft: `1px solid ${resolvedBorder}`,
|
|
3622
4067
|
padding: "10px",
|
|
3623
|
-
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius:
|
|
3624
|
-
|
|
3625
|
-
}, children: /* @__PURE__ */ jsx6(
|
|
4068
|
+
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: resolvedBorderRadius, borderBottomLeftRadius: resolvedBorderRadius, borderRight: "none" } : { borderRadius: resolvedBorderRadius }
|
|
4069
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
3626
4070
|
"select",
|
|
3627
4071
|
{
|
|
4072
|
+
id: "flopay-billing-country",
|
|
4073
|
+
name: "billing-country",
|
|
3628
4074
|
value: selectedCountry,
|
|
3629
4075
|
onChange: (e) => {
|
|
3630
4076
|
selectedCountryRef.current = e.target.value;
|
|
@@ -3634,7 +4080,7 @@ function SplitCardFormInner({
|
|
|
3634
4080
|
setStateValue("");
|
|
3635
4081
|
},
|
|
3636
4082
|
disabled: isSubmitting,
|
|
3637
|
-
autoComplete: "country",
|
|
4083
|
+
autoComplete: "billing country",
|
|
3638
4084
|
"data-testid": "flopay-country",
|
|
3639
4085
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
3640
4086
|
children: COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ jsxs4("option", { value: c.code, children: [
|
|
@@ -3644,34 +4090,55 @@ function SplitCardFormInner({
|
|
|
3644
4090
|
] }, c.code))
|
|
3645
4091
|
}
|
|
3646
4092
|
) }),
|
|
3647
|
-
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */
|
|
4093
|
+
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
3648
4094
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
3649
4095
|
backgroundColor: cardInputBg,
|
|
3650
|
-
border: `1px solid ${
|
|
4096
|
+
border: `1px solid ${zipBorderColor}`,
|
|
3651
4097
|
padding: "10px",
|
|
3652
|
-
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius:
|
|
3653
|
-
|
|
3654
|
-
}, children: /* @__PURE__ */ jsx6(
|
|
4098
|
+
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: resolvedBorderRadius, borderBottomRightRadius: resolvedBorderRadius } : { borderRadius: resolvedBorderRadius }
|
|
4099
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
3655
4100
|
"input",
|
|
3656
4101
|
{
|
|
3657
4102
|
className: "flopay-shared-input",
|
|
4103
|
+
id: "flopay-billing-postal-code",
|
|
4104
|
+
name: "billing-postal-code",
|
|
3658
4105
|
placeholder: getPostalCodeLabel(selectedCountry),
|
|
3659
|
-
autoComplete: "postal-code",
|
|
4106
|
+
autoComplete: "billing postal-code",
|
|
3660
4107
|
value: zipCode,
|
|
3661
4108
|
onChange: (e) => {
|
|
3662
4109
|
zipCodeRef.current = e.target.value;
|
|
3663
4110
|
setZipCode(e.target.value);
|
|
3664
4111
|
onZipChange?.(e.target.value);
|
|
3665
4112
|
},
|
|
4113
|
+
onBlur: () => setZipTouched(true),
|
|
3666
4114
|
disabled: isSubmitting,
|
|
3667
|
-
required:
|
|
4115
|
+
required: postalCodeState.required,
|
|
4116
|
+
"aria-invalid": showPostcodeError || void 0,
|
|
4117
|
+
"aria-describedby": showPostcodeError ? "flopay-billing-postal-code-error" : void 0,
|
|
3668
4118
|
"data-testid": "flopay-zip",
|
|
3669
4119
|
style: inputFieldStyle()
|
|
3670
4120
|
}
|
|
3671
4121
|
) })
|
|
3672
|
-
] })
|
|
4122
|
+
] }),
|
|
4123
|
+
showPostcodeError && /* @__PURE__ */ jsx7(
|
|
4124
|
+
"div",
|
|
4125
|
+
{
|
|
4126
|
+
id: "flopay-billing-postal-code-error",
|
|
4127
|
+
role: "alert",
|
|
4128
|
+
"data-testid": "flopay-zip-error",
|
|
4129
|
+
style: {
|
|
4130
|
+
marginTop: "0.375rem",
|
|
4131
|
+
color: resolvedDangerColor,
|
|
4132
|
+
...sharedInputTypography,
|
|
4133
|
+
fontSize: "0.75rem"
|
|
4134
|
+
},
|
|
4135
|
+
children: postalCodeState.empty ? `${getPostalCodeLabel(cc)} is required` : malformedPostcodeMessage(cc)
|
|
4136
|
+
}
|
|
4137
|
+
)
|
|
3673
4138
|
] });
|
|
3674
|
-
})(),
|
|
4139
|
+
})() }),
|
|
4140
|
+
vaultActive && cardPreFormSlot && /* @__PURE__ */ jsx7("div", { style: { order: -2, width: "100%" }, children: cardPreFormSlot }),
|
|
4141
|
+
vaultActive && vaultCardFieldsNode,
|
|
3675
4142
|
displayError && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
3676
4143
|
margin: "0.75rem 0",
|
|
3677
4144
|
padding: "0.625rem 0.875rem",
|
|
@@ -3686,15 +4153,21 @@ function SplitCardFormInner({
|
|
|
3686
4153
|
gap: "0.5rem",
|
|
3687
4154
|
...bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
3688
4155
|
}, children: [
|
|
3689
|
-
/* @__PURE__ */
|
|
4156
|
+
/* @__PURE__ */ jsx7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx7("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" }) }),
|
|
3690
4157
|
displayError
|
|
3691
4158
|
] }),
|
|
3692
|
-
children ?? /* @__PURE__ */
|
|
4159
|
+
!vaultActive && (children ?? /* @__PURE__ */ jsx7(
|
|
3693
4160
|
"button",
|
|
3694
4161
|
{
|
|
3695
4162
|
type: "submit",
|
|
3696
4163
|
disabled: !formReady || isSubmitting,
|
|
3697
4164
|
"data-testid": "flopay-submit",
|
|
4165
|
+
onMouseEnter: (e) => {
|
|
4166
|
+
if (formReady && !isSubmitting) e.currentTarget.style.backgroundColor = resolvedPrimaryHoverColor;
|
|
4167
|
+
},
|
|
4168
|
+
onMouseLeave: (e) => {
|
|
4169
|
+
e.currentTarget.style.backgroundColor = bStyles.submitButton?.backgroundColor ?? resolvedPrimaryColor;
|
|
4170
|
+
},
|
|
3698
4171
|
style: {
|
|
3699
4172
|
width: "100%",
|
|
3700
4173
|
padding: "0.875rem",
|
|
@@ -3707,11 +4180,12 @@ function SplitCardFormInner({
|
|
|
3707
4180
|
fontWeight: 600,
|
|
3708
4181
|
cursor: !formReady || isSubmitting ? "not-allowed" : "pointer",
|
|
3709
4182
|
opacity: !formReady || isSubmitting ? 0.5 : 1,
|
|
4183
|
+
transition: "background-color 0.15s",
|
|
3710
4184
|
...bStyles.submitButton
|
|
3711
4185
|
},
|
|
3712
4186
|
children: isSubmitting ? "PROCESSING..." : submitLabel
|
|
3713
4187
|
}
|
|
3714
|
-
)
|
|
4188
|
+
))
|
|
3715
4189
|
] });
|
|
3716
4190
|
const gateDebugStyle = {
|
|
3717
4191
|
margin: 0,
|
|
@@ -3727,9 +4201,9 @@ function SplitCardFormInner({
|
|
|
3727
4201
|
const renderDirectPaypalGateDebug = (testId) => {
|
|
3728
4202
|
if (!debug) return null;
|
|
3729
4203
|
if (!showPayPal || !directPaypalConfigured) {
|
|
3730
|
-
return /* @__PURE__ */
|
|
4204
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/DirectPayPal-debug - not enabled" });
|
|
3731
4205
|
}
|
|
3732
|
-
return /* @__PURE__ */
|
|
4206
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3733
4207
|
"FloPay/DirectPayPal-debug (parent gate)",
|
|
3734
4208
|
` showPayPal=${showPayPal}`,
|
|
3735
4209
|
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
@@ -3742,9 +4216,9 @@ function SplitCardFormInner({
|
|
|
3742
4216
|
const renderStripeGateDebug = (testId) => {
|
|
3743
4217
|
if (!debug) return null;
|
|
3744
4218
|
if (!showStripe || !stripeInstance) {
|
|
3745
|
-
return /* @__PURE__ */
|
|
4219
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/Stripe-debug - not enabled" });
|
|
3746
4220
|
}
|
|
3747
|
-
return /* @__PURE__ */
|
|
4221
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3748
4222
|
"FloPay/Stripe-debug (parent gate)",
|
|
3749
4223
|
` showStripe=${showStripe}`,
|
|
3750
4224
|
` currency=${currency}`,
|
|
@@ -3774,8 +4248,8 @@ function SplitCardFormInner({
|
|
|
3774
4248
|
const buttonsAnim = viewState === "expanding" || viewState === "apm-expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" || viewState === "apm-collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
|
|
3775
4249
|
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;
|
|
3776
4250
|
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
3777
|
-
/* @__PURE__ */
|
|
3778
|
-
overlayStatus && /* @__PURE__ */
|
|
4251
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
4252
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
3779
4253
|
/* @__PURE__ */ jsxs4("div", { style: { display: "grid" }, children: [
|
|
3780
4254
|
/* @__PURE__ */ jsxs4(
|
|
3781
4255
|
"div",
|
|
@@ -3795,7 +4269,7 @@ function SplitCardFormInner({
|
|
|
3795
4269
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug"),
|
|
3796
4270
|
renderStripeGateDebug("flopay-stripe-gate-debug"),
|
|
3797
4271
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3798
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
4272
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
3799
4273
|
"div",
|
|
3800
4274
|
{
|
|
3801
4275
|
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
@@ -3811,7 +4285,7 @@ function SplitCardFormInner({
|
|
|
3811
4285
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
3812
4286
|
}
|
|
3813
4287
|
),
|
|
3814
|
-
/* @__PURE__ */
|
|
4288
|
+
/* @__PURE__ */ jsx7(
|
|
3815
4289
|
DirectPayPalButton,
|
|
3816
4290
|
{
|
|
3817
4291
|
sessionId,
|
|
@@ -3837,7 +4311,7 @@ function SplitCardFormInner({
|
|
|
3837
4311
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
3838
4312
|
)
|
|
3839
4313
|
] }),
|
|
3840
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
4314
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
3841
4315
|
PayPalButtonInner,
|
|
3842
4316
|
{
|
|
3843
4317
|
sessionId,
|
|
@@ -3851,10 +4325,10 @@ function SplitCardFormInner({
|
|
|
3851
4325
|
onDecline,
|
|
3852
4326
|
runBeforeButtonClick,
|
|
3853
4327
|
onLoadStateChange: setPaypalLoadState,
|
|
3854
|
-
placeholderBorderRadius:
|
|
4328
|
+
placeholderBorderRadius: buttonBorderRadius
|
|
3855
4329
|
}
|
|
3856
4330
|
) }),
|
|
3857
|
-
shouldRenderWallets ? /* @__PURE__ */
|
|
4331
|
+
shouldRenderWallets ? /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
3858
4332
|
WalletButtonInner,
|
|
3859
4333
|
{
|
|
3860
4334
|
sessionId,
|
|
@@ -3868,10 +4342,10 @@ function SplitCardFormInner({
|
|
|
3868
4342
|
onDecline,
|
|
3869
4343
|
runBeforeButtonClick,
|
|
3870
4344
|
onLoadStateChange: setWalletLoadState,
|
|
3871
|
-
placeholderBorderRadius:
|
|
4345
|
+
placeholderBorderRadius: buttonBorderRadius
|
|
3872
4346
|
}
|
|
3873
|
-
) }) : shouldShowWallets ? /* @__PURE__ */
|
|
3874
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
4347
|
+
) }) : shouldShowWallets ? /* @__PURE__ */ jsx7("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: buttonBorderRadius, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
4348
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
3875
4349
|
StripePaymentElementInner,
|
|
3876
4350
|
{
|
|
3877
4351
|
sessionId,
|
|
@@ -3899,11 +4373,11 @@ function SplitCardFormInner({
|
|
|
3899
4373
|
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
3900
4374
|
borderColor: bStyles.cardInputBorder,
|
|
3901
4375
|
textColor: bStyles.cardButton?.color,
|
|
3902
|
-
borderRadius:
|
|
4376
|
+
borderRadius: buttonBorderRadius
|
|
3903
4377
|
}
|
|
3904
4378
|
}
|
|
3905
4379
|
),
|
|
3906
|
-
showStripe && /* @__PURE__ */
|
|
4380
|
+
showStripe && /* @__PURE__ */ jsx7(
|
|
3907
4381
|
"button",
|
|
3908
4382
|
{
|
|
3909
4383
|
type: "button",
|
|
@@ -3931,7 +4405,8 @@ function SplitCardFormInner({
|
|
|
3931
4405
|
themeBundle,
|
|
3932
4406
|
resolvedPrimaryColor,
|
|
3933
4407
|
resolvedBorderRadius,
|
|
3934
|
-
submitButtonStyle: bStyles.submitButton
|
|
4408
|
+
submitButtonStyle: bStyles.submitButton,
|
|
4409
|
+
explicitPrimaryColor: appearanceVars?.colorPrimary
|
|
3935
4410
|
}),
|
|
3936
4411
|
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
3937
4412
|
fontWeight: 600,
|
|
@@ -3940,17 +4415,25 @@ function SplitCardFormInner({
|
|
|
3940
4415
|
alignItems: "center",
|
|
3941
4416
|
justifyContent: "center",
|
|
3942
4417
|
gap: "0.625rem",
|
|
3943
|
-
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
4418
|
+
transition: "background-color 0.15s, border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
3944
4419
|
position: "relative",
|
|
3945
4420
|
opacity: isSubmitting ? 0.6 : 1
|
|
3946
4421
|
},
|
|
4422
|
+
onMouseEnter: (e) => {
|
|
4423
|
+
if (!isSubmitting && (themeBundle || appearanceVars?.colorPrimary)) {
|
|
4424
|
+
e.currentTarget.style.backgroundColor = resolvedPrimaryHoverColor;
|
|
4425
|
+
}
|
|
4426
|
+
},
|
|
4427
|
+
onMouseLeave: (e) => {
|
|
4428
|
+
if (themeBundle || appearanceVars?.colorPrimary) e.currentTarget.style.backgroundColor = resolvedPrimaryColor;
|
|
4429
|
+
},
|
|
3947
4430
|
onMouseDown: (e) => {
|
|
3948
4431
|
e.currentTarget.style.transform = "scale(0.985)";
|
|
3949
4432
|
},
|
|
3950
4433
|
onMouseUp: (e) => {
|
|
3951
4434
|
e.currentTarget.style.transform = "scale(1)";
|
|
3952
4435
|
},
|
|
3953
|
-
children: /* @__PURE__ */
|
|
4436
|
+
children: /* @__PURE__ */ jsx7(CardButtonContentSlot, { content: cardButtonContent })
|
|
3954
4437
|
}
|
|
3955
4438
|
),
|
|
3956
4439
|
displayError && viewState === "buttons" && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
@@ -3967,18 +4450,18 @@ function SplitCardFormInner({
|
|
|
3967
4450
|
gap: "0.5rem",
|
|
3968
4451
|
...bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
3969
4452
|
}, children: [
|
|
3970
|
-
/* @__PURE__ */
|
|
4453
|
+
/* @__PURE__ */ jsx7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx7("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" }) }),
|
|
3971
4454
|
displayError
|
|
3972
4455
|
] })
|
|
3973
4456
|
]
|
|
3974
4457
|
}
|
|
3975
4458
|
),
|
|
3976
|
-
showStripe && isCardView && /* @__PURE__ */
|
|
4459
|
+
showStripe && isCardView && /* @__PURE__ */ jsx7("div", { style: {
|
|
3977
4460
|
gridArea: "1 / 1",
|
|
3978
4461
|
...cardAnim ? { animation: cardAnim } : {},
|
|
3979
4462
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
3980
4463
|
}, children: cardFormBlock }),
|
|
3981
|
-
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */
|
|
4464
|
+
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */ jsx7("div", { style: {
|
|
3982
4465
|
gridArea: "1 / 1",
|
|
3983
4466
|
...apmAnim ? { animation: apmAnim } : {},
|
|
3984
4467
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
@@ -4016,7 +4499,7 @@ function SplitCardFormInner({
|
|
|
4016
4499
|
},
|
|
4017
4500
|
"aria-label": "Back to payment methods",
|
|
4018
4501
|
children: [
|
|
4019
|
-
/* @__PURE__ */
|
|
4502
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
4020
4503
|
display: "inline-flex",
|
|
4021
4504
|
alignItems: "center",
|
|
4022
4505
|
justifyContent: "center",
|
|
@@ -4026,12 +4509,12 @@ function SplitCardFormInner({
|
|
|
4026
4509
|
backgroundColor: "#f3f4f6",
|
|
4027
4510
|
transition: "background-color 0.15s",
|
|
4028
4511
|
...bStyles.backButtonIcon
|
|
4029
|
-
}, children: /* @__PURE__ */
|
|
4030
|
-
/* @__PURE__ */
|
|
4512
|
+
}, children: /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
4513
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
4031
4514
|
]
|
|
4032
4515
|
}
|
|
4033
4516
|
),
|
|
4034
|
-
/* @__PURE__ */
|
|
4517
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
4035
4518
|
flex: 1,
|
|
4036
4519
|
textAlign: "center",
|
|
4037
4520
|
fontWeight: 600,
|
|
@@ -4041,12 +4524,12 @@ function SplitCardFormInner({
|
|
|
4041
4524
|
...bStyles.title
|
|
4042
4525
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
4043
4526
|
] }),
|
|
4044
|
-
/* @__PURE__ */
|
|
4527
|
+
/* @__PURE__ */ jsx7(
|
|
4045
4528
|
StripeElements,
|
|
4046
4529
|
{
|
|
4047
4530
|
stripe: stripeInstance,
|
|
4048
4531
|
options: apmInlineOptions,
|
|
4049
|
-
children: /* @__PURE__ */
|
|
4532
|
+
children: /* @__PURE__ */ jsx7(
|
|
4050
4533
|
StripeMethodInlineForm,
|
|
4051
4534
|
{
|
|
4052
4535
|
method: expandedApmMethod,
|
|
@@ -4064,7 +4547,8 @@ function SplitCardFormInner({
|
|
|
4064
4547
|
isProcessing: isSubmitting,
|
|
4065
4548
|
submitButtonColor: resolvedPrimaryColor,
|
|
4066
4549
|
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4067
|
-
submitButtonStyle: bStyles.submitButton
|
|
4550
|
+
submitButtonStyle: bStyles.submitButton,
|
|
4551
|
+
errorText: displayError
|
|
4068
4552
|
}
|
|
4069
4553
|
)
|
|
4070
4554
|
},
|
|
@@ -4076,9 +4560,9 @@ function SplitCardFormInner({
|
|
|
4076
4560
|
}
|
|
4077
4561
|
if (isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && showStripe) {
|
|
4078
4562
|
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
4079
|
-
/* @__PURE__ */
|
|
4080
|
-
overlayStatus && /* @__PURE__ */
|
|
4081
|
-
/* @__PURE__ */
|
|
4563
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
4564
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
4565
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
4082
4566
|
...apmAnim ? { animation: apmAnim } : {},
|
|
4083
4567
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
4084
4568
|
}, children: /* @__PURE__ */ jsxs4("div", { style: {
|
|
@@ -4115,7 +4599,7 @@ function SplitCardFormInner({
|
|
|
4115
4599
|
},
|
|
4116
4600
|
"aria-label": "Back to payment methods",
|
|
4117
4601
|
children: [
|
|
4118
|
-
/* @__PURE__ */
|
|
4602
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
4119
4603
|
display: "inline-flex",
|
|
4120
4604
|
alignItems: "center",
|
|
4121
4605
|
justifyContent: "center",
|
|
@@ -4125,12 +4609,12 @@ function SplitCardFormInner({
|
|
|
4125
4609
|
backgroundColor: "#f3f4f6",
|
|
4126
4610
|
transition: "background-color 0.15s",
|
|
4127
4611
|
...bStyles.backButtonIcon
|
|
4128
|
-
}, children: /* @__PURE__ */
|
|
4129
|
-
/* @__PURE__ */
|
|
4612
|
+
}, children: /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
4613
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
4130
4614
|
]
|
|
4131
4615
|
}
|
|
4132
4616
|
),
|
|
4133
|
-
/* @__PURE__ */
|
|
4617
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
4134
4618
|
flex: 1,
|
|
4135
4619
|
textAlign: "center",
|
|
4136
4620
|
fontWeight: 600,
|
|
@@ -4140,12 +4624,12 @@ function SplitCardFormInner({
|
|
|
4140
4624
|
...bStyles.title
|
|
4141
4625
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
4142
4626
|
] }),
|
|
4143
|
-
/* @__PURE__ */
|
|
4627
|
+
/* @__PURE__ */ jsx7(
|
|
4144
4628
|
StripeElements,
|
|
4145
4629
|
{
|
|
4146
4630
|
stripe: stripeInstance,
|
|
4147
4631
|
options: apmInlineOptions,
|
|
4148
|
-
children: /* @__PURE__ */
|
|
4632
|
+
children: /* @__PURE__ */ jsx7(
|
|
4149
4633
|
StripeMethodInlineForm,
|
|
4150
4634
|
{
|
|
4151
4635
|
method: expandedApmMethod,
|
|
@@ -4163,7 +4647,8 @@ function SplitCardFormInner({
|
|
|
4163
4647
|
isProcessing: isSubmitting,
|
|
4164
4648
|
submitButtonColor: resolvedPrimaryColor,
|
|
4165
4649
|
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4166
|
-
submitButtonStyle: bStyles.submitButton
|
|
4650
|
+
submitButtonStyle: bStyles.submitButton,
|
|
4651
|
+
errorText: displayError
|
|
4167
4652
|
}
|
|
4168
4653
|
)
|
|
4169
4654
|
},
|
|
@@ -4173,13 +4658,13 @@ function SplitCardFormInner({
|
|
|
4173
4658
|
] });
|
|
4174
4659
|
}
|
|
4175
4660
|
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
4176
|
-
/* @__PURE__ */
|
|
4177
|
-
overlayStatus && /* @__PURE__ */
|
|
4661
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
4662
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
4178
4663
|
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4179
4664
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug-default"),
|
|
4180
4665
|
renderStripeGateDebug("flopay-stripe-gate-debug-default"),
|
|
4181
4666
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
4182
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
4667
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
4183
4668
|
"div",
|
|
4184
4669
|
{
|
|
4185
4670
|
"data-testid": "flopay-paypal-direct-retry-notice-default",
|
|
@@ -4195,7 +4680,7 @@ function SplitCardFormInner({
|
|
|
4195
4680
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
4196
4681
|
}
|
|
4197
4682
|
),
|
|
4198
|
-
/* @__PURE__ */
|
|
4683
|
+
/* @__PURE__ */ jsx7(
|
|
4199
4684
|
DirectPayPalButton,
|
|
4200
4685
|
{
|
|
4201
4686
|
sessionId,
|
|
@@ -4221,7 +4706,7 @@ function SplitCardFormInner({
|
|
|
4221
4706
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
4222
4707
|
)
|
|
4223
4708
|
] }),
|
|
4224
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
4709
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
4225
4710
|
PayPalButtonInner,
|
|
4226
4711
|
{
|
|
4227
4712
|
sessionId,
|
|
@@ -4235,10 +4720,10 @@ function SplitCardFormInner({
|
|
|
4235
4720
|
onDecline,
|
|
4236
4721
|
runBeforeButtonClick,
|
|
4237
4722
|
onLoadStateChange: setPaypalLoadState,
|
|
4238
|
-
placeholderBorderRadius:
|
|
4723
|
+
placeholderBorderRadius: buttonBorderRadius
|
|
4239
4724
|
}
|
|
4240
4725
|
) }),
|
|
4241
|
-
shouldRenderWallets && /* @__PURE__ */
|
|
4726
|
+
shouldRenderWallets && /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
4242
4727
|
WalletButtonInner,
|
|
4243
4728
|
{
|
|
4244
4729
|
sessionId,
|
|
@@ -4252,10 +4737,10 @@ function SplitCardFormInner({
|
|
|
4252
4737
|
onDecline,
|
|
4253
4738
|
runBeforeButtonClick,
|
|
4254
4739
|
onLoadStateChange: setWalletLoadState,
|
|
4255
|
-
placeholderBorderRadius:
|
|
4740
|
+
placeholderBorderRadius: buttonBorderRadius
|
|
4256
4741
|
}
|
|
4257
4742
|
) }),
|
|
4258
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
4743
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
4259
4744
|
StripePaymentElementInner,
|
|
4260
4745
|
{
|
|
4261
4746
|
sessionId,
|
|
@@ -4283,7 +4768,7 @@ function SplitCardFormInner({
|
|
|
4283
4768
|
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
4284
4769
|
borderColor: bStyles.cardInputBorder,
|
|
4285
4770
|
textColor: bStyles.cardButton?.color,
|
|
4286
|
-
borderRadius:
|
|
4771
|
+
borderRadius: buttonBorderRadius
|
|
4287
4772
|
}
|
|
4288
4773
|
}
|
|
4289
4774
|
)
|
|
@@ -4296,9 +4781,9 @@ function SplitCardFormInner({
|
|
|
4296
4781
|
color: "#999",
|
|
4297
4782
|
fontSize: "0.85rem"
|
|
4298
4783
|
}, children: [
|
|
4299
|
-
/* @__PURE__ */
|
|
4300
|
-
/* @__PURE__ */
|
|
4301
|
-
/* @__PURE__ */
|
|
4784
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
|
|
4785
|
+
/* @__PURE__ */ jsx7("span", { children: "or pay with card" }),
|
|
4786
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
4302
4787
|
] }),
|
|
4303
4788
|
showStripe && cardFormBlock
|
|
4304
4789
|
] });
|
|
@@ -4341,6 +4826,210 @@ function getRedirectResultFromCheckoutProcessError(error) {
|
|
|
4341
4826
|
paymentMethodId: error.paymentMethodId
|
|
4342
4827
|
};
|
|
4343
4828
|
}
|
|
4829
|
+
function isTerminalAutoCheckoutThreeDsOutcome(outcome) {
|
|
4830
|
+
return outcome.status === "succeeded" || outcome.status === "declined";
|
|
4831
|
+
}
|
|
4832
|
+
async function runAutoCheckoutThreeDsChallenge(input) {
|
|
4833
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
4834
|
+
throw new FloPayError4("3DS challenge requires a browser environment.", "api_error", {
|
|
4835
|
+
code: "three_ds_no_window"
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
if (input.signal?.aborted) {
|
|
4839
|
+
throw new FloPayError4("Card authentication was cancelled.", "api_error", {
|
|
4840
|
+
code: "three_ds_aborted"
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
const CHALLENGE_TIMEOUT_MS = 3e5;
|
|
4844
|
+
const CHALLENGE_POLL_INTERVAL_MS = 1e3;
|
|
4845
|
+
const COMPLETE_REQUEST_TIMEOUT_MS = 15e3;
|
|
4846
|
+
const completionEndpoint = `${input.billingApiUrl.replace(/\/$/, "")}/v1/checkouts/sessions/${encodeURIComponent(
|
|
4847
|
+
input.sessionId
|
|
4848
|
+
)}/3ds/complete`;
|
|
4849
|
+
const completeThreeDs = async () => {
|
|
4850
|
+
const controller = new AbortController();
|
|
4851
|
+
const onParentAbort = () => controller.abort();
|
|
4852
|
+
if (input.signal?.aborted) {
|
|
4853
|
+
controller.abort();
|
|
4854
|
+
} else {
|
|
4855
|
+
input.signal?.addEventListener("abort", onParentAbort);
|
|
4856
|
+
}
|
|
4857
|
+
const requestTimeout = window.setTimeout(() => controller.abort(), COMPLETE_REQUEST_TIMEOUT_MS);
|
|
4858
|
+
try {
|
|
4859
|
+
const response = await fetch(completionEndpoint, {
|
|
4860
|
+
method: "POST",
|
|
4861
|
+
headers: {
|
|
4862
|
+
"x-checkout-session-token": input.nonce,
|
|
4863
|
+
"content-type": "application/json"
|
|
4864
|
+
},
|
|
4865
|
+
body: "{}",
|
|
4866
|
+
signal: controller.signal
|
|
4867
|
+
});
|
|
4868
|
+
if (!response.ok) {
|
|
4869
|
+
return { status: "unknown" };
|
|
4870
|
+
}
|
|
4871
|
+
const json = await response.json().catch(() => null);
|
|
4872
|
+
return coerceThreeDsOutcome(json);
|
|
4873
|
+
} catch {
|
|
4874
|
+
return { status: "unknown" };
|
|
4875
|
+
} finally {
|
|
4876
|
+
window.clearTimeout(requestTimeout);
|
|
4877
|
+
input.signal?.removeEventListener("abort", onParentAbort);
|
|
4878
|
+
}
|
|
4879
|
+
};
|
|
4880
|
+
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
4881
|
+
const backdrop = document.createElement("div");
|
|
4882
|
+
backdrop.setAttribute("data-flopay-auto-3ds-overlay", "1");
|
|
4883
|
+
backdrop.setAttribute("role", "dialog");
|
|
4884
|
+
backdrop.setAttribute("aria-modal", "true");
|
|
4885
|
+
backdrop.setAttribute("aria-label", "Card authentication");
|
|
4886
|
+
backdrop.style.cssText = [
|
|
4887
|
+
"position:fixed",
|
|
4888
|
+
"inset:0",
|
|
4889
|
+
"z-index:2147483647",
|
|
4890
|
+
"background:rgba(15,23,42,0.6)",
|
|
4891
|
+
"display:flex",
|
|
4892
|
+
"align-items:center",
|
|
4893
|
+
"justify-content:center",
|
|
4894
|
+
"padding:16px"
|
|
4895
|
+
].join(";");
|
|
4896
|
+
const frame = document.createElement("iframe");
|
|
4897
|
+
frame.setAttribute("title", "Card authentication");
|
|
4898
|
+
frame.setAttribute("allow", "payment");
|
|
4899
|
+
frame.tabIndex = 0;
|
|
4900
|
+
frame.style.cssText = [
|
|
4901
|
+
"width:min(100%,460px)",
|
|
4902
|
+
"height:min(100%,640px)",
|
|
4903
|
+
"border:0",
|
|
4904
|
+
"border-radius:12px",
|
|
4905
|
+
"background:#fff",
|
|
4906
|
+
"box-shadow:0 12px 30px rgba(0,0,0,0.35)"
|
|
4907
|
+
].join(";");
|
|
4908
|
+
frame.src = input.nextActionRedirectUrl;
|
|
4909
|
+
backdrop.appendChild(frame);
|
|
4910
|
+
document.body.appendChild(backdrop);
|
|
4911
|
+
frame.focus();
|
|
4912
|
+
let expectedReturnOrigin = null;
|
|
4913
|
+
try {
|
|
4914
|
+
expectedReturnOrigin = new URL(input.billingApiUrl, window.location.href).origin;
|
|
4915
|
+
} catch {
|
|
4916
|
+
expectedReturnOrigin = null;
|
|
4917
|
+
}
|
|
4918
|
+
try {
|
|
4919
|
+
const polledOutcome = await new Promise((resolve, reject) => {
|
|
4920
|
+
let settled = false;
|
|
4921
|
+
let timer = 0;
|
|
4922
|
+
let pollTimer = 0;
|
|
4923
|
+
let loadPollTimer = 0;
|
|
4924
|
+
let pollInFlight = false;
|
|
4925
|
+
const cleanup = () => {
|
|
4926
|
+
window.clearTimeout(timer);
|
|
4927
|
+
window.clearInterval(pollTimer);
|
|
4928
|
+
window.clearTimeout(loadPollTimer);
|
|
4929
|
+
window.removeEventListener("message", listener);
|
|
4930
|
+
frame.removeEventListener("load", onFrameLoad);
|
|
4931
|
+
input.signal?.removeEventListener("abort", onAbort);
|
|
4932
|
+
};
|
|
4933
|
+
const maybeResolveFromBackend = async () => {
|
|
4934
|
+
if (settled || pollInFlight) return;
|
|
4935
|
+
pollInFlight = true;
|
|
4936
|
+
try {
|
|
4937
|
+
const outcome = await completeThreeDs();
|
|
4938
|
+
if (settled || !isTerminalAutoCheckoutThreeDsOutcome(outcome)) return;
|
|
4939
|
+
settled = true;
|
|
4940
|
+
cleanup();
|
|
4941
|
+
resolve(outcome);
|
|
4942
|
+
} finally {
|
|
4943
|
+
pollInFlight = false;
|
|
4944
|
+
}
|
|
4945
|
+
};
|
|
4946
|
+
const onFrameLoad = () => {
|
|
4947
|
+
window.clearTimeout(loadPollTimer);
|
|
4948
|
+
loadPollTimer = window.setTimeout(() => {
|
|
4949
|
+
void maybeResolveFromBackend();
|
|
4950
|
+
}, 250);
|
|
4951
|
+
};
|
|
4952
|
+
const onAbort = () => {
|
|
4953
|
+
if (settled) return;
|
|
4954
|
+
settled = true;
|
|
4955
|
+
cleanup();
|
|
4956
|
+
reject(
|
|
4957
|
+
new FloPayError4("Card authentication was cancelled.", "api_error", {
|
|
4958
|
+
code: "three_ds_aborted"
|
|
4959
|
+
})
|
|
4960
|
+
);
|
|
4961
|
+
};
|
|
4962
|
+
const listener = (event) => {
|
|
4963
|
+
if (event.source !== frame.contentWindow) return;
|
|
4964
|
+
if (expectedReturnOrigin && event.origin !== expectedReturnOrigin) return;
|
|
4965
|
+
const data = event.data;
|
|
4966
|
+
if (!data || typeof data !== "object") return;
|
|
4967
|
+
const record = data;
|
|
4968
|
+
if (record["source"] !== "flopay-vault-3ds-return") return;
|
|
4969
|
+
if (settled) return;
|
|
4970
|
+
settled = true;
|
|
4971
|
+
cleanup();
|
|
4972
|
+
resolve(null);
|
|
4973
|
+
};
|
|
4974
|
+
timer = window.setTimeout(() => {
|
|
4975
|
+
if (settled) return;
|
|
4976
|
+
settled = true;
|
|
4977
|
+
cleanup();
|
|
4978
|
+
reject(
|
|
4979
|
+
new FloPayError4("Card authentication timed out.", "api_error", {
|
|
4980
|
+
code: "three_ds_timeout"
|
|
4981
|
+
})
|
|
4982
|
+
);
|
|
4983
|
+
}, CHALLENGE_TIMEOUT_MS);
|
|
4984
|
+
pollTimer = window.setInterval(() => {
|
|
4985
|
+
void maybeResolveFromBackend();
|
|
4986
|
+
}, CHALLENGE_POLL_INTERVAL_MS);
|
|
4987
|
+
frame.addEventListener("load", onFrameLoad);
|
|
4988
|
+
window.addEventListener("message", listener);
|
|
4989
|
+
input.signal?.addEventListener("abort", onAbort);
|
|
4990
|
+
if (input.signal?.aborted) onAbort();
|
|
4991
|
+
});
|
|
4992
|
+
if (polledOutcome) {
|
|
4993
|
+
return polledOutcome;
|
|
4994
|
+
}
|
|
4995
|
+
return await completeThreeDs();
|
|
4996
|
+
} finally {
|
|
4997
|
+
backdrop.parentNode?.removeChild(backdrop);
|
|
4998
|
+
if (previousFocus?.isConnected) {
|
|
4999
|
+
previousFocus.focus();
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
function coerceThreeDsOutcome(json) {
|
|
5004
|
+
if (!json || typeof json !== "object") return { status: "unknown" };
|
|
5005
|
+
const status = typeof json["status"] === "string" ? json["status"] : "unknown";
|
|
5006
|
+
const providerIntentId = typeof json["providerIntentId"] === "string" ? json["providerIntentId"] : null;
|
|
5007
|
+
switch (status) {
|
|
5008
|
+
case "succeeded":
|
|
5009
|
+
return { status: "succeeded", providerIntentId };
|
|
5010
|
+
case "declined":
|
|
5011
|
+
return {
|
|
5012
|
+
status: "declined",
|
|
5013
|
+
providerIntentId,
|
|
5014
|
+
declineReason: typeof json["declineReason"] === "string" ? json["declineReason"] : null,
|
|
5015
|
+
gatewayDeclineReason: typeof json["gatewayDeclineReason"] === "string" ? json["gatewayDeclineReason"] : null
|
|
5016
|
+
};
|
|
5017
|
+
case "requires_action":
|
|
5018
|
+
return {
|
|
5019
|
+
status: "requires_action",
|
|
5020
|
+
providerIntentId,
|
|
5021
|
+
nextActionRedirectUrl: typeof json["nextActionRedirectUrl"] === "string" ? json["nextActionRedirectUrl"] : null
|
|
5022
|
+
};
|
|
5023
|
+
case "pending":
|
|
5024
|
+
return { status: "pending", providerIntentId };
|
|
5025
|
+
case "timeout":
|
|
5026
|
+
return { status: "timeout", providerIntentId };
|
|
5027
|
+
case "no_attempt":
|
|
5028
|
+
return { status: "no_attempt" };
|
|
5029
|
+
default:
|
|
5030
|
+
return { status: "unknown" };
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
4344
5033
|
function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
|
|
4345
5034
|
const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
|
|
4346
5035
|
const rawMessage = error?.message ?? fallbackMessage;
|
|
@@ -4782,7 +5471,7 @@ async function loadSavedPaymentProviders({
|
|
|
4782
5471
|
}
|
|
4783
5472
|
|
|
4784
5473
|
// src/flopay-checkout.tsx
|
|
4785
|
-
import { Fragment as Fragment3, jsx as
|
|
5474
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4786
5475
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
4787
5476
|
var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
|
|
4788
5477
|
var sessionInflightMap = /* @__PURE__ */ new Map();
|
|
@@ -4831,6 +5520,36 @@ function clearPayPalResumeState() {
|
|
|
4831
5520
|
console.warn("[FloPayCheckout] Failed to clear PayPal resume state.", error);
|
|
4832
5521
|
}
|
|
4833
5522
|
}
|
|
5523
|
+
function readCachedInlineSession(cacheKey) {
|
|
5524
|
+
if (!canUseStorage()) return null;
|
|
5525
|
+
const raw = window.sessionStorage.getItem(cacheKey);
|
|
5526
|
+
if (!raw) return null;
|
|
5527
|
+
try {
|
|
5528
|
+
const parsed = JSON.parse(raw);
|
|
5529
|
+
if (parsed && typeof parsed.sid === "string" && parsed.sid) {
|
|
5530
|
+
return { sid: parsed.sid, nonce: typeof parsed.nonce === "string" ? parsed.nonce : void 0 };
|
|
5531
|
+
}
|
|
5532
|
+
return null;
|
|
5533
|
+
} catch {
|
|
5534
|
+
return { sid: raw };
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
function persistCachedInlineSession(cacheKey, sid, nonce) {
|
|
5538
|
+
if (!canUseStorage()) return;
|
|
5539
|
+
try {
|
|
5540
|
+
window.sessionStorage.setItem(cacheKey, JSON.stringify(nonce ? { sid, nonce } : { sid }));
|
|
5541
|
+
} catch (error) {
|
|
5542
|
+
console.warn("[FloPayCheckout] Failed to persist checkout session cache.", error);
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
function clearCachedInlineSession(cacheKey) {
|
|
5546
|
+
if (!canUseStorage()) return;
|
|
5547
|
+
try {
|
|
5548
|
+
window.sessionStorage.removeItem(cacheKey);
|
|
5549
|
+
} catch (error) {
|
|
5550
|
+
console.warn("[FloPayCheckout] Failed to clear checkout session cache.", error);
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
4834
5553
|
function clearPayPalRedirectParams() {
|
|
4835
5554
|
if (typeof window === "undefined") return;
|
|
4836
5555
|
const url = new URL(window.location.href);
|
|
@@ -4889,6 +5608,8 @@ function FloPayCheckout({
|
|
|
4889
5608
|
onButtonClick,
|
|
4890
5609
|
onBeforeButtonClick,
|
|
4891
5610
|
enableAVS,
|
|
5611
|
+
cardFieldOrder,
|
|
5612
|
+
cardPreFormSlot,
|
|
4892
5613
|
avsLayout,
|
|
4893
5614
|
submitLabel,
|
|
4894
5615
|
className,
|
|
@@ -4906,9 +5627,9 @@ function FloPayCheckout({
|
|
|
4906
5627
|
const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
|
|
4907
5628
|
const [unified, setUnified] = useState4(null);
|
|
4908
5629
|
const [flopay, setFloPay] = useState4(null);
|
|
4909
|
-
const flopayRef =
|
|
5630
|
+
const flopayRef = useRef5(null);
|
|
4910
5631
|
const [paypalFlopay, setPaypalFloPay] = useState4(null);
|
|
4911
|
-
const paypalFlopayRef =
|
|
5632
|
+
const paypalFlopayRef = useRef5(null);
|
|
4912
5633
|
const [session, setSession] = useState4(null);
|
|
4913
5634
|
const [resolvedSessionId, setResolvedSessionId] = useState4(sessionIdProp ?? "");
|
|
4914
5635
|
const activeSessionId = sessionIdProp ?? resolvedSessionId;
|
|
@@ -4923,18 +5644,18 @@ function FloPayCheckout({
|
|
|
4923
5644
|
const [createSessionPatch, setCreateSessionPatch] = useState4(void 0);
|
|
4924
5645
|
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = useState4("");
|
|
4925
5646
|
const [cardBootstrapPending, setCardBootstrapPending] = useState4(false);
|
|
4926
|
-
const autoCheckoutAttempted =
|
|
4927
|
-
const paypalResumeAttempted =
|
|
4928
|
-
const savedPaymentKeysRef =
|
|
4929
|
-
const onCompleteRef =
|
|
5647
|
+
const autoCheckoutAttempted = useRef5(false);
|
|
5648
|
+
const paypalResumeAttempted = useRef5(false);
|
|
5649
|
+
const savedPaymentKeysRef = useRef5(null);
|
|
5650
|
+
const onCompleteRef = useRef5(onComplete);
|
|
4930
5651
|
onCompleteRef.current = onComplete;
|
|
4931
|
-
const onErrorRef =
|
|
5652
|
+
const onErrorRef = useRef5(onError);
|
|
4932
5653
|
onErrorRef.current = onError;
|
|
4933
|
-
const onDeclineRef =
|
|
5654
|
+
const onDeclineRef = useRef5(onDecline);
|
|
4934
5655
|
onDeclineRef.current = onDecline;
|
|
4935
|
-
const onSessionCompletedRef =
|
|
5656
|
+
const onSessionCompletedRef = useRef5(onSessionCompleted);
|
|
4936
5657
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
4937
|
-
|
|
5658
|
+
useEffect6(() => {
|
|
4938
5659
|
console.info("[FloPay] Checkout initialized", {
|
|
4939
5660
|
sdk_version: SDK_VERSION,
|
|
4940
5661
|
checkout_type: checkoutType,
|
|
@@ -4962,11 +5683,11 @@ function FloPayCheckout({
|
|
|
4962
5683
|
} : void 0,
|
|
4963
5684
|
[effectiveCreateSessionBase, effectiveCreateSessionMode]
|
|
4964
5685
|
);
|
|
4965
|
-
|
|
5686
|
+
useEffect6(() => {
|
|
4966
5687
|
setCreateSessionPatch(void 0);
|
|
4967
5688
|
setCreateSessionPatchBaseHash(baseCreateSessionHash);
|
|
4968
5689
|
}, [baseCreateSessionHash]);
|
|
4969
|
-
|
|
5690
|
+
useEffect6(() => {
|
|
4970
5691
|
setModeError(initialErrorMessage);
|
|
4971
5692
|
}, [initialErrorMessage]);
|
|
4972
5693
|
const emitDecline = useCallback2(
|
|
@@ -5093,7 +5814,7 @@ function FloPayCheckout({
|
|
|
5093
5814
|
resolvedBillingUrl
|
|
5094
5815
|
]
|
|
5095
5816
|
);
|
|
5096
|
-
|
|
5817
|
+
useEffect6(() => {
|
|
5097
5818
|
if (typeof window === "undefined" || paypalResumeAttempted.current) {
|
|
5098
5819
|
return;
|
|
5099
5820
|
}
|
|
@@ -5210,7 +5931,7 @@ function FloPayCheckout({
|
|
|
5210
5931
|
}
|
|
5211
5932
|
})();
|
|
5212
5933
|
}, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
|
|
5213
|
-
const initializedHashRef =
|
|
5934
|
+
const initializedHashRef = useRef5(null);
|
|
5214
5935
|
function hashCreateParams(params) {
|
|
5215
5936
|
const key = JSON.stringify({
|
|
5216
5937
|
c: params?.clientId,
|
|
@@ -5247,12 +5968,12 @@ function FloPayCheckout({
|
|
|
5247
5968
|
() => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
|
|
5248
5969
|
[effectiveCreateSession]
|
|
5249
5970
|
);
|
|
5250
|
-
const createSessionParamsRef =
|
|
5971
|
+
const createSessionParamsRef = useRef5(effectiveCreateSession);
|
|
5251
5972
|
createSessionParamsRef.current = effectiveCreateSession;
|
|
5252
|
-
|
|
5973
|
+
useEffect6(() => {
|
|
5253
5974
|
setResolvedSessionId(sessionIdProp ?? "");
|
|
5254
5975
|
}, [sessionIdProp]);
|
|
5255
|
-
|
|
5976
|
+
useEffect6(() => {
|
|
5256
5977
|
autoCheckoutAttempted.current = false;
|
|
5257
5978
|
setModeError(initialErrorMessage);
|
|
5258
5979
|
setModeOverlayError(null);
|
|
@@ -5260,22 +5981,23 @@ function FloPayCheckout({
|
|
|
5260
5981
|
}, [createSessionHash, initialErrorMessage, sessionIdProp]);
|
|
5261
5982
|
async function resolveInlineSession(params, cacheKey) {
|
|
5262
5983
|
const api = new PaymentAPI4(resolvedBillingUrl);
|
|
5263
|
-
|
|
5984
|
+
const cached = readCachedInlineSession(cacheKey);
|
|
5985
|
+
let sid = cached?.sid ?? null;
|
|
5264
5986
|
let realResult = null;
|
|
5265
5987
|
if (sid) {
|
|
5266
5988
|
try {
|
|
5267
|
-
realResult = await api.getUnifiedCheckoutSession(sid);
|
|
5989
|
+
realResult = await api.getUnifiedCheckoutSession(sid, cached?.nonce);
|
|
5268
5990
|
const status = realResult.data.session?.status;
|
|
5269
5991
|
if (status === "complete") {
|
|
5270
5992
|
if (wasSessionRecentlyCompleted(sid)) {
|
|
5271
5993
|
return { sid, result: realResult };
|
|
5272
5994
|
}
|
|
5273
|
-
|
|
5995
|
+
clearCachedInlineSession(cacheKey);
|
|
5274
5996
|
sid = null;
|
|
5275
5997
|
realResult = null;
|
|
5276
5998
|
}
|
|
5277
5999
|
} catch {
|
|
5278
|
-
|
|
6000
|
+
clearCachedInlineSession(cacheKey);
|
|
5279
6001
|
sid = null;
|
|
5280
6002
|
}
|
|
5281
6003
|
}
|
|
@@ -5289,8 +6011,8 @@ function FloPayCheckout({
|
|
|
5289
6011
|
};
|
|
5290
6012
|
realResult = await api.createAndFetchSession(paramsWithAnalytics);
|
|
5291
6013
|
sid = realResult.data.session?.id ?? "";
|
|
5292
|
-
if (sid
|
|
5293
|
-
|
|
6014
|
+
if (sid) {
|
|
6015
|
+
persistCachedInlineSession(cacheKey, sid, realResult.data.session?.clientSecret);
|
|
5294
6016
|
}
|
|
5295
6017
|
}
|
|
5296
6018
|
return { sid: sid ?? "", result: realResult };
|
|
@@ -5379,7 +6101,7 @@ function FloPayCheckout({
|
|
|
5379
6101
|
resolvedSessionId,
|
|
5380
6102
|
session
|
|
5381
6103
|
]);
|
|
5382
|
-
|
|
6104
|
+
useEffect6(() => {
|
|
5383
6105
|
let cancelled = false;
|
|
5384
6106
|
setLoadError(null);
|
|
5385
6107
|
if (createSessionHash) {
|
|
@@ -5601,7 +6323,7 @@ function FloPayCheckout({
|
|
|
5601
6323
|
]
|
|
5602
6324
|
);
|
|
5603
6325
|
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
|
|
5604
|
-
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */
|
|
6326
|
+
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ jsx8(
|
|
5605
6327
|
ProcessingOverlay,
|
|
5606
6328
|
{
|
|
5607
6329
|
status: modeOverlayStatus,
|
|
@@ -5617,7 +6339,7 @@ function FloPayCheckout({
|
|
|
5617
6339
|
}
|
|
5618
6340
|
if (layout === "buttons") {
|
|
5619
6341
|
const bundleRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
5620
|
-
const skeletonBar = (h) => /* @__PURE__ */
|
|
6342
|
+
const skeletonBar = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
5621
6343
|
height: h,
|
|
5622
6344
|
borderRadius: bundleRadius,
|
|
5623
6345
|
background: "#e5e7eb",
|
|
@@ -5628,14 +6350,14 @@ function FloPayCheckout({
|
|
|
5628
6350
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5629
6351
|
showStripe && (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5630
6352
|
showStripe && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5631
|
-
/* @__PURE__ */
|
|
6353
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
5632
6354
|
] }),
|
|
5633
6355
|
modeOverlay
|
|
5634
6356
|
] });
|
|
5635
6357
|
}
|
|
5636
6358
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
5637
6359
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
|
|
5638
|
-
/* @__PURE__ */
|
|
6360
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
5639
6361
|
width: 24,
|
|
5640
6362
|
height: 24,
|
|
5641
6363
|
border: "2px solid #e5e7eb",
|
|
@@ -5643,16 +6365,16 @@ function FloPayCheckout({
|
|
|
5643
6365
|
borderRadius: "50%",
|
|
5644
6366
|
animation: "spin 0.6s linear infinite"
|
|
5645
6367
|
} }),
|
|
5646
|
-
/* @__PURE__ */
|
|
6368
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
5647
6369
|
] }),
|
|
5648
6370
|
modeOverlay
|
|
5649
6371
|
] });
|
|
5650
6372
|
}
|
|
5651
6373
|
if (loadError) {
|
|
5652
6374
|
if (errorNode) {
|
|
5653
|
-
return /* @__PURE__ */
|
|
6375
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
|
|
5654
6376
|
}
|
|
5655
|
-
return /* @__PURE__ */
|
|
6377
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
5656
6378
|
"div",
|
|
5657
6379
|
{
|
|
5658
6380
|
role: "alert",
|
|
@@ -5669,7 +6391,7 @@ function FloPayCheckout({
|
|
|
5669
6391
|
}
|
|
5670
6392
|
if (shouldShowInterimButtons) {
|
|
5671
6393
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
5672
|
-
/* @__PURE__ */
|
|
6394
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
5673
6395
|
InterimButtonsView,
|
|
5674
6396
|
{
|
|
5675
6397
|
onButtonClick,
|
|
@@ -5690,8 +6412,8 @@ function FloPayCheckout({
|
|
|
5690
6412
|
}
|
|
5691
6413
|
if (isPaypalOnlySession && session && directPaypalConfig) {
|
|
5692
6414
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
5693
|
-
/* @__PURE__ */
|
|
5694
|
-
modeError && /* @__PURE__ */
|
|
6415
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsxs5("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
6416
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
5695
6417
|
"div",
|
|
5696
6418
|
{
|
|
5697
6419
|
role: "alert",
|
|
@@ -5708,7 +6430,7 @@ function FloPayCheckout({
|
|
|
5708
6430
|
children: modeError
|
|
5709
6431
|
}
|
|
5710
6432
|
),
|
|
5711
|
-
/* @__PURE__ */
|
|
6433
|
+
/* @__PURE__ */ jsx8(
|
|
5712
6434
|
DirectPayPalButton,
|
|
5713
6435
|
{
|
|
5714
6436
|
sessionId: activeSessionId,
|
|
@@ -5732,12 +6454,12 @@ function FloPayCheckout({
|
|
|
5732
6454
|
] });
|
|
5733
6455
|
}
|
|
5734
6456
|
if (!flopay || !providerOptions) {
|
|
5735
|
-
return /* @__PURE__ */
|
|
6457
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: modeOverlay });
|
|
5736
6458
|
}
|
|
5737
6459
|
if (currentMode === "confirm") {
|
|
5738
6460
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
5739
|
-
/* @__PURE__ */
|
|
5740
|
-
modeError && /* @__PURE__ */
|
|
6461
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ jsxs5("div", { className, children: [
|
|
6462
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
5741
6463
|
"div",
|
|
5742
6464
|
{
|
|
5743
6465
|
style: {
|
|
@@ -5752,7 +6474,7 @@ function FloPayCheckout({
|
|
|
5752
6474
|
renderConfirmButton ? renderConfirmButton({
|
|
5753
6475
|
onConfirm: handleConfirmCheckout,
|
|
5754
6476
|
isProcessing: confirmProcessing
|
|
5755
|
-
}) : /* @__PURE__ */
|
|
6477
|
+
}) : /* @__PURE__ */ jsx8(
|
|
5756
6478
|
"button",
|
|
5757
6479
|
{
|
|
5758
6480
|
type: "button",
|
|
@@ -5778,8 +6500,8 @@ function FloPayCheckout({
|
|
|
5778
6500
|
] });
|
|
5779
6501
|
}
|
|
5780
6502
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
5781
|
-
/* @__PURE__ */
|
|
5782
|
-
modeError && /* @__PURE__ */
|
|
6503
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
6504
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
5783
6505
|
"div",
|
|
5784
6506
|
{
|
|
5785
6507
|
style: {
|
|
@@ -5794,7 +6516,7 @@ function FloPayCheckout({
|
|
|
5794
6516
|
children: modeError
|
|
5795
6517
|
}
|
|
5796
6518
|
),
|
|
5797
|
-
/* @__PURE__ */
|
|
6519
|
+
/* @__PURE__ */ jsx8(
|
|
5798
6520
|
SessionInjector,
|
|
5799
6521
|
{
|
|
5800
6522
|
sessionId: activeSessionId,
|
|
@@ -5804,7 +6526,7 @@ function FloPayCheckout({
|
|
|
5804
6526
|
children
|
|
5805
6527
|
}
|
|
5806
6528
|
)
|
|
5807
|
-
] }) : /* @__PURE__ */
|
|
6529
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
5808
6530
|
SplitCardForm,
|
|
5809
6531
|
{
|
|
5810
6532
|
sessionId: activeSessionId,
|
|
@@ -5824,6 +6546,7 @@ function FloPayCheckout({
|
|
|
5824
6546
|
showPayPal,
|
|
5825
6547
|
showStripe,
|
|
5826
6548
|
enabledPaymentMethods: unified?.data.stripe?.enabledPaymentMethods,
|
|
6549
|
+
enabledPaymentMethodCountries: unified?.data.stripe?.enabledPaymentMethodCountries,
|
|
5827
6550
|
showApplePay,
|
|
5828
6551
|
showGooglePay,
|
|
5829
6552
|
layout,
|
|
@@ -5837,6 +6560,8 @@ function FloPayCheckout({
|
|
|
5837
6560
|
onButtonClick,
|
|
5838
6561
|
onBeforeButtonClick,
|
|
5839
6562
|
enableAVS,
|
|
6563
|
+
...cardFieldOrder ? { cardFieldOrder } : {},
|
|
6564
|
+
...cardPreFormSlot ? { cardPreFormSlot } : {},
|
|
5840
6565
|
avsLayout,
|
|
5841
6566
|
country: session?.customer?.country,
|
|
5842
6567
|
city: session?.customer?.city,
|
|
@@ -5864,8 +6589,8 @@ function SessionInjector({
|
|
|
5864
6589
|
session,
|
|
5865
6590
|
children
|
|
5866
6591
|
}) {
|
|
5867
|
-
return /* @__PURE__ */
|
|
5868
|
-
if (!
|
|
6592
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: React8.Children.map(children, (child) => {
|
|
6593
|
+
if (!React8.isValidElement(child)) return child;
|
|
5869
6594
|
const existing = child.props;
|
|
5870
6595
|
const injected = {};
|
|
5871
6596
|
if (!existing.sessionId) injected.sessionId = sessionId;
|
|
@@ -5880,7 +6605,7 @@ function SessionInjector({
|
|
|
5880
6605
|
injected.lastName = session.customer.lastName;
|
|
5881
6606
|
}
|
|
5882
6607
|
if (Object.keys(injected).length === 0) return child;
|
|
5883
|
-
return
|
|
6608
|
+
return React8.cloneElement(child, injected);
|
|
5884
6609
|
}) });
|
|
5885
6610
|
}
|
|
5886
6611
|
function InterimButtonsView({
|
|
@@ -5902,7 +6627,7 @@ function InterimButtonsView({
|
|
|
5902
6627
|
}) {
|
|
5903
6628
|
const [showCardForm, setShowCardForm] = useState4(false);
|
|
5904
6629
|
const isCardOpenControlled = typeof cardOpen === "boolean";
|
|
5905
|
-
|
|
6630
|
+
useEffect6(() => {
|
|
5906
6631
|
if (isCardOpenControlled) {
|
|
5907
6632
|
setShowCardForm(cardOpen);
|
|
5908
6633
|
}
|
|
@@ -5923,7 +6648,7 @@ function InterimButtonsView({
|
|
|
5923
6648
|
};
|
|
5924
6649
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
5925
6650
|
const skeletonRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
5926
|
-
const skeleton = (h) => /* @__PURE__ */
|
|
6651
|
+
const skeleton = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
5927
6652
|
height: h,
|
|
5928
6653
|
borderRadius: skeletonRadius,
|
|
5929
6654
|
background: "#e5e7eb",
|
|
@@ -5970,7 +6695,7 @@ function InterimButtonsView({
|
|
|
5970
6695
|
...bStyles.backButton
|
|
5971
6696
|
},
|
|
5972
6697
|
children: [
|
|
5973
|
-
/* @__PURE__ */
|
|
6698
|
+
/* @__PURE__ */ jsx8("span", { style: {
|
|
5974
6699
|
display: "inline-flex",
|
|
5975
6700
|
alignItems: "center",
|
|
5976
6701
|
justifyContent: "center",
|
|
@@ -5979,12 +6704,12 @@ function InterimButtonsView({
|
|
|
5979
6704
|
borderRadius: "50%",
|
|
5980
6705
|
backgroundColor: "#f3f4f6",
|
|
5981
6706
|
...bStyles.backButtonIcon
|
|
5982
|
-
}, children: /* @__PURE__ */
|
|
5983
|
-
/* @__PURE__ */
|
|
6707
|
+
}, children: /* @__PURE__ */ jsx8("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx8("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
6708
|
+
/* @__PURE__ */ jsx8(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
5984
6709
|
]
|
|
5985
6710
|
}
|
|
5986
6711
|
),
|
|
5987
|
-
hideTitle ? /* @__PURE__ */
|
|
6712
|
+
hideTitle ? /* @__PURE__ */ jsx8("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx8("div", { style: {
|
|
5988
6713
|
flex: 1,
|
|
5989
6714
|
textAlign: "center",
|
|
5990
6715
|
fontWeight: 600,
|
|
@@ -5992,11 +6717,11 @@ function InterimButtonsView({
|
|
|
5992
6717
|
color: "#262833",
|
|
5993
6718
|
paddingRight: 80,
|
|
5994
6719
|
...bStyles.title
|
|
5995
|
-
}, children: /* @__PURE__ */
|
|
6720
|
+
}, children: /* @__PURE__ */ jsx8(TitleContentSlot, { content: cardTitleContent }) })
|
|
5996
6721
|
] }),
|
|
5997
|
-
/* @__PURE__ */
|
|
6722
|
+
/* @__PURE__ */ jsx8("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ jsx8("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
5998
6723
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex" }, children: [
|
|
5999
|
-
/* @__PURE__ */
|
|
6724
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
6000
6725
|
flex: 1,
|
|
6001
6726
|
backgroundColor: inputBg,
|
|
6002
6727
|
borderTop: "none",
|
|
@@ -6006,8 +6731,8 @@ function InterimButtonsView({
|
|
|
6006
6731
|
borderBottomLeftRadius: 8,
|
|
6007
6732
|
padding: 12,
|
|
6008
6733
|
height: 45
|
|
6009
|
-
}, children: /* @__PURE__ */
|
|
6010
|
-
/* @__PURE__ */
|
|
6734
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
6735
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
6011
6736
|
flex: 1,
|
|
6012
6737
|
backgroundColor: inputBg,
|
|
6013
6738
|
borderTop: "none",
|
|
@@ -6017,10 +6742,10 @@ function InterimButtonsView({
|
|
|
6017
6742
|
borderBottomRightRadius: 8,
|
|
6018
6743
|
padding: 12,
|
|
6019
6744
|
height: 45
|
|
6020
|
-
}, children: /* @__PURE__ */
|
|
6745
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
6021
6746
|
] }),
|
|
6022
|
-
/* @__PURE__ */
|
|
6023
|
-
/* @__PURE__ */
|
|
6747
|
+
/* @__PURE__ */ jsx8("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ jsx8("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
6748
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
6024
6749
|
height: 50,
|
|
6025
6750
|
borderRadius: 8,
|
|
6026
6751
|
marginTop: 16,
|
|
@@ -6029,7 +6754,7 @@ function InterimButtonsView({
|
|
|
6029
6754
|
...bStyles.submitButton,
|
|
6030
6755
|
opacity: 0.5
|
|
6031
6756
|
} }),
|
|
6032
|
-
/* @__PURE__ */
|
|
6757
|
+
/* @__PURE__ */ jsx8("style", { children: `
|
|
6033
6758
|
@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
6034
6759
|
@keyframes flopay-interim-expand {
|
|
6035
6760
|
0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
|
|
@@ -6042,7 +6767,7 @@ function InterimButtonsView({
|
|
|
6042
6767
|
return /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
6043
6768
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
6044
6769
|
showStripe && (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
6045
|
-
showStripe && /* @__PURE__ */
|
|
6770
|
+
showStripe && /* @__PURE__ */ jsx8(
|
|
6046
6771
|
"button",
|
|
6047
6772
|
{
|
|
6048
6773
|
type: "button",
|
|
@@ -6082,7 +6807,7 @@ function InterimButtonsView({
|
|
|
6082
6807
|
onMouseUp: (e) => {
|
|
6083
6808
|
e.currentTarget.style.transform = "scale(1)";
|
|
6084
6809
|
},
|
|
6085
|
-
children: /* @__PURE__ */
|
|
6810
|
+
children: /* @__PURE__ */ jsx8(CardButtonContentSlot, { content: cardButtonContent })
|
|
6086
6811
|
}
|
|
6087
6812
|
),
|
|
6088
6813
|
errorMessage && /* @__PURE__ */ jsxs5("div", { style: {
|
|
@@ -6099,22 +6824,22 @@ function InterimButtonsView({
|
|
|
6099
6824
|
gap: "0.5rem",
|
|
6100
6825
|
...bStyles.errorBanner
|
|
6101
6826
|
}, children: [
|
|
6102
|
-
/* @__PURE__ */
|
|
6827
|
+
/* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx8("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" }) }),
|
|
6103
6828
|
errorMessage
|
|
6104
6829
|
] }),
|
|
6105
|
-
/* @__PURE__ */
|
|
6830
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
6106
6831
|
] });
|
|
6107
6832
|
}
|
|
6108
6833
|
|
|
6109
6834
|
// src/checkout-form.tsx
|
|
6110
6835
|
import { PaymentAPI as PaymentAPI5 } from "@flopay/js";
|
|
6111
6836
|
import { FloPayError as FloPayError6 } from "@flopay/shared";
|
|
6112
|
-
import { forwardRef as forwardRef2, useCallback as useCallback3, useEffect as
|
|
6113
|
-
import { Fragment as Fragment4, jsx as
|
|
6837
|
+
import { forwardRef as forwardRef2, useCallback as useCallback3, useEffect as useEffect7, useImperativeHandle as useImperativeHandle2, useState as useState5 } from "react";
|
|
6838
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6114
6839
|
var WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
6115
6840
|
var CheckoutForm = forwardRef2(
|
|
6116
6841
|
function CheckoutForm2(props, ref) {
|
|
6117
|
-
return /* @__PURE__ */
|
|
6842
|
+
return /* @__PURE__ */ jsx9(CheckoutFormInner, { ...props, innerRef: ref });
|
|
6118
6843
|
}
|
|
6119
6844
|
);
|
|
6120
6845
|
function CheckoutFormInner({
|
|
@@ -6313,7 +7038,7 @@ function CheckoutFormInner({
|
|
|
6313
7038
|
}
|
|
6314
7039
|
}
|
|
6315
7040
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
6316
|
-
|
|
7041
|
+
useEffect7(() => {
|
|
6317
7042
|
if (typeof window === "undefined") return;
|
|
6318
7043
|
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
6319
7044
|
if (!stored) return;
|
|
@@ -6424,7 +7149,7 @@ function CheckoutFormInner({
|
|
|
6424
7149
|
);
|
|
6425
7150
|
const isReady = flopay !== null && elements !== null;
|
|
6426
7151
|
return /* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
6427
|
-
(is3DSActive || isSubmitting) && /* @__PURE__ */
|
|
7152
|
+
(is3DSActive || isSubmitting) && /* @__PURE__ */ jsx9("div", { "data-testid": "flopay-overlay", style: {
|
|
6428
7153
|
position: "absolute",
|
|
6429
7154
|
inset: 0,
|
|
6430
7155
|
background: "rgba(255,255,255,0.7)",
|
|
@@ -6433,12 +7158,12 @@ function CheckoutFormInner({
|
|
|
6433
7158
|
justifyContent: "center",
|
|
6434
7159
|
zIndex: 10
|
|
6435
7160
|
}, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
|
|
6436
|
-
!isReady && /* @__PURE__ */
|
|
7161
|
+
!isReady && /* @__PURE__ */ jsx9("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
|
|
6437
7162
|
isReady && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
6438
|
-
/* @__PURE__ */
|
|
6439
|
-
showAddress && /* @__PURE__ */
|
|
6440
|
-
displayError && /* @__PURE__ */
|
|
6441
|
-
children ?? /* @__PURE__ */
|
|
7163
|
+
/* @__PURE__ */ jsx9(PaymentElement, { options: { layout } }),
|
|
7164
|
+
showAddress && /* @__PURE__ */ jsx9(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
|
|
7165
|
+
displayError && /* @__PURE__ */ jsx9("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
|
|
7166
|
+
children ?? /* @__PURE__ */ jsx9(
|
|
6442
7167
|
"button",
|
|
6443
7168
|
{
|
|
6444
7169
|
type: "submit",
|
|
@@ -6454,8 +7179,8 @@ function CheckoutFormInner({
|
|
|
6454
7179
|
// src/paypal-button.tsx
|
|
6455
7180
|
import { PaymentAPI as PaymentAPI6 } from "@flopay/js";
|
|
6456
7181
|
import { FloPayError as FloPayError7 } from "@flopay/shared";
|
|
6457
|
-
import { useCallback as useCallback4, useEffect as
|
|
6458
|
-
import { Fragment as Fragment5, jsx as
|
|
7182
|
+
import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef6, useState as useState6 } from "react";
|
|
7183
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
6459
7184
|
function PayPalButton({
|
|
6460
7185
|
sessionId,
|
|
6461
7186
|
nonce,
|
|
@@ -6475,7 +7200,7 @@ function PayPalButton({
|
|
|
6475
7200
|
const contextBillingUrl = useBillingApiUrl();
|
|
6476
7201
|
const [ready, setReady] = useState6(false);
|
|
6477
7202
|
const [submitting, setSubmitting] = useState6(false);
|
|
6478
|
-
const paypalResumeAttempted =
|
|
7203
|
+
const paypalResumeAttempted = useRef6(false);
|
|
6479
7204
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
6480
7205
|
const processPaymentInternal = useCallback4(
|
|
6481
7206
|
async (tokenizedBody) => {
|
|
@@ -6515,7 +7240,7 @@ function PayPalButton({
|
|
|
6515
7240
|
},
|
|
6516
7241
|
[onTokenizedBody, processPaymentInternal]
|
|
6517
7242
|
);
|
|
6518
|
-
|
|
7243
|
+
useEffect8(() => {
|
|
6519
7244
|
if (!flopay || paypalResumeAttempted.current) return;
|
|
6520
7245
|
const params = new URLSearchParams(window.location.search);
|
|
6521
7246
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -6597,11 +7322,11 @@ function PayPalButton({
|
|
|
6597
7322
|
}
|
|
6598
7323
|
}, [flopay, elements, sessionId, nonce, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
|
|
6599
7324
|
if (!flopay || !elements) {
|
|
6600
|
-
return /* @__PURE__ */
|
|
7325
|
+
return /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
|
|
6601
7326
|
}
|
|
6602
7327
|
return /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
6603
|
-
!ready && /* @__PURE__ */
|
|
6604
|
-
/* @__PURE__ */
|
|
7328
|
+
!ready && /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
|
|
7329
|
+
/* @__PURE__ */ jsx10("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ jsx10(
|
|
6605
7330
|
"button",
|
|
6606
7331
|
{
|
|
6607
7332
|
type: "button",
|
|
@@ -6623,7 +7348,7 @@ function PayPalButton({
|
|
|
6623
7348
|
children: submitting ? "Processing..." : "PayPal"
|
|
6624
7349
|
}
|
|
6625
7350
|
) }),
|
|
6626
|
-
(submitting || isProcessing) && /* @__PURE__ */
|
|
7351
|
+
(submitting || isProcessing) && /* @__PURE__ */ jsx10("div", { style: {
|
|
6627
7352
|
position: "fixed",
|
|
6628
7353
|
inset: 0,
|
|
6629
7354
|
background: "rgba(0,0,0,0.4)",
|
|
@@ -6631,7 +7356,7 @@ function PayPalButton({
|
|
|
6631
7356
|
alignItems: "center",
|
|
6632
7357
|
justifyContent: "center",
|
|
6633
7358
|
zIndex: 1e3
|
|
6634
|
-
}, children: /* @__PURE__ */
|
|
7359
|
+
}, children: /* @__PURE__ */ jsx10("div", { style: {
|
|
6635
7360
|
background: "white",
|
|
6636
7361
|
borderRadius: 8,
|
|
6637
7362
|
padding: "1.5rem",
|
|
@@ -6643,10 +7368,10 @@ function PayPalButton({
|
|
|
6643
7368
|
}
|
|
6644
7369
|
|
|
6645
7370
|
// src/automatic-payment-button.tsx
|
|
6646
|
-
import { useCallback as useCallback5, useEffect as
|
|
7371
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as useMemo5, useRef as useRef7, useState as useState7 } from "react";
|
|
6647
7372
|
import { PaymentAPI as PaymentAPI7 } from "@flopay/js";
|
|
6648
7373
|
import { FloPayError as FloPayError8, resolveBillingApiUrl as resolveBillingApiUrl4, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme3, resolveTheme as resolveTheme3 } from "@flopay/shared";
|
|
6649
|
-
import { Fragment as Fragment6, jsx as
|
|
7374
|
+
import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
6650
7375
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
|
|
6651
7376
|
function sleep2(ms) {
|
|
6652
7377
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -6714,6 +7439,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
6714
7439
|
billingApiUrl,
|
|
6715
7440
|
locale,
|
|
6716
7441
|
theme,
|
|
7442
|
+
appearance,
|
|
6717
7443
|
buttonsTheme,
|
|
6718
7444
|
buttonsStyles: stylesOverride,
|
|
6719
7445
|
onSuccess,
|
|
@@ -6761,30 +7487,32 @@ function FloPayAutomaticPaymentButton({
|
|
|
6761
7487
|
const [overlayStatus, setOverlayStatus] = useState7(null);
|
|
6762
7488
|
const [overlayError, setOverlayError] = useState7(null);
|
|
6763
7489
|
const [fallbackSession, setFallbackSession] = useState7(null);
|
|
6764
|
-
const isMountedRef =
|
|
6765
|
-
const
|
|
6766
|
-
const
|
|
6767
|
-
const
|
|
6768
|
-
const
|
|
6769
|
-
|
|
7490
|
+
const isMountedRef = useRef7(true);
|
|
7491
|
+
const threeDsAbortRef = useRef7(null);
|
|
7492
|
+
const fallbackSessionRef = useRef7(fallbackSession);
|
|
7493
|
+
const onSuccessRef = useRef7(onSuccess);
|
|
7494
|
+
const onErrorRef = useRef7(onError);
|
|
7495
|
+
const onDeclineRef = useRef7(onDecline);
|
|
7496
|
+
useEffect9(() => {
|
|
6770
7497
|
fallbackSessionRef.current = fallbackSession;
|
|
6771
7498
|
}, [fallbackSession]);
|
|
6772
|
-
|
|
7499
|
+
useEffect9(() => {
|
|
6773
7500
|
onSuccessRef.current = onSuccess;
|
|
6774
7501
|
}, [onSuccess]);
|
|
6775
|
-
|
|
7502
|
+
useEffect9(() => {
|
|
6776
7503
|
onErrorRef.current = onError;
|
|
6777
7504
|
}, [onError]);
|
|
6778
|
-
|
|
7505
|
+
useEffect9(() => {
|
|
6779
7506
|
onDeclineRef.current = onDecline;
|
|
6780
7507
|
}, [onDecline]);
|
|
6781
|
-
|
|
7508
|
+
useEffect9(() => {
|
|
6782
7509
|
isMountedRef.current = true;
|
|
6783
7510
|
return () => {
|
|
6784
7511
|
isMountedRef.current = false;
|
|
7512
|
+
threeDsAbortRef.current?.abort();
|
|
6785
7513
|
};
|
|
6786
7514
|
}, []);
|
|
6787
|
-
|
|
7515
|
+
useEffect9(() => {
|
|
6788
7516
|
if (!fallbackSession || typeof window === "undefined") {
|
|
6789
7517
|
return;
|
|
6790
7518
|
}
|
|
@@ -6863,6 +7591,62 @@ function FloPayAutomaticPaymentButton({
|
|
|
6863
7591
|
return;
|
|
6864
7592
|
}
|
|
6865
7593
|
if (apiResult.autoProcessingError) {
|
|
7594
|
+
if (apiResult.autoProcessingError.type === "3ds_required" && apiResult.autoProcessingError.nextActionRedirectUrl && resolvedSessionId && effectiveNonce) {
|
|
7595
|
+
const threeDsAbort = new AbortController();
|
|
7596
|
+
threeDsAbortRef.current = threeDsAbort;
|
|
7597
|
+
let outcome;
|
|
7598
|
+
try {
|
|
7599
|
+
outcome = await runAutoCheckoutThreeDsChallenge({
|
|
7600
|
+
billingApiUrl: resolvedBillingUrl,
|
|
7601
|
+
sessionId: resolvedSessionId,
|
|
7602
|
+
nonce: effectiveNonce,
|
|
7603
|
+
nextActionRedirectUrl: apiResult.autoProcessingError.nextActionRedirectUrl,
|
|
7604
|
+
signal: threeDsAbort.signal
|
|
7605
|
+
});
|
|
7606
|
+
} finally {
|
|
7607
|
+
if (threeDsAbortRef.current === threeDsAbort) {
|
|
7608
|
+
threeDsAbortRef.current = null;
|
|
7609
|
+
}
|
|
7610
|
+
}
|
|
7611
|
+
if (outcome.status === "declined") {
|
|
7612
|
+
throw checkoutProcessErrorToFloPayError(
|
|
7613
|
+
{
|
|
7614
|
+
type: outcome.declineReason ?? "decline",
|
|
7615
|
+
message: "Card was declined.",
|
|
7616
|
+
gatewayErrorCode: outcome.gatewayDeclineReason ?? void 0
|
|
7617
|
+
},
|
|
7618
|
+
"Card was declined.",
|
|
7619
|
+
{
|
|
7620
|
+
checkoutMethod: apiResult.autoProcessingError.checkoutMethod
|
|
7621
|
+
}
|
|
7622
|
+
);
|
|
7623
|
+
}
|
|
7624
|
+
const api = new PaymentAPI7(resolvedBillingUrl);
|
|
7625
|
+
const completed = await api.waitForCheckoutSessionCompletion(resolvedSessionId, {
|
|
7626
|
+
initialDelayMs: 0,
|
|
7627
|
+
nonce: effectiveNonce
|
|
7628
|
+
});
|
|
7629
|
+
const completedSession = completed.data.session;
|
|
7630
|
+
if (!completedSession || completedSession.status !== "complete") {
|
|
7631
|
+
throw checkoutProcessErrorToFloPayError(
|
|
7632
|
+
{
|
|
7633
|
+
type: "unknown",
|
|
7634
|
+
message: "Card authentication was not completed."
|
|
7635
|
+
},
|
|
7636
|
+
"Card authentication was not completed.",
|
|
7637
|
+
{
|
|
7638
|
+
checkoutMethod: apiResult.autoProcessingError.checkoutMethod
|
|
7639
|
+
}
|
|
7640
|
+
);
|
|
7641
|
+
}
|
|
7642
|
+
await showSuccess({
|
|
7643
|
+
result: { status: "succeeded" },
|
|
7644
|
+
session: completedSession,
|
|
7645
|
+
sessionId: completedSession.id || resolvedSessionId,
|
|
7646
|
+
autoCompleted: false
|
|
7647
|
+
});
|
|
7648
|
+
return;
|
|
7649
|
+
}
|
|
6866
7650
|
throw checkoutProcessErrorToFloPayError(
|
|
6867
7651
|
apiResult.autoProcessingError,
|
|
6868
7652
|
"Automatic payment failed. Please try again.",
|
|
@@ -7030,9 +7814,26 @@ function FloPayAutomaticPaymentButton({
|
|
|
7030
7814
|
cardButton: { ...base.cardButton, ...stylesOverride.cardButton }
|
|
7031
7815
|
};
|
|
7032
7816
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
7817
|
+
const resolvedAppearance = useMemo5(() => {
|
|
7818
|
+
const bundleAppearance = themeBundle?.appearance;
|
|
7819
|
+
if (!appearance) return bundleAppearance;
|
|
7820
|
+
if (!bundleAppearance) return appearance;
|
|
7821
|
+
return {
|
|
7822
|
+
...bundleAppearance,
|
|
7823
|
+
...appearance,
|
|
7824
|
+
variables: {
|
|
7825
|
+
...bundleAppearance.variables,
|
|
7826
|
+
...appearance.variables
|
|
7827
|
+
}
|
|
7828
|
+
};
|
|
7829
|
+
}, [appearance, themeBundle]);
|
|
7830
|
+
const resolvedAppearanceVars = resolvedAppearance?.variables;
|
|
7831
|
+
const resolvedPrimaryColor = resolvedAppearanceVars?.colorPrimary ?? "#4A49FF";
|
|
7832
|
+
const resolvedPrimaryHoverColor = resolvedAppearanceVars?.colorPrimaryHover ?? darkenHex(resolvedPrimaryColor, 0.12);
|
|
7833
|
+
const resolvedButtonBorderRadius = resolvedAppearanceVars?.borderRadius ?? "8px";
|
|
7033
7834
|
const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
7034
7835
|
return /* @__PURE__ */ jsxs8(Fragment6, { children: [
|
|
7035
|
-
/* @__PURE__ */
|
|
7836
|
+
/* @__PURE__ */ jsx11(
|
|
7036
7837
|
"button",
|
|
7037
7838
|
{
|
|
7038
7839
|
...buttonProps,
|
|
@@ -7048,14 +7849,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
7048
7849
|
// on top so the auto-pay button carries the *submit* button's
|
|
7049
7850
|
// background and text colours — making it visually identical to
|
|
7050
7851
|
// the "Confirm Payment" / "Pay with X" actions it stands in for.
|
|
7852
|
+
// `resolvedPrimaryColor` is the *merged* appearance value, so a
|
|
7853
|
+
// per-checkout `colorPrimary` override re-skins this button too.
|
|
7051
7854
|
// Inline `style` consumer override stays at the end so explicit
|
|
7052
7855
|
// per-button overrides still win.
|
|
7053
7856
|
...bStyles.cardButton,
|
|
7054
7857
|
...derivePrimaryTileStyle({
|
|
7055
7858
|
themeBundle,
|
|
7056
|
-
resolvedPrimaryColor
|
|
7057
|
-
resolvedBorderRadius:
|
|
7058
|
-
submitButtonStyle: bStyles.submitButton
|
|
7859
|
+
resolvedPrimaryColor,
|
|
7860
|
+
resolvedBorderRadius: resolvedButtonBorderRadius,
|
|
7861
|
+
submitButtonStyle: bStyles.submitButton,
|
|
7862
|
+
explicitPrimaryColor: resolvedAppearanceVars?.colorPrimary
|
|
7059
7863
|
}),
|
|
7060
7864
|
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
7061
7865
|
fontWeight: 600,
|
|
@@ -7064,11 +7868,23 @@ function FloPayAutomaticPaymentButton({
|
|
|
7064
7868
|
alignItems: "center",
|
|
7065
7869
|
justifyContent: "center",
|
|
7066
7870
|
gap: "0.625rem",
|
|
7067
|
-
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
7871
|
+
transition: "background-color 0.15s, border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
7068
7872
|
position: "relative",
|
|
7069
7873
|
opacity: disabled || isProcessing ? 0.6 : 1,
|
|
7070
7874
|
...style
|
|
7071
7875
|
},
|
|
7876
|
+
onMouseEnter: (e) => {
|
|
7877
|
+
buttonProps.onMouseEnter?.(e);
|
|
7878
|
+
if (!e.defaultPrevented && !disabled && !isProcessing && (themeBundle || resolvedAppearanceVars?.colorPrimary)) {
|
|
7879
|
+
e.currentTarget.style.backgroundColor = resolvedPrimaryHoverColor;
|
|
7880
|
+
}
|
|
7881
|
+
},
|
|
7882
|
+
onMouseLeave: (e) => {
|
|
7883
|
+
buttonProps.onMouseLeave?.(e);
|
|
7884
|
+
if (!e.defaultPrevented && (themeBundle || resolvedAppearanceVars?.colorPrimary)) {
|
|
7885
|
+
e.currentTarget.style.backgroundColor = resolvedPrimaryColor;
|
|
7886
|
+
}
|
|
7887
|
+
},
|
|
7072
7888
|
onMouseDown: (e) => {
|
|
7073
7889
|
buttonProps.onMouseDown?.(e);
|
|
7074
7890
|
if (!e.defaultPrevented) {
|
|
@@ -7081,17 +7897,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
7081
7897
|
e.currentTarget.style.transform = "scale(1)";
|
|
7082
7898
|
}
|
|
7083
7899
|
},
|
|
7084
|
-
children: /* @__PURE__ */
|
|
7900
|
+
children: /* @__PURE__ */ jsx11(CardButtonContentSlot, { content: children })
|
|
7085
7901
|
}
|
|
7086
7902
|
),
|
|
7087
|
-
overlayStatus && /* @__PURE__ */
|
|
7903
|
+
overlayStatus && /* @__PURE__ */ jsx11(
|
|
7088
7904
|
ProcessingOverlay,
|
|
7089
7905
|
{
|
|
7090
7906
|
status: overlayStatus,
|
|
7091
7907
|
errorMessage: overlayError
|
|
7092
7908
|
}
|
|
7093
7909
|
),
|
|
7094
|
-
fallbackSession && /* @__PURE__ */
|
|
7910
|
+
fallbackSession && /* @__PURE__ */ jsx11(
|
|
7095
7911
|
"div",
|
|
7096
7912
|
{
|
|
7097
7913
|
"data-testid": "flopay-automatic-payment-fallback",
|
|
@@ -7112,7 +7928,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
7112
7928
|
padding: "1.5rem",
|
|
7113
7929
|
zIndex: 1100
|
|
7114
7930
|
},
|
|
7115
|
-
children: /* @__PURE__ */
|
|
7931
|
+
children: /* @__PURE__ */ jsx11(
|
|
7116
7932
|
"div",
|
|
7117
7933
|
{
|
|
7118
7934
|
style: {
|
|
@@ -7128,7 +7944,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
7128
7944
|
flexDirection: "column",
|
|
7129
7945
|
gap: "1rem"
|
|
7130
7946
|
},
|
|
7131
|
-
children: /* @__PURE__ */
|
|
7947
|
+
children: /* @__PURE__ */ jsx11(
|
|
7132
7948
|
FloPayCheckout,
|
|
7133
7949
|
{
|
|
7134
7950
|
sessionId: fallbackSession.sessionId,
|
|
@@ -7137,6 +7953,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
7137
7953
|
billingApiUrl: resolvedBillingUrl,
|
|
7138
7954
|
locale,
|
|
7139
7955
|
theme,
|
|
7956
|
+
...resolvedAppearance ? { appearance: resolvedAppearance } : {},
|
|
7140
7957
|
buttonsTheme,
|
|
7141
7958
|
buttonsStyles: stylesOverride,
|
|
7142
7959
|
initialErrorMessage: fallbackSession.errorMessage,
|
|
@@ -7166,6 +7983,7 @@ export {
|
|
|
7166
7983
|
PayPalButton,
|
|
7167
7984
|
PaymentElement,
|
|
7168
7985
|
SplitCardForm,
|
|
7986
|
+
VaultCardFields,
|
|
7169
7987
|
useCheckout,
|
|
7170
7988
|
useElements,
|
|
7171
7989
|
useFloPay,
|