@flopay/react 1.4.1 → 1.4.2
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 +93 -165
- package/dist/index.cjs +1131 -1653
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -180
- package/dist/index.d.ts +71 -180
- package/dist/index.mjs +919 -1434
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -193,7 +193,7 @@ function FloPayProvider({
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/flopay-checkout.tsx
|
|
196
|
-
import
|
|
196
|
+
import React8, { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
|
|
197
197
|
import { PaymentAPI as PaymentAPI4 } from "@flopay/js";
|
|
198
198
|
import { SDK_VERSION as SDK_VERSION2, FloPayError as FloPayError5, resolveBillingApiUrl as resolveBillingApiUrl3, buildCheckoutDisplayData, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme2, resolveTheme as resolveTheme2 } from "@flopay/shared";
|
|
199
199
|
|
|
@@ -264,73 +264,10 @@ function TitleContentSlot({
|
|
|
264
264
|
return /* @__PURE__ */ jsx2(Fragment, { children: content === void 0 ? /* @__PURE__ */ jsx2(DefaultTitleContent, {}) : content });
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
-
// src/elements.tsx
|
|
268
|
-
import { useEffect as useEffect2, useRef as useRef2, useContext } from "react";
|
|
269
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
270
|
-
function createElementComponent(elementType, displayName) {
|
|
271
|
-
function ElementComponent({
|
|
272
|
-
className,
|
|
273
|
-
id,
|
|
274
|
-
style,
|
|
275
|
-
options,
|
|
276
|
-
onChange,
|
|
277
|
-
onReady,
|
|
278
|
-
onFocus,
|
|
279
|
-
onBlur,
|
|
280
|
-
onEscape
|
|
281
|
-
}) {
|
|
282
|
-
const containerRef = useRef2(null);
|
|
283
|
-
const elementRef = useRef2(null);
|
|
284
|
-
const { elements, reportInteractive } = useContext(FloPayContext);
|
|
285
|
-
useEffect2(() => {
|
|
286
|
-
if (!elements || !containerRef.current) return;
|
|
287
|
-
let mounted = true;
|
|
288
|
-
(async () => {
|
|
289
|
-
let element = elements.getElement(elementType);
|
|
290
|
-
if (!element) {
|
|
291
|
-
element = await elements.create(elementType, options);
|
|
292
|
-
}
|
|
293
|
-
if (!mounted || !containerRef.current) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
element.mount(containerRef.current);
|
|
297
|
-
elementRef.current = element;
|
|
298
|
-
if (onChange) element.on("change", onChange);
|
|
299
|
-
element.on("ready", () => {
|
|
300
|
-
reportInteractive?.();
|
|
301
|
-
onReady?.();
|
|
302
|
-
});
|
|
303
|
-
if (onFocus) element.on("focus", onFocus);
|
|
304
|
-
if (onBlur) element.on("blur", onBlur);
|
|
305
|
-
if (onEscape) element.on("escape", onEscape);
|
|
306
|
-
})();
|
|
307
|
-
return () => {
|
|
308
|
-
mounted = false;
|
|
309
|
-
if (elementRef.current) {
|
|
310
|
-
try {
|
|
311
|
-
elementRef.current.unmount();
|
|
312
|
-
} catch {
|
|
313
|
-
}
|
|
314
|
-
elementRef.current = null;
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
}, [elements, reportInteractive]);
|
|
318
|
-
return /* @__PURE__ */ jsx3("div", { ref: containerRef, className, id, style });
|
|
319
|
-
}
|
|
320
|
-
ElementComponent.displayName = displayName;
|
|
321
|
-
return ElementComponent;
|
|
322
|
-
}
|
|
323
|
-
var PaymentElement = createElementComponent("payment", "PaymentElement");
|
|
324
|
-
var CardElement = createElementComponent("card", "CardElement");
|
|
325
|
-
var CardNumberElement = createElementComponent("cardNumber", "CardNumberElement");
|
|
326
|
-
var CardExpiryElement = createElementComponent("cardExpiry", "CardExpiryElement");
|
|
327
|
-
var CardCvcElement = createElementComponent("cardCvc", "CardCvcElement");
|
|
328
|
-
var AddressElement = createElementComponent("address", "AddressElement");
|
|
329
|
-
|
|
330
267
|
// src/split-card-form.tsx
|
|
331
268
|
import {
|
|
332
269
|
ExpressCheckoutElement,
|
|
333
|
-
PaymentElement
|
|
270
|
+
PaymentElement,
|
|
334
271
|
Elements as StripeElements,
|
|
335
272
|
useElements as useStripeElements,
|
|
336
273
|
useStripe as useStripeRaw
|
|
@@ -358,8 +295,8 @@ import {
|
|
|
358
295
|
import { PaymentAPI as PaymentAPI2 } from "@flopay/js";
|
|
359
296
|
|
|
360
297
|
// src/vault-card-fields.tsx
|
|
361
|
-
import { useEffect as
|
|
362
|
-
import { jsx as
|
|
298
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
299
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
363
300
|
function VaultCardFields({
|
|
364
301
|
capture,
|
|
365
302
|
html,
|
|
@@ -371,16 +308,16 @@ function VaultCardFields({
|
|
|
371
308
|
onError,
|
|
372
309
|
onValidation
|
|
373
310
|
}) {
|
|
374
|
-
const containerRef =
|
|
375
|
-
const onReadyRef =
|
|
376
|
-
const onErrorRef =
|
|
377
|
-
const onValidationRef =
|
|
311
|
+
const containerRef = useRef2(null);
|
|
312
|
+
const onReadyRef = useRef2(onReady);
|
|
313
|
+
const onErrorRef = useRef2(onError);
|
|
314
|
+
const onValidationRef = useRef2(onValidation);
|
|
378
315
|
onReadyRef.current = onReady;
|
|
379
316
|
onErrorRef.current = onError;
|
|
380
317
|
onValidationRef.current = onValidation;
|
|
381
|
-
const themeRef =
|
|
318
|
+
const themeRef = useRef2(theme);
|
|
382
319
|
themeRef.current = theme;
|
|
383
|
-
|
|
320
|
+
useEffect2(() => {
|
|
384
321
|
const el = containerRef.current;
|
|
385
322
|
if (!el) return;
|
|
386
323
|
let active = true;
|
|
@@ -422,15 +359,15 @@ function VaultCardFields({
|
|
|
422
359
|
capture.unmount();
|
|
423
360
|
};
|
|
424
361
|
}, [capture, html, messageToken, expectedOrigin]);
|
|
425
|
-
|
|
362
|
+
useEffect2(() => {
|
|
426
363
|
if (theme) capture.applyTheme?.(theme);
|
|
427
364
|
}, [capture, theme]);
|
|
428
|
-
return /* @__PURE__ */
|
|
365
|
+
return /* @__PURE__ */ jsx3("div", { ref: containerRef, "data-testid": "flopay-vault-card-fields", style: containerStyle });
|
|
429
366
|
}
|
|
430
367
|
|
|
431
368
|
// src/error-banner.tsx
|
|
432
369
|
import "react";
|
|
433
|
-
import { jsx as
|
|
370
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
434
371
|
function ErrorBanner({
|
|
435
372
|
children,
|
|
436
373
|
margin,
|
|
@@ -455,7 +392,7 @@ function ErrorBanner({
|
|
|
455
392
|
...styleOverride ?? {}
|
|
456
393
|
},
|
|
457
394
|
children: [
|
|
458
|
-
icon && /* @__PURE__ */
|
|
395
|
+
icon && /* @__PURE__ */ jsx4("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx4(
|
|
459
396
|
"path",
|
|
460
397
|
{
|
|
461
398
|
d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z",
|
|
@@ -486,41 +423,41 @@ var PAYMENT_METHOD_LOGO_URLS = {
|
|
|
486
423
|
};
|
|
487
424
|
|
|
488
425
|
// src/split-card-form.tsx
|
|
489
|
-
import
|
|
426
|
+
import React7, { useCallback as useCallback3, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState3 } from "react";
|
|
490
427
|
|
|
491
428
|
// src/hooks.ts
|
|
492
|
-
import { useContext
|
|
429
|
+
import { useContext } from "react";
|
|
493
430
|
import { resolveBillingApiUrl as resolveBillingApiUrl2 } from "@flopay/shared";
|
|
494
431
|
function useFloPay() {
|
|
495
|
-
const ctx =
|
|
432
|
+
const ctx = useContext(FloPayContext);
|
|
496
433
|
return ctx.flopay;
|
|
497
434
|
}
|
|
498
435
|
function usePayPalFloPay() {
|
|
499
|
-
const ctx =
|
|
436
|
+
const ctx = useContext(FloPayContext);
|
|
500
437
|
return ctx.paypalFlopay ?? null;
|
|
501
438
|
}
|
|
502
439
|
function useElements() {
|
|
503
|
-
const ctx =
|
|
440
|
+
const ctx = useContext(FloPayContext);
|
|
504
441
|
return ctx.elements;
|
|
505
442
|
}
|
|
506
443
|
function useCheckout() {
|
|
507
|
-
return
|
|
444
|
+
return useContext(CheckoutContext);
|
|
508
445
|
}
|
|
509
446
|
function useBillingApiUrl() {
|
|
510
|
-
const ctx =
|
|
447
|
+
const ctx = useContext(FloPayContext);
|
|
511
448
|
return ctx.billingApiUrl || resolveBillingApiUrl2();
|
|
512
449
|
}
|
|
513
450
|
|
|
514
451
|
// src/processing-overlay.tsx
|
|
515
452
|
import "react";
|
|
516
|
-
import { jsx as
|
|
453
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
517
454
|
var PROCESSING_OVERLAY_SUCCESS_DELAY_MS = 1200;
|
|
518
455
|
var PROCESSING_OVERLAY_ERROR_DELAY_MS = 1500;
|
|
519
456
|
function ProcessingOverlay({
|
|
520
457
|
status,
|
|
521
458
|
errorMessage
|
|
522
459
|
}) {
|
|
523
|
-
return /* @__PURE__ */
|
|
460
|
+
return /* @__PURE__ */ jsx5(
|
|
524
461
|
"div",
|
|
525
462
|
{
|
|
526
463
|
"data-testid": "flopay-processing-overlay",
|
|
@@ -564,14 +501,14 @@ function ProcessingOverlay({
|
|
|
564
501
|
xmlns: "http://www.w3.org/2000/svg",
|
|
565
502
|
style: { animation: "flopay-spin 0.8s linear infinite" },
|
|
566
503
|
children: [
|
|
567
|
-
/* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
504
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "10", stroke: "#e5e7eb", strokeWidth: "3" }),
|
|
505
|
+
/* @__PURE__ */ jsx5("path", { d: "M4 12a8 8 0 018-8v3a5 5 0 00-5 5H4z", fill: "#4A49FF" })
|
|
569
506
|
]
|
|
570
507
|
}
|
|
571
508
|
),
|
|
572
|
-
status === "success" && /* @__PURE__ */
|
|
573
|
-
/* @__PURE__ */
|
|
574
|
-
/* @__PURE__ */
|
|
509
|
+
status === "success" && /* @__PURE__ */ jsx5("div", { style: { animation: "flopay-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)" }, children: /* @__PURE__ */ jsxs3("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
510
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "11", fill: "#22c55e" }),
|
|
511
|
+
/* @__PURE__ */ jsx5(
|
|
575
512
|
"path",
|
|
576
513
|
{
|
|
577
514
|
d: "M7 12.5l3 3 7-7",
|
|
@@ -587,9 +524,9 @@ function ProcessingOverlay({
|
|
|
587
524
|
}
|
|
588
525
|
)
|
|
589
526
|
] }) }),
|
|
590
|
-
status === "error" && /* @__PURE__ */
|
|
591
|
-
/* @__PURE__ */
|
|
592
|
-
/* @__PURE__ */
|
|
527
|
+
status === "error" && /* @__PURE__ */ jsx5("div", { style: { animation: "flopay-shake 0.4s ease" }, children: /* @__PURE__ */ jsxs3("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
528
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "11", fill: "#ef4444" }),
|
|
529
|
+
/* @__PURE__ */ jsx5(
|
|
593
530
|
"path",
|
|
594
531
|
{
|
|
595
532
|
d: "M8 8l8 8M16 8l-8 8",
|
|
@@ -621,7 +558,7 @@ function ProcessingOverlay({
|
|
|
621
558
|
]
|
|
622
559
|
}
|
|
623
560
|
),
|
|
624
|
-
status === "success" && /* @__PURE__ */
|
|
561
|
+
status === "success" && /* @__PURE__ */ jsx5(
|
|
625
562
|
"p",
|
|
626
563
|
{
|
|
627
564
|
style: {
|
|
@@ -635,7 +572,7 @@ function ProcessingOverlay({
|
|
|
635
572
|
children: "You will be automatically redirected, do not close or navigate away from this window."
|
|
636
573
|
}
|
|
637
574
|
),
|
|
638
|
-
status === "error" && errorMessage && /* @__PURE__ */
|
|
575
|
+
status === "error" && errorMessage && /* @__PURE__ */ jsx5(
|
|
639
576
|
"p",
|
|
640
577
|
{
|
|
641
578
|
style: {
|
|
@@ -649,7 +586,7 @@ function ProcessingOverlay({
|
|
|
649
586
|
children: errorMessage
|
|
650
587
|
}
|
|
651
588
|
),
|
|
652
|
-
/* @__PURE__ */
|
|
589
|
+
/* @__PURE__ */ jsx5("style", { children: `
|
|
653
590
|
@keyframes flopay-spin { to { transform: rotate(360deg); } }
|
|
654
591
|
@keyframes flopay-pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
|
|
655
592
|
@keyframes flopay-draw { to { stroke-dashoffset: 0; } }
|
|
@@ -774,13 +711,6 @@ function buildDeclineEvent(method, input, overrides) {
|
|
|
774
711
|
...declineCode ? { declineCode } : {}
|
|
775
712
|
};
|
|
776
713
|
}
|
|
777
|
-
function isRecord(value) {
|
|
778
|
-
return typeof value === "object" && value !== null;
|
|
779
|
-
}
|
|
780
|
-
function readString(payload, key) {
|
|
781
|
-
const value = payload?.[key];
|
|
782
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
783
|
-
}
|
|
784
714
|
var FRIENDLY_MESSAGE_OVERRIDES = [
|
|
785
715
|
{
|
|
786
716
|
match: /^paypal authorization required\.?$/i,
|
|
@@ -796,26 +726,6 @@ function applyFriendlyMessageOverride(message) {
|
|
|
796
726
|
}
|
|
797
727
|
return message;
|
|
798
728
|
}
|
|
799
|
-
function buildFloPayApiError(payload, fallbackMessage) {
|
|
800
|
-
const nestedError = isRecord(payload?.error) ? payload.error : null;
|
|
801
|
-
const rawMessage = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
|
|
802
|
-
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
803
|
-
const code = readString(payload, "code") ?? readString(payload, "gatewayErrorCode") ?? readString(nestedError, "code");
|
|
804
|
-
const declineCode = readString(payload, "declineCode") ?? readString(payload, "gatewayDeclineReason") ?? readString(payload, "decline_code") ?? readString(nestedError, "decline_code");
|
|
805
|
-
return new FloPayError(message, "api_error", {
|
|
806
|
-
...code ? { code } : {},
|
|
807
|
-
...declineCode ? { declineCode } : {}
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
async function buildFloPayApiErrorFromResponse(response, fallbackMessage) {
|
|
811
|
-
const payload = await response.json().catch(() => null);
|
|
812
|
-
return buildFloPayApiError(payload, fallbackMessage);
|
|
813
|
-
}
|
|
814
|
-
function intentRequestHeaders(nonce) {
|
|
815
|
-
const headers = { "Content-Type": "application/json" };
|
|
816
|
-
if (nonce) headers["x-checkout-session-token"] = nonce;
|
|
817
|
-
return headers;
|
|
818
|
-
}
|
|
819
729
|
function isSuccessfulPaymentIntentStatus(status) {
|
|
820
730
|
return status === "succeeded" || status === "requires_capture" || status === "processing";
|
|
821
731
|
}
|
|
@@ -828,41 +738,6 @@ function mapPayPalIntentStatusToPaymentResult(status) {
|
|
|
828
738
|
}
|
|
829
739
|
return "failed";
|
|
830
740
|
}
|
|
831
|
-
function resolvePaymentIntentPaymentMethodId(paymentIntent) {
|
|
832
|
-
const paymentMethod = paymentIntent?.payment_method;
|
|
833
|
-
if (typeof paymentMethod === "string" && paymentMethod.startsWith("pm_")) {
|
|
834
|
-
return paymentMethod;
|
|
835
|
-
}
|
|
836
|
-
if (paymentMethod && typeof paymentMethod === "object" && typeof paymentMethod.id === "string") {
|
|
837
|
-
return paymentMethod.id;
|
|
838
|
-
}
|
|
839
|
-
return void 0;
|
|
840
|
-
}
|
|
841
|
-
async function retrievePaymentIntentFromProvider(provider, clientSecret) {
|
|
842
|
-
const retriever = provider;
|
|
843
|
-
if (isSetupIntentClientSecret(clientSecret)) {
|
|
844
|
-
if (!retriever?.retrieveSetupIntent) {
|
|
845
|
-
return null;
|
|
846
|
-
}
|
|
847
|
-
const { setupIntent, error: error2 } = await retriever.retrieveSetupIntent(clientSecret);
|
|
848
|
-
if (error2) {
|
|
849
|
-
throw new FloPayError(error2.message ?? "Failed to retrieve setup intent.", "api_error", {
|
|
850
|
-
...error2.code ? { code: error2.code } : {}
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
return setupIntent ?? null;
|
|
854
|
-
}
|
|
855
|
-
if (!retriever?.retrievePaymentIntent) {
|
|
856
|
-
return null;
|
|
857
|
-
}
|
|
858
|
-
const { paymentIntent, error } = await retriever.retrievePaymentIntent(clientSecret);
|
|
859
|
-
if (error) {
|
|
860
|
-
throw new FloPayError(error.message ?? "Failed to retrieve payment intent.", "api_error", {
|
|
861
|
-
...error.code ? { code: error.code } : {}
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
return paymentIntent ?? null;
|
|
865
|
-
}
|
|
866
741
|
function resolveWalletElementsMode(amountInMinorUnits) {
|
|
867
742
|
if (typeof amountInMinorUnits !== "number" || !Number.isFinite(amountInMinorUnits) || amountInMinorUnits <= 0) {
|
|
868
743
|
return { mode: "setup" };
|
|
@@ -931,10 +806,15 @@ function isInAppBrowser(userAgent) {
|
|
|
931
806
|
}
|
|
932
807
|
|
|
933
808
|
// src/direct-paypal-button.tsx
|
|
934
|
-
import { useCallback as useCallback2, useEffect as
|
|
809
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState2 } from "react";
|
|
935
810
|
import { loadScript } from "@paypal/paypal-js";
|
|
936
811
|
import { PaymentAPI } from "@flopay/js";
|
|
937
|
-
import {
|
|
812
|
+
import {
|
|
813
|
+
FloPayError as FloPayError2,
|
|
814
|
+
SDK_VERSION,
|
|
815
|
+
generateIdempotencyKey,
|
|
816
|
+
normalizeGatewayEnvironment
|
|
817
|
+
} from "@flopay/shared";
|
|
938
818
|
|
|
939
819
|
// src/merchant-callback.ts
|
|
940
820
|
function invokeMerchantCallback(callback) {
|
|
@@ -986,8 +866,14 @@ function isPopupBlockedError(err) {
|
|
|
986
866
|
}
|
|
987
867
|
|
|
988
868
|
// src/direct-paypal-button.tsx
|
|
989
|
-
import { jsx as
|
|
869
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
990
870
|
var DEFAULT_BUTTON_HEIGHT = 45;
|
|
871
|
+
var PAYPAL_INIT_RETRY_DELAY_MS = 1e3;
|
|
872
|
+
var PAYPAL_RENDER_WATCHDOG_MS = 11e3;
|
|
873
|
+
var PAYPAL_INIT_ACKNOWLEDGEMENT_HOSTS = [
|
|
874
|
+
"https://www.paypal.com",
|
|
875
|
+
"https://www.sandbox.paypal.com"
|
|
876
|
+
];
|
|
991
877
|
var DIRECT_PAYPAL_RECOVERY_MESSAGE = "We couldn't open PayPal. Try again or choose another payment method.";
|
|
992
878
|
var DIRECT_PAYPAL_RECOVERY_ACTION_STYLE = {
|
|
993
879
|
width: "100%",
|
|
@@ -1002,6 +888,9 @@ var DIRECT_PAYPAL_RECOVERY_ACTION_STYLE = {
|
|
|
1002
888
|
fontWeight: 700,
|
|
1003
889
|
cursor: "pointer"
|
|
1004
890
|
};
|
|
891
|
+
function isPayPalInitAcknowledgementTimeout(message) {
|
|
892
|
+
return message.includes("No ack for postMessage init()") && PAYPAL_INIT_ACKNOWLEDGEMENT_HOSTS.some((host) => message.includes(host)) && message.includes("10000ms");
|
|
893
|
+
}
|
|
1005
894
|
function buildDirectPayPalRecoveryMessage(popupBlocked) {
|
|
1006
895
|
return popupBlocked ? `${DIRECT_PAYPAL_RECOVERY_MESSAGE} Allow pop-ups for this site, then try again.` : DIRECT_PAYPAL_RECOVERY_MESSAGE;
|
|
1007
896
|
}
|
|
@@ -1021,6 +910,8 @@ function DirectPayPalButtonImplementation({
|
|
|
1021
910
|
onTechnicalFailure,
|
|
1022
911
|
isProcessing = false,
|
|
1023
912
|
onLoadStateChange,
|
|
913
|
+
onInitializationStateChange,
|
|
914
|
+
allowAutomaticRetry = true,
|
|
1024
915
|
onButtonClick,
|
|
1025
916
|
runBeforeButtonClick,
|
|
1026
917
|
session,
|
|
@@ -1049,7 +940,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1049
940
|
telemetryContext?.layout
|
|
1050
941
|
]);
|
|
1051
942
|
const floPayTelemetry = useMemo2(() => getFloPayTelemetryBridge(flopay), [flopay]);
|
|
1052
|
-
|
|
943
|
+
useEffect3(() => () => {
|
|
1053
944
|
if (!standaloneTelemetry) return;
|
|
1054
945
|
void standaloneTelemetry.flush().catch(() => {
|
|
1055
946
|
}).finally(() => standaloneTelemetry.destroy());
|
|
@@ -1074,76 +965,104 @@ function DirectPayPalButtonImplementation({
|
|
|
1074
965
|
startTiming: () => floPayTelemetry?.now() ?? standaloneTelemetry?.now() ?? 0,
|
|
1075
966
|
elapsed: (startedAt) => floPayTelemetry?.elapsed(startedAt) ?? Math.max(0, (standaloneTelemetry?.now() ?? startedAt) - startedAt)
|
|
1076
967
|
}), [floPayTelemetry, standaloneTelemetry]);
|
|
1077
|
-
const containerRef =
|
|
1078
|
-
const providerStartedAt =
|
|
1079
|
-
const focusTargetRef =
|
|
1080
|
-
const pendingProviderFocusRef =
|
|
968
|
+
const containerRef = useRef3(null);
|
|
969
|
+
const providerStartedAt = useRef3(0);
|
|
970
|
+
const focusTargetRef = useRef3(null);
|
|
971
|
+
const pendingProviderFocusRef = useRef3(false);
|
|
1081
972
|
const [ready, setReady] = useState2(false);
|
|
973
|
+
const [recovering, setRecovering] = useState2(false);
|
|
1082
974
|
const [renderGeneration, setRenderGeneration] = useState2(0);
|
|
1083
|
-
const activeRenderGenerationRef =
|
|
975
|
+
const activeRenderGenerationRef = useRef3(0);
|
|
1084
976
|
const [showRetryFocusTarget, setShowRetryFocusTarget] = useState2(false);
|
|
977
|
+
const automaticRetryUsedRef = useRef3(false);
|
|
978
|
+
const initializationFailureLoggedRef = useRef3(false);
|
|
1085
979
|
const [failed, setFailed] = useState2(false);
|
|
1086
980
|
const [submitting, setSubmitting] = useState2(false);
|
|
1087
981
|
const baseUrl = useMemo2(() => billingApiUrl.replace(/\/+$/, ""), [billingApiUrl]);
|
|
982
|
+
const initializationConfigKey = useMemo2(
|
|
983
|
+
() => JSON.stringify([
|
|
984
|
+
baseUrl,
|
|
985
|
+
clientId,
|
|
986
|
+
currency,
|
|
987
|
+
environment ?? "",
|
|
988
|
+
isSubscription,
|
|
989
|
+
sessionId,
|
|
990
|
+
existingOrderId ?? ""
|
|
991
|
+
]),
|
|
992
|
+
[baseUrl, clientId, currency, environment, existingOrderId, isSubscription, sessionId]
|
|
993
|
+
);
|
|
994
|
+
const initializationConfigKeyRef = useRef3(initializationConfigKey);
|
|
995
|
+
const initializationConfigChanged = initializationConfigKeyRef.current !== initializationConfigKey;
|
|
1088
996
|
const [debugLines, setDebugLines] = useState2([]);
|
|
1089
997
|
const appendDebug = (line) => {
|
|
1090
998
|
if (!debug) return;
|
|
1091
999
|
setDebugLines((prev) => [...prev, `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 23)} ${line}`]);
|
|
1092
1000
|
};
|
|
1093
|
-
const onTokenizedBodyRef =
|
|
1094
|
-
const onCompleteRef =
|
|
1095
|
-
const onErrorChangeRef =
|
|
1096
|
-
const onDeclineRef =
|
|
1097
|
-
const onTechnicalFailureRef =
|
|
1098
|
-
const onButtonClickRef =
|
|
1099
|
-
const onLoadStateChangeRef =
|
|
1100
|
-
const
|
|
1101
|
-
const
|
|
1102
|
-
const
|
|
1103
|
-
const
|
|
1104
|
-
const
|
|
1105
|
-
const
|
|
1106
|
-
const
|
|
1107
|
-
const
|
|
1108
|
-
const
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1001
|
+
const onTokenizedBodyRef = useRef3(onTokenizedBody);
|
|
1002
|
+
const onCompleteRef = useRef3(onComplete);
|
|
1003
|
+
const onErrorChangeRef = useRef3(onErrorChange);
|
|
1004
|
+
const onDeclineRef = useRef3(onDecline);
|
|
1005
|
+
const onTechnicalFailureRef = useRef3(onTechnicalFailure);
|
|
1006
|
+
const onButtonClickRef = useRef3(onButtonClick);
|
|
1007
|
+
const onLoadStateChangeRef = useRef3(onLoadStateChange);
|
|
1008
|
+
const onInitializationStateChangeRef = useRef3(onInitializationStateChange);
|
|
1009
|
+
const runBeforeButtonClickRef = useRef3(runBeforeButtonClick);
|
|
1010
|
+
const sessionRef = useRef3(session);
|
|
1011
|
+
const emailRef = useRef3(email);
|
|
1012
|
+
const nonceRef = useRef3(nonce);
|
|
1013
|
+
const beforeClickRef = useRef3(null);
|
|
1014
|
+
const attemptGenerationRef = useRef3(0);
|
|
1015
|
+
const attemptRef = useRef3(null);
|
|
1016
|
+
const invalidatedAttemptGenerationRef = useRef3(null);
|
|
1017
|
+
const attemptContextBySurfaceRef = useRef3(/* @__PURE__ */ new Map());
|
|
1018
|
+
const approvalContextByTokenRef = useRef3(/* @__PURE__ */ new Map());
|
|
1019
|
+
const componentMountedRef = useRef3(false);
|
|
1020
|
+
useEffect3(() => {
|
|
1021
|
+
componentMountedRef.current = true;
|
|
1022
|
+
return () => {
|
|
1023
|
+
componentMountedRef.current = false;
|
|
1024
|
+
};
|
|
1025
|
+
}, []);
|
|
1026
|
+
useEffect3(() => {
|
|
1111
1027
|
onTokenizedBodyRef.current = onTokenizedBody;
|
|
1112
1028
|
}, [onTokenizedBody]);
|
|
1113
|
-
|
|
1029
|
+
useEffect3(() => {
|
|
1114
1030
|
onCompleteRef.current = onComplete;
|
|
1115
1031
|
}, [onComplete]);
|
|
1116
|
-
|
|
1032
|
+
useEffect3(() => {
|
|
1117
1033
|
onErrorChangeRef.current = onErrorChange;
|
|
1118
1034
|
}, [onErrorChange]);
|
|
1119
|
-
|
|
1035
|
+
useEffect3(() => {
|
|
1120
1036
|
onDeclineRef.current = onDecline;
|
|
1121
1037
|
}, [onDecline]);
|
|
1122
|
-
|
|
1038
|
+
useEffect3(() => {
|
|
1123
1039
|
onTechnicalFailureRef.current = onTechnicalFailure;
|
|
1124
1040
|
}, [onTechnicalFailure]);
|
|
1125
|
-
|
|
1041
|
+
useEffect3(() => {
|
|
1126
1042
|
onButtonClickRef.current = onButtonClick;
|
|
1127
1043
|
}, [onButtonClick]);
|
|
1128
|
-
|
|
1044
|
+
useEffect3(() => {
|
|
1129
1045
|
onLoadStateChangeRef.current = onLoadStateChange;
|
|
1130
1046
|
}, [onLoadStateChange]);
|
|
1131
|
-
|
|
1047
|
+
useEffect3(() => {
|
|
1048
|
+
onInitializationStateChangeRef.current = onInitializationStateChange;
|
|
1049
|
+
}, [onInitializationStateChange]);
|
|
1050
|
+
useEffect3(() => {
|
|
1132
1051
|
runBeforeButtonClickRef.current = runBeforeButtonClick;
|
|
1133
1052
|
}, [runBeforeButtonClick]);
|
|
1134
|
-
|
|
1053
|
+
useEffect3(() => {
|
|
1135
1054
|
sessionRef.current = session;
|
|
1136
1055
|
}, [session]);
|
|
1137
|
-
|
|
1056
|
+
useEffect3(() => {
|
|
1138
1057
|
emailRef.current = email;
|
|
1139
1058
|
}, [email]);
|
|
1140
|
-
|
|
1059
|
+
useEffect3(() => {
|
|
1141
1060
|
nonceRef.current = nonce;
|
|
1142
1061
|
}, [nonce]);
|
|
1143
|
-
|
|
1062
|
+
useEffect3(() => {
|
|
1144
1063
|
activeRenderGenerationRef.current = renderGeneration;
|
|
1145
1064
|
}, [renderGeneration]);
|
|
1146
|
-
|
|
1065
|
+
useEffect3(() => {
|
|
1147
1066
|
if (showRetryFocusTarget) focusTargetRef.current?.focus();
|
|
1148
1067
|
}, [showRetryFocusTarget, renderGeneration]);
|
|
1149
1068
|
const focusRetryTarget = useCallback2(() => {
|
|
@@ -1162,7 +1081,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1162
1081
|
);
|
|
1163
1082
|
(target ?? containerRef.current)?.focus?.();
|
|
1164
1083
|
}, []);
|
|
1165
|
-
|
|
1084
|
+
useEffect3(() => {
|
|
1166
1085
|
if (!ready || !pendingProviderFocusRef.current) return;
|
|
1167
1086
|
pendingProviderFocusRef.current = false;
|
|
1168
1087
|
focusPayPalSurface();
|
|
@@ -1245,7 +1164,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1245
1164
|
}
|
|
1246
1165
|
return token;
|
|
1247
1166
|
};
|
|
1248
|
-
|
|
1167
|
+
useEffect3(() => {
|
|
1249
1168
|
const handleVisibilityChange = () => {
|
|
1250
1169
|
if (document.visibilityState === "visible") {
|
|
1251
1170
|
scheduleMissingCallbackRecovery();
|
|
@@ -1263,11 +1182,21 @@ function DirectPayPalButtonImplementation({
|
|
|
1263
1182
|
clearAttemptTimer();
|
|
1264
1183
|
};
|
|
1265
1184
|
}, []);
|
|
1266
|
-
|
|
1185
|
+
useEffect3(() => {
|
|
1186
|
+
if (initializationConfigKeyRef.current === initializationConfigKey) return;
|
|
1187
|
+
initializationConfigKeyRef.current = initializationConfigKey;
|
|
1188
|
+
automaticRetryUsedRef.current = false;
|
|
1189
|
+
initializationFailureLoggedRef.current = false;
|
|
1190
|
+
setReady(false);
|
|
1191
|
+
setRecovering(false);
|
|
1192
|
+
setFailed(false);
|
|
1193
|
+
onInitializationStateChangeRef.current?.("loading");
|
|
1194
|
+
}, [initializationConfigKey]);
|
|
1195
|
+
useEffect3(() => {
|
|
1267
1196
|
invokeMerchantCallback(() => onLoadStateChangeRef.current?.(ready && !failed));
|
|
1268
1197
|
}, [ready, failed]);
|
|
1269
1198
|
const normalizedEnv = normalizeGatewayEnvironment(environment);
|
|
1270
|
-
|
|
1199
|
+
useEffect3(() => {
|
|
1271
1200
|
const maskedClient = clientId ? `${clientId.slice(0, 6)}\u2026(len ${clientId.length})` : "(empty)";
|
|
1272
1201
|
const ua = typeof navigator !== "undefined" ? navigator.userAgent : "(no navigator)";
|
|
1273
1202
|
appendDebug(`mount clientId=${maskedClient} env=${environment ?? "(unset)"}\u2192${normalizedEnv ?? "live"} ccy=${currency} sub=${isSubscription}`);
|
|
@@ -1297,7 +1226,29 @@ function DirectPayPalButtonImplementation({
|
|
|
1297
1226
|
paymentMethodCategory: "paypal"
|
|
1298
1227
|
});
|
|
1299
1228
|
let cancelled = false;
|
|
1300
|
-
let
|
|
1229
|
+
let superseded = false;
|
|
1230
|
+
const isInactive = () => cancelled || superseded;
|
|
1231
|
+
let paypalIntentIdempotencyKey;
|
|
1232
|
+
let paypalIntentAttemptActive = false;
|
|
1233
|
+
const beginPaypalIntentAttempt = () => {
|
|
1234
|
+
paypalIntentIdempotencyKey = generateIdempotencyKey();
|
|
1235
|
+
if (!paypalIntentIdempotencyKey) {
|
|
1236
|
+
console.warn(
|
|
1237
|
+
"[FloPay] DirectPayPal: secure idempotency key unavailable; retries may not be deduplicated."
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
paypalIntentAttemptActive = true;
|
|
1241
|
+
};
|
|
1242
|
+
let retryTimer = null;
|
|
1243
|
+
let preRenderFailureHandled = false;
|
|
1244
|
+
let ownedButtons = null;
|
|
1245
|
+
let ownedButtonsClosed = false;
|
|
1246
|
+
const closeOwnedButtons = () => {
|
|
1247
|
+
if (!ownedButtons || ownedButtonsClosed) return;
|
|
1248
|
+
ownedButtonsClosed = true;
|
|
1249
|
+
ownedButtons.close().catch(() => {
|
|
1250
|
+
});
|
|
1251
|
+
};
|
|
1301
1252
|
let overlayStartedAt = null;
|
|
1302
1253
|
const finishOverlay = () => {
|
|
1303
1254
|
if (overlayStartedAt === null) return;
|
|
@@ -1367,6 +1318,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1367
1318
|
};
|
|
1368
1319
|
const errorMessages = [];
|
|
1369
1320
|
const onWindowError = (ev) => {
|
|
1321
|
+
if (isInactive()) return;
|
|
1370
1322
|
const msg = ev.message ?? String(ev.error ?? "(no message)");
|
|
1371
1323
|
if (msg && (msg.toLowerCase().includes("paypal") || msg.toLowerCase().includes("zoid") || msg.toLowerCase().includes("postrobot") || msg.toLowerCase().includes("storage"))) {
|
|
1372
1324
|
appendDebug(`window:error ${msg.slice(0, 140)}`);
|
|
@@ -1374,6 +1326,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1374
1326
|
}
|
|
1375
1327
|
};
|
|
1376
1328
|
const onUnhandledRejection = (ev) => {
|
|
1329
|
+
if (isInactive()) return;
|
|
1377
1330
|
const reason = ev.reason instanceof Error ? ev.reason.message : String(ev.reason ?? "(no reason)");
|
|
1378
1331
|
if (reason && (reason.toLowerCase().includes("paypal") || reason.toLowerCase().includes("zoid") || reason.toLowerCase().includes("postrobot") || reason.toLowerCase().includes("storage"))) {
|
|
1379
1332
|
appendDebug(`window:rejection ${reason.slice(0, 140)}`);
|
|
@@ -1388,6 +1341,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1388
1341
|
if (debug && typeof PerformanceObserver !== "undefined") {
|
|
1389
1342
|
try {
|
|
1390
1343
|
perfObserver = new PerformanceObserver((list) => {
|
|
1344
|
+
if (isInactive()) return;
|
|
1391
1345
|
for (const entry of list.getEntries()) {
|
|
1392
1346
|
if (!entry.name.toLowerCase().includes("paypal")) continue;
|
|
1393
1347
|
paypalRequestCount.value += 1;
|
|
@@ -1416,17 +1370,13 @@ function DirectPayPalButtonImplementation({
|
|
|
1416
1370
|
return lower.includes("zoid destroyed") || lower.includes("destroyed all components") || lower.includes("window closed") || lower.includes("detected container element removed");
|
|
1417
1371
|
};
|
|
1418
1372
|
const forwardError = (message) => {
|
|
1419
|
-
if (
|
|
1373
|
+
if (isInactive()) return;
|
|
1420
1374
|
if (isZoidLifecycleMessage(message)) return;
|
|
1421
1375
|
const friendly = applyFriendlyMessageOverride(message) ?? message;
|
|
1422
1376
|
invokeMerchantCallback(() => onErrorChangeRef.current?.(friendly));
|
|
1423
1377
|
};
|
|
1424
1378
|
const markRenderFailed = (message) => {
|
|
1425
1379
|
if (cancelled) return;
|
|
1426
|
-
if (isZoidLifecycleMessage(message)) {
|
|
1427
|
-
appendDebug(`markRenderFailed:skip-zoid msg=${message.slice(0, 80)}`);
|
|
1428
|
-
return;
|
|
1429
|
-
}
|
|
1430
1380
|
setFailed(true);
|
|
1431
1381
|
if (!message.includes("paypal_ineligible")) {
|
|
1432
1382
|
telemetrySource.error({
|
|
@@ -1439,8 +1389,48 @@ function DirectPayPalButtonImplementation({
|
|
|
1439
1389
|
}
|
|
1440
1390
|
console.error("[FloPay] DirectPayPal load/render failure:", message);
|
|
1441
1391
|
};
|
|
1392
|
+
const handlePreRenderFailure = (message, retryable = false) => {
|
|
1393
|
+
if (cancelled) return;
|
|
1394
|
+
const isRecoveryAttempt = automaticRetryUsedRef.current || !allowAutomaticRetry;
|
|
1395
|
+
if (preRenderFailureHandled) return;
|
|
1396
|
+
preRenderFailureHandled = true;
|
|
1397
|
+
superseded = true;
|
|
1398
|
+
stopDiagnostics();
|
|
1399
|
+
closeOwnedButtons();
|
|
1400
|
+
const isRetryableInitializationFailure = retryable || isPayPalInitAcknowledgementTimeout(message);
|
|
1401
|
+
if (isRetryableInitializationFailure && allowAutomaticRetry && !automaticRetryUsedRef.current) {
|
|
1402
|
+
automaticRetryUsedRef.current = true;
|
|
1403
|
+
setReady(false);
|
|
1404
|
+
setSubmitting(false);
|
|
1405
|
+
setRecovering(true);
|
|
1406
|
+
onInitializationStateChangeRef.current?.("retrying");
|
|
1407
|
+
retryTimer = setTimeout(() => {
|
|
1408
|
+
if (cancelled) return;
|
|
1409
|
+
setRenderGeneration((generation) => generation + 1);
|
|
1410
|
+
}, PAYPAL_INIT_RETRY_DELAY_MS);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (isRetryableInitializationFailure || isRecoveryAttempt) {
|
|
1414
|
+
setReady(false);
|
|
1415
|
+
setSubmitting(false);
|
|
1416
|
+
setRecovering(false);
|
|
1417
|
+
setFailed(true);
|
|
1418
|
+
onInitializationStateChangeRef.current?.("exhausted");
|
|
1419
|
+
if (!initializationFailureLoggedRef.current) {
|
|
1420
|
+
initializationFailureLoggedRef.current = true;
|
|
1421
|
+
const failureCode = isPayPalInitAcknowledgementTimeout(message) ? "paypal_init_timeout" : retryable ? "paypal_render_timeout" : "paypal_init_failure";
|
|
1422
|
+
console.error(
|
|
1423
|
+
"[FloPay] Direct PayPal initialization failed:",
|
|
1424
|
+
failureCode
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
markRenderFailed(message);
|
|
1430
|
+
};
|
|
1442
1431
|
setFailed(false);
|
|
1443
1432
|
const dispatchTokenizedBody = async (body, prepared = beforeClickRef.current) => {
|
|
1433
|
+
if (isInactive()) return;
|
|
1444
1434
|
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
1445
1435
|
if (onTokenizedBodyRef.current) {
|
|
1446
1436
|
await onTokenizedBodyRef.current(body, {
|
|
@@ -1494,41 +1484,45 @@ function DirectPayPalButtonImplementation({
|
|
|
1494
1484
|
}
|
|
1495
1485
|
);
|
|
1496
1486
|
if (response.ok) {
|
|
1487
|
+
if (superseded || cancelled && componentMountedRef.current) return;
|
|
1497
1488
|
finishProcessing();
|
|
1498
1489
|
telemetrySource.terminal({
|
|
1499
1490
|
outcome: "payment_succeeded",
|
|
1500
1491
|
provider: "paypal",
|
|
1501
1492
|
paymentMethodCategory: "paypal"
|
|
1502
1493
|
});
|
|
1503
|
-
|
|
1504
|
-
const json = await response.json().catch(() => null);
|
|
1505
|
-
const rawMessage = json?.["message"] ?? "PayPal payment failed.";
|
|
1506
|
-
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
1507
|
-
finishProcessing();
|
|
1508
|
-
if (typeof json?.["declineCode"] === "string") {
|
|
1509
|
-
telemetrySource.terminal({
|
|
1510
|
-
outcome: "payment_declined",
|
|
1511
|
-
provider: "paypal",
|
|
1512
|
-
paymentMethodCategory: "paypal"
|
|
1513
|
-
});
|
|
1514
|
-
} else {
|
|
1515
|
-
telemetrySource.error({
|
|
1516
|
-
errorCode: "PAYMENT_PROCESSING_FAILED",
|
|
1517
|
-
stage: "processing",
|
|
1518
|
-
provider: "paypal",
|
|
1519
|
-
paymentMethodCategory: "paypal",
|
|
1520
|
-
requestCategory: "process_payment",
|
|
1521
|
-
statusClass: response.status >= 500 ? "5xx" : response.status >= 400 ? "4xx" : response.status >= 300 ? "3xx" : "unknown"
|
|
1522
|
-
});
|
|
1523
|
-
}
|
|
1524
|
-
forwardError(message);
|
|
1525
|
-
invokeMerchantCallback(() => onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
|
|
1526
|
-
code: json?.["code"],
|
|
1527
|
-
declineCode: json?.["declineCode"]
|
|
1528
|
-
})));
|
|
1494
|
+
invokeMerchantCallback(() => onCompleteRef.current?.({ status: "succeeded", checkoutMethod: "paypal" }));
|
|
1529
1495
|
return;
|
|
1530
1496
|
}
|
|
1497
|
+
if (isInactive()) return;
|
|
1498
|
+
const json = await response.json().catch(() => null);
|
|
1499
|
+
const rawMessage = json?.["message"] ?? "PayPal payment failed.";
|
|
1500
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
1501
|
+
finishProcessing();
|
|
1502
|
+
if (typeof json?.["declineCode"] === "string") {
|
|
1503
|
+
telemetrySource.terminal({
|
|
1504
|
+
outcome: "payment_declined",
|
|
1505
|
+
provider: "paypal",
|
|
1506
|
+
paymentMethodCategory: "paypal"
|
|
1507
|
+
});
|
|
1508
|
+
} else {
|
|
1509
|
+
telemetrySource.error({
|
|
1510
|
+
errorCode: "PAYMENT_PROCESSING_FAILED",
|
|
1511
|
+
stage: "processing",
|
|
1512
|
+
provider: "paypal",
|
|
1513
|
+
paymentMethodCategory: "paypal",
|
|
1514
|
+
requestCategory: "process_payment",
|
|
1515
|
+
statusClass: response.status >= 500 ? "5xx" : response.status >= 400 ? "4xx" : response.status >= 300 ? "3xx" : "unknown"
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
forwardError(message);
|
|
1519
|
+
invokeMerchantCallback(() => onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
|
|
1520
|
+
code: json?.["code"],
|
|
1521
|
+
declineCode: json?.["declineCode"]
|
|
1522
|
+
})));
|
|
1523
|
+
return;
|
|
1531
1524
|
} catch (err) {
|
|
1525
|
+
if (isInactive()) return;
|
|
1532
1526
|
finishProcessing();
|
|
1533
1527
|
telemetrySource.error({
|
|
1534
1528
|
errorCode: "NETWORK_REQUEST_FAILED",
|
|
@@ -1544,14 +1538,21 @@ function DirectPayPalButtonImplementation({
|
|
|
1544
1538
|
invokeMerchantCallback(() => onDeclineRef.current?.(buildDeclineEvent("paypal", message)));
|
|
1545
1539
|
return;
|
|
1546
1540
|
}
|
|
1547
|
-
invokeMerchantCallback(() => onCompleteRef.current?.({ status: "succeeded", checkoutMethod: "paypal" }));
|
|
1548
1541
|
};
|
|
1542
|
+
const supersededRenderError = () => new FloPayError2(
|
|
1543
|
+
"PayPal render was superseded.",
|
|
1544
|
+
"api_error",
|
|
1545
|
+
{ code: "paypal_render_superseded" }
|
|
1546
|
+
);
|
|
1547
|
+
const resolveExistingOrder = (orderId) => isInactive() ? Promise.reject(supersededRenderError()) : Promise.resolve(orderId);
|
|
1549
1548
|
const createPaypalIntent = async (fallbackMessage) => {
|
|
1549
|
+
if (isInactive()) {
|
|
1550
|
+
throw supersededRenderError();
|
|
1551
|
+
}
|
|
1552
|
+
if (!paypalIntentAttemptActive) beginPaypalIntentAttempt();
|
|
1550
1553
|
const prepared = beforeClickRef.current;
|
|
1551
1554
|
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
1552
|
-
const effectiveEmail = prepared?.accountPatch?.email ?? emailRef.current;
|
|
1553
1555
|
const currentNonce = prepared?.nonce ?? nonceRef.current;
|
|
1554
|
-
const intentHeaders = intentRequestHeaders(currentNonce);
|
|
1555
1556
|
telemetrySource.log({
|
|
1556
1557
|
name: "payment.intent.started",
|
|
1557
1558
|
stage: "processing",
|
|
@@ -1559,22 +1560,22 @@ function DirectPayPalButtonImplementation({
|
|
|
1559
1560
|
paymentMethodCategory: "paypal",
|
|
1560
1561
|
requestCategory: "intent_create"
|
|
1561
1562
|
});
|
|
1562
|
-
const
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1563
|
+
const intent = await new PaymentAPI(baseUrl, { telemetry: false }).createSessionIntent(
|
|
1564
|
+
effectiveSessionId,
|
|
1565
|
+
currentNonce ?? "",
|
|
1566
|
+
{
|
|
1567
|
+
provider: "paypal",
|
|
1568
|
+
paymentMethodCategory: "wallet",
|
|
1568
1569
|
paymentMethodType: "paypal",
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1570
|
+
paymentMethodId: null,
|
|
1571
|
+
intentKind: isSubscription ? "subscription" : "order"
|
|
1572
|
+
},
|
|
1573
|
+
{ idempotencyKey: paypalIntentIdempotencyKey }
|
|
1574
|
+
);
|
|
1575
|
+
if (isInactive()) {
|
|
1576
|
+
throw supersededRenderError();
|
|
1575
1577
|
}
|
|
1576
|
-
|
|
1577
|
-
if (!id) {
|
|
1578
|
+
if (intent.provider !== "paypal") {
|
|
1578
1579
|
throw new Error(fallbackMessage);
|
|
1579
1580
|
}
|
|
1580
1581
|
telemetrySource.log({
|
|
@@ -1585,7 +1586,24 @@ function DirectPayPalButtonImplementation({
|
|
|
1585
1586
|
requestCategory: "intent_create",
|
|
1586
1587
|
statusClass: "2xx"
|
|
1587
1588
|
});
|
|
1588
|
-
return
|
|
1589
|
+
return intent.providerObjectId;
|
|
1590
|
+
};
|
|
1591
|
+
const reportPayPalDecline = (error, context) => {
|
|
1592
|
+
const currentNonce = context?.nonce ?? nonceRef.current;
|
|
1593
|
+
if (!currentNonce) return;
|
|
1594
|
+
const effectiveSessionId = context?.sessionId ?? sessionId;
|
|
1595
|
+
const providerDeclineReason = getProviderDeclineCode(error) ?? getProviderErrorCode(error) ?? "provider_declined";
|
|
1596
|
+
void new PaymentAPI(baseUrl, { telemetry: false }).reportSessionIntentDecline(
|
|
1597
|
+
effectiveSessionId,
|
|
1598
|
+
currentNonce,
|
|
1599
|
+
{
|
|
1600
|
+
provider: "paypal",
|
|
1601
|
+
paymentMethodCategory: "wallet",
|
|
1602
|
+
paymentMethodType: "paypal",
|
|
1603
|
+
providerDeclineReason
|
|
1604
|
+
}
|
|
1605
|
+
).catch(() => {
|
|
1606
|
+
});
|
|
1589
1607
|
};
|
|
1590
1608
|
const effectRenderGeneration = renderGeneration;
|
|
1591
1609
|
appendDebug("loadScript:scheduled (deferred 1 tick)");
|
|
@@ -1614,9 +1632,11 @@ function DirectPayPalButtonImplementation({
|
|
|
1614
1632
|
...paypalSdkEnv === "sandbox" ? { dataNamespace: "paypal_sandbox" } : {}
|
|
1615
1633
|
});
|
|
1616
1634
|
loadPromise.then((paypal) => {
|
|
1617
|
-
appendDebug(`loadScript:resolved
|
|
1618
|
-
if (
|
|
1619
|
-
|
|
1635
|
+
appendDebug(`loadScript:resolved inactive=${isInactive()} ns=${!!paypal} buttons=${!!paypal?.Buttons}`);
|
|
1636
|
+
if (isInactive()) return;
|
|
1637
|
+
if (!paypal?.Buttons) {
|
|
1638
|
+
appendDebug("FAIL: namespace missing Buttons factory");
|
|
1639
|
+
handlePreRenderFailure("PayPal SDK did not expose the Buttons factory.");
|
|
1620
1640
|
return;
|
|
1621
1641
|
}
|
|
1622
1642
|
telemetrySource.log({
|
|
@@ -1626,7 +1646,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1626
1646
|
paymentMethodCategory: "paypal"
|
|
1627
1647
|
});
|
|
1628
1648
|
const handleApprove = async (data) => {
|
|
1629
|
-
if (
|
|
1649
|
+
if (isInactive() || activeRenderGenerationRef.current !== effectRenderGeneration) return;
|
|
1630
1650
|
const token = data.subscriptionID ?? data.orderID ?? "";
|
|
1631
1651
|
const context = token ? approvalContextByTokenRef.current.get(token) : attemptContextBySurfaceRef.current.get(effectRenderGeneration);
|
|
1632
1652
|
if (!context || !isAttemptActive(context.generation)) return;
|
|
@@ -1651,7 +1671,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1651
1671
|
} catch (err) {
|
|
1652
1672
|
forwardError(err instanceof Error ? err.message : "PayPal capture failed.");
|
|
1653
1673
|
} finally {
|
|
1654
|
-
setSubmitting(false);
|
|
1674
|
+
if (!isInactive()) setSubmitting(false);
|
|
1655
1675
|
}
|
|
1656
1676
|
};
|
|
1657
1677
|
const buttons = paypal.Buttons({
|
|
@@ -1662,11 +1682,20 @@ function DirectPayPalButtonImplementation({
|
|
|
1662
1682
|
// inline-session/account patches land before the order is created,
|
|
1663
1683
|
// matching the Stripe-rendered PayPal flow.
|
|
1664
1684
|
onClick: async (_data, actions) => {
|
|
1685
|
+
if (isInactive()) {
|
|
1686
|
+
await actions.reject();
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
beginPaypalIntentAttempt();
|
|
1665
1690
|
const runner = runBeforeButtonClickRef.current;
|
|
1666
1691
|
let prepared = {};
|
|
1667
1692
|
if (runner) {
|
|
1668
1693
|
try {
|
|
1669
1694
|
const beforeClick = await runner("paypal");
|
|
1695
|
+
if (isInactive()) {
|
|
1696
|
+
await actions.reject();
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1670
1699
|
if (!beforeClick.proceed) {
|
|
1671
1700
|
beforeClickRef.current = null;
|
|
1672
1701
|
attemptContextBySurfaceRef.current.delete(effectRenderGeneration);
|
|
@@ -1720,10 +1749,11 @@ function DirectPayPalButtonImplementation({
|
|
|
1720
1749
|
// prior backend round-trip (the `paypal_direct_required` retry
|
|
1721
1750
|
// path), feed it straight to PayPal instead of creating a new one.
|
|
1722
1751
|
// Otherwise fall back to the normal create-intent call.
|
|
1723
|
-
createOrder: isSubscription ? void 0 : existingOrderId ? () =>
|
|
1724
|
-
createSubscription: isSubscription ? existingOrderId ? () =>
|
|
1752
|
+
createOrder: isSubscription ? void 0 : existingOrderId ? () => resolveExistingOrder(existingOrderId).then(registerApprovalContext) : () => createPaypalIntent("Failed to create PayPal order.").then(registerApprovalContext),
|
|
1753
|
+
createSubscription: isSubscription ? existingOrderId ? () => resolveExistingOrder(existingOrderId).then(registerApprovalContext) : () => createPaypalIntent("Failed to create PayPal subscription.").then(registerApprovalContext) : void 0,
|
|
1725
1754
|
onApprove: handleApprove,
|
|
1726
1755
|
onCancel: () => {
|
|
1756
|
+
if (isInactive()) return;
|
|
1727
1757
|
const context = attemptContextBySurfaceRef.current.get(effectRenderGeneration) ?? beforeClickRef.current;
|
|
1728
1758
|
if (context) attemptContextBySurfaceRef.current.delete(context.surfaceKey);
|
|
1729
1759
|
beforeClickRef.current = null;
|
|
@@ -1737,7 +1767,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1737
1767
|
invalidateAttempt({ generation: context?.generation, remount: true, focus: false });
|
|
1738
1768
|
},
|
|
1739
1769
|
onError: (err) => {
|
|
1740
|
-
if (
|
|
1770
|
+
if (isInactive() || activeRenderGenerationRef.current !== effectRenderGeneration) return;
|
|
1741
1771
|
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1742
1772
|
appendDebug(`onError rendered=${rendered} msg=${message.slice(0, 120)}`);
|
|
1743
1773
|
if (rendered) {
|
|
@@ -1757,13 +1787,16 @@ function DirectPayPalButtonImplementation({
|
|
|
1757
1787
|
paymentMethodCategory: "paypal",
|
|
1758
1788
|
requestCategory: "provider_sdk"
|
|
1759
1789
|
});
|
|
1790
|
+
if (isProviderDecline(err)) {
|
|
1791
|
+
reportPayPalDecline(err, context);
|
|
1792
|
+
}
|
|
1760
1793
|
if (context) attemptContextBySurfaceRef.current.delete(context.surfaceKey);
|
|
1761
1794
|
beforeClickRef.current = null;
|
|
1762
1795
|
invalidateAttempt({ generation: context?.generation, remount: true, showRetry: true, focus: true });
|
|
1763
1796
|
notifyTechnicalFailure(err, { code: "paypal_runtime_failed" });
|
|
1764
1797
|
return;
|
|
1765
1798
|
}
|
|
1766
|
-
|
|
1799
|
+
handlePreRenderFailure(message);
|
|
1767
1800
|
}
|
|
1768
1801
|
});
|
|
1769
1802
|
const eligible = buttons.isEligible();
|
|
@@ -1776,17 +1809,19 @@ function DirectPayPalButtonImplementation({
|
|
|
1776
1809
|
});
|
|
1777
1810
|
if (!eligible) {
|
|
1778
1811
|
setReady(false);
|
|
1779
|
-
|
|
1812
|
+
handlePreRenderFailure(
|
|
1780
1813
|
"PayPal buttons are not eligible to render in this context (paypal_ineligible)."
|
|
1781
1814
|
);
|
|
1782
1815
|
return;
|
|
1783
1816
|
}
|
|
1784
1817
|
const typedButtons = buttons;
|
|
1818
|
+
ownedButtons = typedButtons;
|
|
1785
1819
|
if (debug) {
|
|
1786
1820
|
appendDebug(`container:dims ${formatDims(container)} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"}`);
|
|
1787
1821
|
}
|
|
1788
1822
|
if (debug && typeof MutationObserver !== "undefined") {
|
|
1789
1823
|
containerObserver = new MutationObserver((mutations) => {
|
|
1824
|
+
if (isInactive()) return;
|
|
1790
1825
|
for (const mutation of mutations) {
|
|
1791
1826
|
if (mutation.type === "childList") {
|
|
1792
1827
|
mutation.addedNodes.forEach((node) => {
|
|
@@ -1814,7 +1849,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1814
1849
|
});
|
|
1815
1850
|
}
|
|
1816
1851
|
const snapshotContainer = (when) => {
|
|
1817
|
-
if (
|
|
1852
|
+
if (isInactive() || rendered) return;
|
|
1818
1853
|
const iframes = container.querySelectorAll("iframe");
|
|
1819
1854
|
const hasStorageAccess = typeof document !== "undefined" && "hasStorageAccess" in document;
|
|
1820
1855
|
appendDebug(`watchdog:${when} container=${formatDims(container)} children=${container.childElementCount} iframes=${iframes.length} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"} cookies=${typeof navigator !== "undefined" ? navigator.cookieEnabled : "?"} hasStorageAccessApi=${hasStorageAccess} paypalNetRequests=${paypalRequestCount.value}`);
|
|
@@ -1834,17 +1869,25 @@ function DirectPayPalButtonImplementation({
|
|
|
1834
1869
|
watchdogTimers.push(setTimeout(() => snapshotContainer("15s"), 15e3));
|
|
1835
1870
|
}
|
|
1836
1871
|
appendDebug("render:start");
|
|
1872
|
+
watchdogTimers.push(setTimeout(() => {
|
|
1873
|
+
if (isInactive() || rendered) return;
|
|
1874
|
+
appendDebug("watchdog:11s retryable render timeout");
|
|
1875
|
+
handlePreRenderFailure(
|
|
1876
|
+
"PayPal Buttons render did not settle within 11000ms.",
|
|
1877
|
+
true
|
|
1878
|
+
);
|
|
1879
|
+
}, PAYPAL_RENDER_WATCHDOG_MS));
|
|
1837
1880
|
buttons.render(container).then(() => {
|
|
1838
|
-
appendDebug(`render:resolved
|
|
1881
|
+
appendDebug(`render:resolved inactive=${isInactive()}`);
|
|
1839
1882
|
stopDiagnostics();
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
});
|
|
1883
|
+
if (isInactive()) {
|
|
1884
|
+
closeOwnedButtons();
|
|
1843
1885
|
return;
|
|
1844
1886
|
}
|
|
1845
|
-
activeButtons = typedButtons;
|
|
1846
1887
|
rendered = true;
|
|
1847
1888
|
setReady(true);
|
|
1889
|
+
setRecovering(false);
|
|
1890
|
+
onInitializationStateChangeRef.current?.("ready");
|
|
1848
1891
|
telemetrySource.log({
|
|
1849
1892
|
name: "provider.ready",
|
|
1850
1893
|
stage: "provider_ready",
|
|
@@ -1862,24 +1905,22 @@ function DirectPayPalButtonImplementation({
|
|
|
1862
1905
|
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1863
1906
|
appendDebug(`render:rejected msg=${message.slice(0, 120)}`);
|
|
1864
1907
|
stopDiagnostics();
|
|
1865
|
-
|
|
1908
|
+
handlePreRenderFailure(message);
|
|
1866
1909
|
});
|
|
1867
1910
|
}).catch((err) => {
|
|
1868
1911
|
const message = err instanceof Error ? err.message : "PayPal SDK failed to load.";
|
|
1869
1912
|
appendDebug(`loadScript:rejected msg=${message.slice(0, 120)}`);
|
|
1870
|
-
|
|
1913
|
+
handlePreRenderFailure(message);
|
|
1871
1914
|
});
|
|
1872
1915
|
}, 0);
|
|
1873
1916
|
return () => {
|
|
1874
1917
|
cancelled = true;
|
|
1875
1918
|
clearTimeout(startTimer);
|
|
1919
|
+
if (retryTimer) clearTimeout(retryTimer);
|
|
1876
1920
|
stopDiagnostics();
|
|
1877
|
-
|
|
1878
|
-
activeButtons.close().catch(() => {
|
|
1879
|
-
});
|
|
1880
|
-
}
|
|
1921
|
+
closeOwnedButtons();
|
|
1881
1922
|
};
|
|
1882
|
-
}, [baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId, renderGeneration, telemetrySource]);
|
|
1923
|
+
}, [allowAutomaticRetry, baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId, renderGeneration, telemetrySource]);
|
|
1883
1924
|
const debugPanel = debug ? /* @__PURE__ */ jsxs4(
|
|
1884
1925
|
"pre",
|
|
1885
1926
|
{
|
|
@@ -1904,8 +1945,8 @@ ${debugLines.join("\n")}`
|
|
|
1904
1945
|
]
|
|
1905
1946
|
}
|
|
1906
1947
|
) : null;
|
|
1907
|
-
if (failed) {
|
|
1908
|
-
return debug ? /* @__PURE__ */
|
|
1948
|
+
if (failed && !initializationConfigChanged) {
|
|
1949
|
+
return debug ? /* @__PURE__ */ jsx6("div", { children: debugPanel }) : null;
|
|
1909
1950
|
}
|
|
1910
1951
|
return (
|
|
1911
1952
|
// Single wrapper so the parent flex container sees exactly one flex item
|
|
@@ -1914,39 +1955,52 @@ ${debugLines.join("\n")}`
|
|
|
1914
1955
|
// intentionally has no margin/padding so the parent owns all spacing.
|
|
1915
1956
|
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1916
1957
|
debugPanel,
|
|
1917
|
-
/* @__PURE__ */ jsxs4(
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1958
|
+
/* @__PURE__ */ jsxs4(
|
|
1959
|
+
"div",
|
|
1960
|
+
{
|
|
1961
|
+
"aria-hidden": recovering ? true : void 0,
|
|
1962
|
+
style: recovering ? {
|
|
1963
|
+
position: "relative",
|
|
1964
|
+
height: 0,
|
|
1965
|
+
opacity: 0,
|
|
1966
|
+
pointerEvents: "none"
|
|
1967
|
+
} : { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT },
|
|
1968
|
+
children: [
|
|
1969
|
+
!ready && !recovering && /* @__PURE__ */ jsx6(
|
|
1970
|
+
"div",
|
|
1971
|
+
{
|
|
1972
|
+
"data-testid": "flopay-direct-paypal-placeholder",
|
|
1973
|
+
style: {
|
|
1974
|
+
position: "absolute",
|
|
1975
|
+
inset: 0,
|
|
1976
|
+
borderRadius: 8,
|
|
1977
|
+
background: "#e5e7eb",
|
|
1978
|
+
animation: "flopay-pulse 1.5s ease-in-out infinite",
|
|
1979
|
+
pointerEvents: "none"
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
),
|
|
1983
|
+
/* @__PURE__ */ jsx6(
|
|
1984
|
+
"div",
|
|
1985
|
+
{
|
|
1986
|
+
ref: containerRef,
|
|
1987
|
+
"data-testid": "flopay-direct-paypal-container",
|
|
1988
|
+
tabIndex: -1,
|
|
1989
|
+
"aria-label": "PayPal payment method",
|
|
1990
|
+
style: {
|
|
1991
|
+
minHeight: DEFAULT_BUTTON_HEIGHT,
|
|
1992
|
+
display: "flex",
|
|
1993
|
+
opacity: ready ? 1 : 0
|
|
1994
|
+
},
|
|
1995
|
+
"aria-busy": submitting || isProcessing
|
|
1996
|
+
},
|
|
1997
|
+
renderGeneration
|
|
1998
|
+
)
|
|
1999
|
+
]
|
|
2000
|
+
},
|
|
2001
|
+
renderGeneration
|
|
2002
|
+
),
|
|
2003
|
+
showRetryFocusTarget && /* @__PURE__ */ jsx6(
|
|
1950
2004
|
"button",
|
|
1951
2005
|
{
|
|
1952
2006
|
ref: focusTargetRef,
|
|
@@ -1961,18 +2015,34 @@ ${debugLines.join("\n")}`
|
|
|
1961
2015
|
);
|
|
1962
2016
|
}
|
|
1963
2017
|
function DirectPayPalButton(props) {
|
|
1964
|
-
return /* @__PURE__ */
|
|
2018
|
+
return /* @__PURE__ */ jsx6(DirectPayPalButtonImplementation, { ...props });
|
|
1965
2019
|
}
|
|
1966
2020
|
function InstrumentedDirectPayPalButton(props) {
|
|
1967
|
-
return /* @__PURE__ */
|
|
2021
|
+
return /* @__PURE__ */ jsx6(DirectPayPalButtonImplementation, { ...props });
|
|
1968
2022
|
}
|
|
1969
2023
|
|
|
1970
2024
|
// src/split-card-form.tsx
|
|
1971
2025
|
import { FloPayError as FloPayError3, isSetupIntentClientSecret as isSetupIntentClientSecret2, resolveTheme } from "@flopay/shared";
|
|
1972
|
-
import { Fragment as Fragment2, jsx as
|
|
2026
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1973
2027
|
var STRIPE_RESUME_KEY = "flopay_stripe_resume";
|
|
1974
2028
|
var LEGACY_WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
1975
2029
|
var PAYPAL_RESUME_KEY = "flopay_paypal_resume";
|
|
2030
|
+
async function reportNonCardDecline({
|
|
2031
|
+
billingApiUrl,
|
|
2032
|
+
sessionId,
|
|
2033
|
+
nonce,
|
|
2034
|
+
request
|
|
2035
|
+
}) {
|
|
2036
|
+
if (!sessionId || !nonce) return;
|
|
2037
|
+
try {
|
|
2038
|
+
await new PaymentAPI2(billingApiUrl, { telemetry: false }).reportSessionIntentDecline(
|
|
2039
|
+
sessionId,
|
|
2040
|
+
nonce,
|
|
2041
|
+
request
|
|
2042
|
+
);
|
|
2043
|
+
} catch {
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
1976
2046
|
function isAccountValidationError(err) {
|
|
1977
2047
|
return err instanceof FloPayError3 && typeof err.statusCode === "number" && err.statusCode >= 400 && err.statusCode < 500;
|
|
1978
2048
|
}
|
|
@@ -2084,9 +2154,9 @@ function buildExternalMethodRecoveryMessage(method, popupBlocked) {
|
|
|
2084
2154
|
return popupBlocked ? `${base} Allow pop-ups for this site, then try again.` : base;
|
|
2085
2155
|
}
|
|
2086
2156
|
function useExternalAttemptReconciliation(onMissingTerminal) {
|
|
2087
|
-
const generationRef =
|
|
2088
|
-
const invalidatedGenerationRef =
|
|
2089
|
-
const attemptRef =
|
|
2157
|
+
const generationRef = useRef4(0);
|
|
2158
|
+
const invalidatedGenerationRef = useRef4(null);
|
|
2159
|
+
const attemptRef = useRef4(null);
|
|
2090
2160
|
const clearAttemptTimer = useCallback3((targetAttempt = attemptRef.current) => {
|
|
2091
2161
|
const attempt = targetAttempt;
|
|
2092
2162
|
if (attempt?.timer) {
|
|
@@ -2160,7 +2230,7 @@ function useExternalAttemptReconciliation(onMissingTerminal) {
|
|
|
2160
2230
|
attempt.yieldedControl = true;
|
|
2161
2231
|
clearAttemptTimer(attempt);
|
|
2162
2232
|
}, [clearAttemptTimer]);
|
|
2163
|
-
|
|
2233
|
+
useEffect4(() => {
|
|
2164
2234
|
const handleVisibilityChange = () => {
|
|
2165
2235
|
if (document.visibilityState === "visible") {
|
|
2166
2236
|
scheduleRecoveryIfReturned();
|
|
@@ -2202,7 +2272,7 @@ function normalizeBeforeButtonClickError(method, err) {
|
|
|
2202
2272
|
);
|
|
2203
2273
|
}
|
|
2204
2274
|
function FloPayKeyframes() {
|
|
2205
|
-
return /* @__PURE__ */
|
|
2275
|
+
return /* @__PURE__ */ jsx7("style", { children: FLOPAY_KEYFRAMES });
|
|
2206
2276
|
}
|
|
2207
2277
|
function toCssSize(value) {
|
|
2208
2278
|
if (typeof value === "number") return `${value}px`;
|
|
@@ -2225,7 +2295,7 @@ function ExpressCheckoutReadySwap({
|
|
|
2225
2295
|
}) {
|
|
2226
2296
|
if (state === "unavailable" || state === "load_error") return null;
|
|
2227
2297
|
return /* @__PURE__ */ jsxs5("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
2228
|
-
/* @__PURE__ */
|
|
2298
|
+
/* @__PURE__ */ jsx7(
|
|
2229
2299
|
"div",
|
|
2230
2300
|
{
|
|
2231
2301
|
"data-testid": placeholderTestId,
|
|
@@ -2244,7 +2314,7 @@ function ExpressCheckoutReadySwap({
|
|
|
2244
2314
|
}
|
|
2245
2315
|
}
|
|
2246
2316
|
),
|
|
2247
|
-
/* @__PURE__ */
|
|
2317
|
+
/* @__PURE__ */ jsx7(
|
|
2248
2318
|
"div",
|
|
2249
2319
|
{
|
|
2250
2320
|
style: {
|
|
@@ -2262,11 +2332,9 @@ function ExpressCheckoutReadySwap({
|
|
|
2262
2332
|
function isExpressCheckoutRowVisible(state) {
|
|
2263
2333
|
return state !== "unavailable" && state !== "load_error";
|
|
2264
2334
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
}
|
|
2269
|
-
);
|
|
2335
|
+
function SplitCardForm(props) {
|
|
2336
|
+
return /* @__PURE__ */ jsx7(SplitCardFormInner, { ...props });
|
|
2337
|
+
}
|
|
2270
2338
|
function PayPalButtonInner({
|
|
2271
2339
|
sessionId,
|
|
2272
2340
|
nonce,
|
|
@@ -2286,18 +2354,17 @@ function PayPalButtonInner({
|
|
|
2286
2354
|
const stripe = useStripeRaw();
|
|
2287
2355
|
const elements = useStripeElements();
|
|
2288
2356
|
const [loadState, setLoadState] = useState3("loading");
|
|
2289
|
-
|
|
2357
|
+
useEffect4(() => {
|
|
2290
2358
|
onLoadStateChange?.(loadState);
|
|
2291
2359
|
}, [loadState, onLoadStateChange]);
|
|
2292
2360
|
const [submitting, setSubmitting] = useState3(false);
|
|
2293
|
-
const paypalResumeAttempted =
|
|
2294
|
-
const focusTargetRef =
|
|
2295
|
-
const recoveryActionRef =
|
|
2361
|
+
const paypalResumeAttempted = useRef4(false);
|
|
2362
|
+
const focusTargetRef = useRef4(null);
|
|
2363
|
+
const recoveryActionRef = useRef4(null);
|
|
2296
2364
|
const [surfaceKey, setSurfaceKey] = useState3(0);
|
|
2297
2365
|
const [showRecoveryAction, setShowRecoveryAction] = useState3(false);
|
|
2298
|
-
const pendingProviderFocusRef =
|
|
2299
|
-
const attemptContextBySurfaceRef =
|
|
2300
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
2366
|
+
const pendingProviderFocusRef = useRef4(false);
|
|
2367
|
+
const attemptContextBySurfaceRef = useRef4(/* @__PURE__ */ new Map());
|
|
2301
2368
|
const {
|
|
2302
2369
|
startAttempt,
|
|
2303
2370
|
finishAttempt,
|
|
@@ -2312,7 +2379,7 @@ function PayPalButtonInner({
|
|
|
2312
2379
|
setShowRecoveryAction(true);
|
|
2313
2380
|
setSurfaceKey((key) => key + 1);
|
|
2314
2381
|
});
|
|
2315
|
-
|
|
2382
|
+
useEffect4(() => {
|
|
2316
2383
|
if (showRecoveryAction) recoveryActionRef.current?.focus();
|
|
2317
2384
|
}, [showRecoveryAction, surfaceKey]);
|
|
2318
2385
|
const resetSurface = useCallback3(() => {
|
|
@@ -2330,7 +2397,7 @@ function PayPalButtonInner({
|
|
|
2330
2397
|
(target ?? focusTargetRef.current)?.focus();
|
|
2331
2398
|
}, 0);
|
|
2332
2399
|
}, []);
|
|
2333
|
-
|
|
2400
|
+
useEffect4(() => {
|
|
2334
2401
|
if (!pendingProviderFocusRef.current) return;
|
|
2335
2402
|
pendingProviderFocusRef.current = false;
|
|
2336
2403
|
focusProviderSurface();
|
|
@@ -2340,7 +2407,7 @@ function PayPalButtonInner({
|
|
|
2340
2407
|
onErrorChange?.(null);
|
|
2341
2408
|
focusProviderSurface();
|
|
2342
2409
|
}, [focusProviderSurface, onErrorChange]);
|
|
2343
|
-
|
|
2410
|
+
useEffect4(() => {
|
|
2344
2411
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
2345
2412
|
const params = new URLSearchParams(window.location.search);
|
|
2346
2413
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -2468,32 +2535,21 @@ function PayPalButtonInner({
|
|
|
2468
2535
|
event.paymentFailed({ reason: "fail" });
|
|
2469
2536
|
return;
|
|
2470
2537
|
}
|
|
2471
|
-
const
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
if (!intentResponse.ok) {
|
|
2485
|
-
const intentError = await buildFloPayApiErrorFromResponse(
|
|
2486
|
-
intentResponse,
|
|
2487
|
-
"Failed to create payment intent"
|
|
2488
|
-
);
|
|
2489
|
-
onErrorChange?.(intentError.message);
|
|
2490
|
-
onDecline?.(buildDeclineEvent("paypal", intentError));
|
|
2491
|
-
event.paymentFailed({ reason: "fail", message: intentError.message });
|
|
2492
|
-
return;
|
|
2538
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
2539
|
+
effectiveSessionId,
|
|
2540
|
+
effectiveNonce ?? "",
|
|
2541
|
+
{
|
|
2542
|
+
provider: "stripe",
|
|
2543
|
+
paymentMethodCategory: "wallet",
|
|
2544
|
+
paymentMethodType: "paypal",
|
|
2545
|
+
paymentMethodId: paymentMethod?.id ?? null,
|
|
2546
|
+
intentKind: "payment"
|
|
2547
|
+
}
|
|
2548
|
+
);
|
|
2549
|
+
if (intent.provider !== "stripe") {
|
|
2550
|
+
throw new Error("Invalid provider returned for PayPal intent");
|
|
2493
2551
|
}
|
|
2494
|
-
const
|
|
2495
|
-
const intentClientSecret = intentJson.data?.id;
|
|
2496
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2552
|
+
const intentClientSecret = intent.clientSecret;
|
|
2497
2553
|
const confirmParams = {
|
|
2498
2554
|
return_url: window.location.href
|
|
2499
2555
|
};
|
|
@@ -2530,6 +2586,17 @@ function PayPalButtonInner({
|
|
|
2530
2586
|
code: getProviderErrorCode(confirmError),
|
|
2531
2587
|
declineCode: getProviderDeclineCode(confirmError)
|
|
2532
2588
|
}));
|
|
2589
|
+
await reportNonCardDecline({
|
|
2590
|
+
billingApiUrl,
|
|
2591
|
+
sessionId: effectiveSessionId,
|
|
2592
|
+
nonce: effectiveNonce,
|
|
2593
|
+
request: {
|
|
2594
|
+
provider: "stripe",
|
|
2595
|
+
paymentMethodCategory: "wallet",
|
|
2596
|
+
paymentMethodType: "paypal",
|
|
2597
|
+
providerDeclineReason: getProviderErrorCode(confirmError) ?? "provider_declined"
|
|
2598
|
+
}
|
|
2599
|
+
});
|
|
2533
2600
|
} else {
|
|
2534
2601
|
recoverTechnicalFailure(confirmError, "stripe_paypal_confirm_failed", attemptContext?.generation);
|
|
2535
2602
|
}
|
|
@@ -2558,9 +2625,9 @@ function PayPalButtonInner({
|
|
|
2558
2625
|
} finally {
|
|
2559
2626
|
setSubmitting(false);
|
|
2560
2627
|
}
|
|
2561
|
-
}, [stripe, elements, sessionId, nonce, email,
|
|
2628
|
+
}, [stripe, elements, sessionId, nonce, email, billingApiUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick, recoverTechnicalFailure, finishAttempt, isAttemptCurrent, isAttemptInvalidated, surfaceKey]);
|
|
2562
2629
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2563
|
-
/* @__PURE__ */
|
|
2630
|
+
/* @__PURE__ */ jsx7(
|
|
2564
2631
|
ExpressCheckoutReadySwap,
|
|
2565
2632
|
{
|
|
2566
2633
|
state: loadState,
|
|
@@ -2575,7 +2642,7 @@ function PayPalButtonInner({
|
|
|
2575
2642
|
"aria-label": "PayPal payment method",
|
|
2576
2643
|
style: { borderRadius: 8, outlineOffset: 4 },
|
|
2577
2644
|
children: [
|
|
2578
|
-
showRecoveryAction && /* @__PURE__ */
|
|
2645
|
+
showRecoveryAction && /* @__PURE__ */ jsx7(
|
|
2579
2646
|
"button",
|
|
2580
2647
|
{
|
|
2581
2648
|
ref: recoveryActionRef,
|
|
@@ -2586,7 +2653,7 @@ function PayPalButtonInner({
|
|
|
2586
2653
|
children: "Try PayPal again"
|
|
2587
2654
|
}
|
|
2588
2655
|
),
|
|
2589
|
-
/* @__PURE__ */
|
|
2656
|
+
/* @__PURE__ */ jsx7(
|
|
2590
2657
|
ExpressCheckoutElement,
|
|
2591
2658
|
{
|
|
2592
2659
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
@@ -2626,7 +2693,7 @@ function PayPalButtonInner({
|
|
|
2626
2693
|
)
|
|
2627
2694
|
}
|
|
2628
2695
|
),
|
|
2629
|
-
submitting && /* @__PURE__ */
|
|
2696
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
2630
2697
|
] });
|
|
2631
2698
|
}
|
|
2632
2699
|
function WalletButtonInner({
|
|
@@ -2634,6 +2701,7 @@ function WalletButtonInner({
|
|
|
2634
2701
|
nonce,
|
|
2635
2702
|
email,
|
|
2636
2703
|
billingApiUrl,
|
|
2704
|
+
intentKind,
|
|
2637
2705
|
expressMethods,
|
|
2638
2706
|
onTokenizedBody,
|
|
2639
2707
|
onErrorChange,
|
|
@@ -2648,20 +2716,19 @@ function WalletButtonInner({
|
|
|
2648
2716
|
const stripe = useStripeRaw();
|
|
2649
2717
|
const elements = useStripeElements();
|
|
2650
2718
|
const [loadState, setLoadState] = useState3("loading");
|
|
2651
|
-
|
|
2719
|
+
useEffect4(() => {
|
|
2652
2720
|
onLoadStateChange?.(loadState);
|
|
2653
2721
|
}, [loadState, onLoadStateChange]);
|
|
2654
2722
|
const [submitting, setSubmitting] = useState3(false);
|
|
2655
|
-
const
|
|
2656
|
-
const
|
|
2657
|
-
const recoveryActionRef = useRef5(null);
|
|
2723
|
+
const focusTargetRef = useRef4(null);
|
|
2724
|
+
const recoveryActionRef = useRef4(null);
|
|
2658
2725
|
const [surfaceKey, setSurfaceKey] = useState3(0);
|
|
2659
2726
|
const [showRecoveryAction, setShowRecoveryAction] = useState3(false);
|
|
2660
2727
|
const [recoveryActionMethod, setRecoveryActionMethod] = useState3("google_pay");
|
|
2661
|
-
const pendingProviderFocusRef =
|
|
2662
|
-
const lastWalletProviderMethodRef =
|
|
2663
|
-
const lastWalletMethodRef =
|
|
2664
|
-
const attemptContextBySurfaceRef =
|
|
2728
|
+
const pendingProviderFocusRef = useRef4(false);
|
|
2729
|
+
const lastWalletProviderMethodRef = useRef4("google_pay");
|
|
2730
|
+
const lastWalletMethodRef = useRef4("google_pay");
|
|
2731
|
+
const attemptContextBySurfaceRef = useRef4(/* @__PURE__ */ new Map());
|
|
2665
2732
|
const {
|
|
2666
2733
|
startAttempt,
|
|
2667
2734
|
finishAttempt,
|
|
@@ -2677,7 +2744,7 @@ function WalletButtonInner({
|
|
|
2677
2744
|
setShowRecoveryAction(true);
|
|
2678
2745
|
setSurfaceKey((key) => key + 1);
|
|
2679
2746
|
});
|
|
2680
|
-
|
|
2747
|
+
useEffect4(() => {
|
|
2681
2748
|
if (showRecoveryAction) recoveryActionRef.current?.focus();
|
|
2682
2749
|
}, [showRecoveryAction, surfaceKey]);
|
|
2683
2750
|
const resetSurface = useCallback3(() => {
|
|
@@ -2696,7 +2763,7 @@ function WalletButtonInner({
|
|
|
2696
2763
|
(target ?? focusTargetRef.current)?.focus();
|
|
2697
2764
|
}, 0);
|
|
2698
2765
|
}, []);
|
|
2699
|
-
|
|
2766
|
+
useEffect4(() => {
|
|
2700
2767
|
if (!pendingProviderFocusRef.current) return;
|
|
2701
2768
|
pendingProviderFocusRef.current = false;
|
|
2702
2769
|
focusProviderSurface();
|
|
@@ -2753,30 +2820,21 @@ function WalletButtonInner({
|
|
|
2753
2820
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
2754
2821
|
throw new Error("Missing sessionId or email for wallet payment");
|
|
2755
2822
|
}
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
|
-
if (
|
|
2768
|
-
|
|
2769
|
-
intentResponse,
|
|
2770
|
-
"Failed to create payment intent"
|
|
2771
|
-
);
|
|
2772
|
-
onErrorChange?.(intentError.message);
|
|
2773
|
-
onDecline?.(buildDeclineEvent(method, intentError));
|
|
2774
|
-
event.paymentFailed({ reason: "fail", message: intentError.message });
|
|
2775
|
-
return;
|
|
2823
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
2824
|
+
effectiveSessionId,
|
|
2825
|
+
effectiveNonce ?? "",
|
|
2826
|
+
{
|
|
2827
|
+
provider: "stripe",
|
|
2828
|
+
paymentMethodCategory: "wallet",
|
|
2829
|
+
paymentMethodType: walletType ?? buttonMethod,
|
|
2830
|
+
paymentMethodId: paymentMethod.id,
|
|
2831
|
+
intentKind
|
|
2832
|
+
}
|
|
2833
|
+
);
|
|
2834
|
+
if (intent.provider !== "stripe") {
|
|
2835
|
+
throw new Error("Invalid provider returned for wallet intent");
|
|
2776
2836
|
}
|
|
2777
|
-
const
|
|
2778
|
-
const intentClientSecret = intentJson.data?.id;
|
|
2779
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2837
|
+
const intentClientSecret = intent.clientSecret;
|
|
2780
2838
|
const { error: confirmError, intentId } = isSetupIntentClientSecret2(intentClientSecret) ? await stripe.confirmCardSetup(intentClientSecret, { payment_method: paymentMethod.id }).then((r) => ({ error: r.error, intentId: r.setupIntent?.id })) : await stripe.confirmCardPayment(intentClientSecret, { payment_method: paymentMethod.id }).then((r) => ({ error: r.error, intentId: r.paymentIntent?.id }));
|
|
2781
2839
|
if (confirmError) {
|
|
2782
2840
|
if (isProviderDecline(confirmError)) {
|
|
@@ -2786,6 +2844,17 @@ function WalletButtonInner({
|
|
|
2786
2844
|
code: getProviderErrorCode(confirmError),
|
|
2787
2845
|
declineCode: getProviderDeclineCode(confirmError)
|
|
2788
2846
|
}));
|
|
2847
|
+
await reportNonCardDecline({
|
|
2848
|
+
billingApiUrl,
|
|
2849
|
+
sessionId: effectiveSessionId,
|
|
2850
|
+
nonce: effectiveNonce,
|
|
2851
|
+
request: {
|
|
2852
|
+
provider: "stripe",
|
|
2853
|
+
paymentMethodCategory: "wallet",
|
|
2854
|
+
paymentMethodType: walletType ?? buttonMethod,
|
|
2855
|
+
providerDeclineReason: getProviderErrorCode(confirmError) ?? "provider_declined"
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2789
2858
|
} else {
|
|
2790
2859
|
recoverTechnicalFailure(walletType, confirmError, "stripe_wallet_confirm_failed", attemptContext?.generation);
|
|
2791
2860
|
}
|
|
@@ -2806,7 +2875,7 @@ function WalletButtonInner({
|
|
|
2806
2875
|
setSubmitting(false);
|
|
2807
2876
|
}
|
|
2808
2877
|
},
|
|
2809
|
-
[stripe, elements, sessionId, nonce, email,
|
|
2878
|
+
[stripe, elements, sessionId, nonce, email, billingApiUrl, intentKind, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick, recoverTechnicalFailure, finishAttempt, isAttemptCurrent, isAttemptInvalidated, surfaceKey]
|
|
2810
2879
|
);
|
|
2811
2880
|
const expressMethodMap = useMemo3(() => {
|
|
2812
2881
|
const allKeys = ["applePay", "googlePay", "paypal", "link", "amazonPay", "klarna"];
|
|
@@ -2827,7 +2896,7 @@ function WalletButtonInner({
|
|
|
2827
2896
|
[expressMethods]
|
|
2828
2897
|
);
|
|
2829
2898
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2830
|
-
/* @__PURE__ */
|
|
2899
|
+
/* @__PURE__ */ jsx7(
|
|
2831
2900
|
ExpressCheckoutReadySwap,
|
|
2832
2901
|
{
|
|
2833
2902
|
state: loadState,
|
|
@@ -2857,7 +2926,7 @@ function WalletButtonInner({
|
|
|
2857
2926
|
]
|
|
2858
2927
|
}
|
|
2859
2928
|
),
|
|
2860
|
-
/* @__PURE__ */
|
|
2929
|
+
/* @__PURE__ */ jsx7(
|
|
2861
2930
|
ExpressCheckoutElement,
|
|
2862
2931
|
{
|
|
2863
2932
|
onReady: (event) => {
|
|
@@ -2921,7 +2990,7 @@ function WalletButtonInner({
|
|
|
2921
2990
|
)
|
|
2922
2991
|
}
|
|
2923
2992
|
),
|
|
2924
|
-
submitting && /* @__PURE__ */
|
|
2993
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
2925
2994
|
] });
|
|
2926
2995
|
}
|
|
2927
2996
|
function StripeMethodButton({
|
|
@@ -2943,7 +3012,7 @@ function StripeMethodButton({
|
|
|
2943
3012
|
const resolvedBackground = brand?.backgroundColor ?? backgroundColor ?? "#ffffff";
|
|
2944
3013
|
const resolvedBorder = brand?.borderColor ?? borderColor ?? "#d1d5db";
|
|
2945
3014
|
const resolvedTextColor = brand?.textColor ?? textColor ?? "#262833";
|
|
2946
|
-
return /* @__PURE__ */
|
|
3015
|
+
return /* @__PURE__ */ jsx7(
|
|
2947
3016
|
"button",
|
|
2948
3017
|
{
|
|
2949
3018
|
type: "button",
|
|
@@ -2990,7 +3059,7 @@ function StripeMethodButton({
|
|
|
2990
3059
|
// Pulse-skeleton parity with the wallet ECE: no spinner, just the
|
|
2991
3060
|
// status text on top of the pulsing background. Keeps the loading
|
|
2992
3061
|
// affordance shape-equivalent across both kinds of tile.
|
|
2993
|
-
/* @__PURE__ */
|
|
3062
|
+
/* @__PURE__ */ jsx7("span", { style: { margin: "0 auto" }, children: `Connecting to ${getStripeMethodDisplayName(method)}\u2026` })
|
|
2994
3063
|
) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2995
3064
|
/* @__PURE__ */ jsxs5(
|
|
2996
3065
|
"span",
|
|
@@ -3010,7 +3079,7 @@ function StripeMethodButton({
|
|
|
3010
3079
|
// bytes ship as a sibling file, out of the JS bundle. 3:2 box
|
|
3011
3080
|
// matching the datatrans logos' 120×80 viewBox; each ships its own
|
|
3012
3081
|
// white rounded-rect background so it stays legible on any tile.
|
|
3013
|
-
/* @__PURE__ */
|
|
3082
|
+
/* @__PURE__ */ jsx7(
|
|
3014
3083
|
"img",
|
|
3015
3084
|
{
|
|
3016
3085
|
src: vendoredLogoUrl,
|
|
@@ -3030,7 +3099,7 @@ function StripeMethodButton({
|
|
|
3030
3099
|
}
|
|
3031
3100
|
}
|
|
3032
3101
|
)
|
|
3033
|
-
) : brand?.logoSvg ? /* @__PURE__ */
|
|
3102
|
+
) : brand?.logoSvg ? /* @__PURE__ */ jsx7(
|
|
3034
3103
|
"span",
|
|
3035
3104
|
{
|
|
3036
3105
|
"aria-hidden": "true",
|
|
@@ -3045,11 +3114,11 @@ function StripeMethodButton({
|
|
|
3045
3114
|
dangerouslySetInnerHTML: { __html: brand.logoSvg }
|
|
3046
3115
|
}
|
|
3047
3116
|
) : null,
|
|
3048
|
-
/* @__PURE__ */
|
|
3117
|
+
/* @__PURE__ */ jsx7("span", { children: getStripeMethodDisplayName(method) })
|
|
3049
3118
|
]
|
|
3050
3119
|
}
|
|
3051
3120
|
),
|
|
3052
|
-
hasNextStep && /* @__PURE__ */
|
|
3121
|
+
hasNextStep && /* @__PURE__ */ jsx7(
|
|
3053
3122
|
"svg",
|
|
3054
3123
|
{
|
|
3055
3124
|
width: "14",
|
|
@@ -3069,7 +3138,7 @@ function StripeMethodButton({
|
|
|
3069
3138
|
opacity: 0.7
|
|
3070
3139
|
},
|
|
3071
3140
|
"aria-hidden": "true",
|
|
3072
|
-
children: /* @__PURE__ */
|
|
3141
|
+
children: /* @__PURE__ */ jsx7("path", { d: "M9 18l6-6-6-6" })
|
|
3073
3142
|
}
|
|
3074
3143
|
)
|
|
3075
3144
|
] })
|
|
@@ -3099,10 +3168,9 @@ function StripeMethodInlineForm({
|
|
|
3099
3168
|
const stripe = useStripeRaw();
|
|
3100
3169
|
const elements = useStripeElements();
|
|
3101
3170
|
const [submitting, setSubmitting] = useState3(false);
|
|
3102
|
-
const submittingRef =
|
|
3171
|
+
const submittingRef = useRef4(false);
|
|
3103
3172
|
const [isMethodComplete, setIsMethodComplete] = useState3(false);
|
|
3104
3173
|
const [loadState, setLoadState] = useState3("loading");
|
|
3105
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
3106
3174
|
const handlePay = useCallback3(async () => {
|
|
3107
3175
|
if (!stripe || !elements || isProcessing || submittingRef.current || !isMethodComplete) return;
|
|
3108
3176
|
submittingRef.current = true;
|
|
@@ -3133,26 +3201,22 @@ function StripeMethodInlineForm({
|
|
|
3133
3201
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
3134
3202
|
throw new Error("Missing sessionId or email for payment.");
|
|
3135
3203
|
}
|
|
3136
|
-
const
|
|
3137
|
-
const
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
paymentMethodType
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
onDecline?.(buildDeclineEvent("card", intentError));
|
|
3151
|
-
return;
|
|
3204
|
+
const paymentMethodType = paymentMethod.type || method;
|
|
3205
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
3206
|
+
effectiveSessionId,
|
|
3207
|
+
effectiveNonce ?? "",
|
|
3208
|
+
{
|
|
3209
|
+
provider: "stripe",
|
|
3210
|
+
paymentMethodCategory: "apm",
|
|
3211
|
+
paymentMethodType,
|
|
3212
|
+
paymentMethodId: null,
|
|
3213
|
+
intentKind: "payment"
|
|
3214
|
+
}
|
|
3215
|
+
);
|
|
3216
|
+
if (intent.provider !== "stripe") {
|
|
3217
|
+
throw new Error("Invalid provider returned for APM intent");
|
|
3152
3218
|
}
|
|
3153
|
-
const
|
|
3154
|
-
const intentClientSecret = intentJson.data?.id;
|
|
3155
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
3219
|
+
const intentClientSecret = intent.clientSecret;
|
|
3156
3220
|
if (typeof window !== "undefined") {
|
|
3157
3221
|
try {
|
|
3158
3222
|
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
@@ -3185,6 +3249,17 @@ function StripeMethodInlineForm({
|
|
|
3185
3249
|
const message = confirmError.message ?? "Payment failed.";
|
|
3186
3250
|
onErrorChange?.(message);
|
|
3187
3251
|
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
3252
|
+
await reportNonCardDecline({
|
|
3253
|
+
billingApiUrl,
|
|
3254
|
+
sessionId: effectiveSessionId,
|
|
3255
|
+
nonce: effectiveNonce,
|
|
3256
|
+
request: {
|
|
3257
|
+
provider: "stripe",
|
|
3258
|
+
paymentMethodCategory: "apm",
|
|
3259
|
+
paymentMethodType: method,
|
|
3260
|
+
providerDeclineReason: confirmError.code ?? "provider_declined"
|
|
3261
|
+
}
|
|
3262
|
+
});
|
|
3188
3263
|
return;
|
|
3189
3264
|
}
|
|
3190
3265
|
const piStatus = paymentIntent?.status;
|
|
@@ -3234,7 +3309,7 @@ function StripeMethodInlineForm({
|
|
|
3234
3309
|
sessionId,
|
|
3235
3310
|
nonce,
|
|
3236
3311
|
email,
|
|
3237
|
-
|
|
3312
|
+
billingApiUrl,
|
|
3238
3313
|
method,
|
|
3239
3314
|
onTokenizedBody,
|
|
3240
3315
|
onErrorChange,
|
|
@@ -3242,8 +3317,8 @@ function StripeMethodInlineForm({
|
|
|
3242
3317
|
]);
|
|
3243
3318
|
void onCancel;
|
|
3244
3319
|
return /* @__PURE__ */ jsxs5("div", { "data-testid": `flopay-stripe-method-form-${method}`, style: { display: "flex", flexDirection: "column" }, children: [
|
|
3245
|
-
/* @__PURE__ */
|
|
3246
|
-
|
|
3320
|
+
/* @__PURE__ */ jsx7(
|
|
3321
|
+
PaymentElement,
|
|
3247
3322
|
{
|
|
3248
3323
|
onReady: () => setLoadState("ready"),
|
|
3249
3324
|
onLoadError: () => {
|
|
@@ -3271,7 +3346,7 @@ function StripeMethodInlineForm({
|
|
|
3271
3346
|
}
|
|
3272
3347
|
}
|
|
3273
3348
|
),
|
|
3274
|
-
/* @__PURE__ */
|
|
3349
|
+
/* @__PURE__ */ jsx7(
|
|
3275
3350
|
"button",
|
|
3276
3351
|
{
|
|
3277
3352
|
type: "button",
|
|
@@ -3298,7 +3373,7 @@ function StripeMethodInlineForm({
|
|
|
3298
3373
|
children: submitting ? "Processing\u2026" : `Pay with ${getStripeMethodDisplayName(method)}`
|
|
3299
3374
|
}
|
|
3300
3375
|
),
|
|
3301
|
-
errorText && /* @__PURE__ */
|
|
3376
|
+
errorText && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.75rem 0 0", children: errorText })
|
|
3302
3377
|
] });
|
|
3303
3378
|
}
|
|
3304
3379
|
function StripePaymentElementInner({
|
|
@@ -3325,11 +3400,10 @@ function StripePaymentElementInner({
|
|
|
3325
3400
|
onExpandApm,
|
|
3326
3401
|
expandedApmMethod
|
|
3327
3402
|
}) {
|
|
3328
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
3329
3403
|
const [expandedMethod, setExpandedMethod] = useState3(null);
|
|
3330
3404
|
const [submittingMethod, setSubmittingMethod] = useState3(null);
|
|
3331
|
-
const submittingRef =
|
|
3332
|
-
|
|
3405
|
+
const submittingRef = useRef4(false);
|
|
3406
|
+
useEffect4(() => {
|
|
3333
3407
|
if (paymentElementMethods.length > 0 && stripeInstance) {
|
|
3334
3408
|
onLoadStateChange?.("ready");
|
|
3335
3409
|
} else if (!stripeInstance) {
|
|
@@ -3356,30 +3430,21 @@ function StripePaymentElementInner({
|
|
|
3356
3430
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
3357
3431
|
throw new Error("Missing sessionId or email for payment.");
|
|
3358
3432
|
}
|
|
3359
|
-
const
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
email: effectiveEmail,
|
|
3366
|
-
// Wire type, not pm_xxx — backend scopes `payment_method_types`
|
|
3367
|
-
// to this single method so unrelated account-wide methods
|
|
3368
|
-
// (apple_pay without domain verification, …) don't poison PI
|
|
3369
|
-
// creation.
|
|
3433
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
3434
|
+
effectiveSessionId,
|
|
3435
|
+
effectiveNonce ?? "",
|
|
3436
|
+
{
|
|
3437
|
+
provider: "stripe",
|
|
3438
|
+
paymentMethodCategory: "apm",
|
|
3370
3439
|
paymentMethodType: method,
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
onDecline?.(buildDeclineEvent("card", intentError));
|
|
3378
|
-
return;
|
|
3440
|
+
paymentMethodId: null,
|
|
3441
|
+
intentKind: "payment"
|
|
3442
|
+
}
|
|
3443
|
+
);
|
|
3444
|
+
if (intent.provider !== "stripe") {
|
|
3445
|
+
throw new Error("Invalid provider returned for APM intent");
|
|
3379
3446
|
}
|
|
3380
|
-
const
|
|
3381
|
-
const intentClientSecret = intentJson.data?.id;
|
|
3382
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
3447
|
+
const intentClientSecret = intent.clientSecret;
|
|
3383
3448
|
if (typeof window !== "undefined") {
|
|
3384
3449
|
try {
|
|
3385
3450
|
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
@@ -3420,6 +3485,17 @@ function StripePaymentElementInner({
|
|
|
3420
3485
|
const message = confirmError.message ?? "Payment failed.";
|
|
3421
3486
|
onErrorChange?.(message);
|
|
3422
3487
|
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
3488
|
+
await reportNonCardDecline({
|
|
3489
|
+
billingApiUrl,
|
|
3490
|
+
sessionId: effectiveSessionId,
|
|
3491
|
+
nonce: effectiveNonce,
|
|
3492
|
+
request: {
|
|
3493
|
+
provider: "stripe",
|
|
3494
|
+
paymentMethodCategory: "apm",
|
|
3495
|
+
paymentMethodType: method,
|
|
3496
|
+
providerDeclineReason: confirmError.code ?? "provider_declined"
|
|
3497
|
+
}
|
|
3498
|
+
});
|
|
3423
3499
|
return;
|
|
3424
3500
|
}
|
|
3425
3501
|
const piStatus = paymentIntent?.status;
|
|
@@ -3467,7 +3543,7 @@ function StripePaymentElementInner({
|
|
|
3467
3543
|
sessionId,
|
|
3468
3544
|
nonce,
|
|
3469
3545
|
email,
|
|
3470
|
-
|
|
3546
|
+
billingApiUrl,
|
|
3471
3547
|
billingName,
|
|
3472
3548
|
onTokenizedBody,
|
|
3473
3549
|
onErrorChange,
|
|
@@ -3495,7 +3571,7 @@ function StripePaymentElementInner({
|
|
|
3495
3571
|
paymentMethodTypes: [localExpandedMethod]
|
|
3496
3572
|
};
|
|
3497
3573
|
}, [localExpandedMethod, paymentElementBaseOptions]);
|
|
3498
|
-
return /* @__PURE__ */
|
|
3574
|
+
return /* @__PURE__ */ jsx7(
|
|
3499
3575
|
"div",
|
|
3500
3576
|
{
|
|
3501
3577
|
"data-testid": "flopay-stripe-payment-element-region",
|
|
@@ -3504,8 +3580,8 @@ function StripePaymentElementInner({
|
|
|
3504
3580
|
const isExpanded = expandedApmMethod === method;
|
|
3505
3581
|
const isSubmittingThis = submittingMethod === method;
|
|
3506
3582
|
const otherInProgress = submittingMethod !== null && submittingMethod !== method || expandedApmMethod !== null && expandedApmMethod !== void 0 && expandedApmMethod !== method;
|
|
3507
|
-
return /* @__PURE__ */ jsxs5(
|
|
3508
|
-
/* @__PURE__ */
|
|
3583
|
+
return /* @__PURE__ */ jsxs5(React7.Fragment, { children: [
|
|
3584
|
+
/* @__PURE__ */ jsx7(
|
|
3509
3585
|
StripeMethodButton,
|
|
3510
3586
|
{
|
|
3511
3587
|
method,
|
|
@@ -3522,12 +3598,12 @@ function StripePaymentElementInner({
|
|
|
3522
3598
|
fontFamily: buttonAppearance?.fontFamily
|
|
3523
3599
|
}
|
|
3524
3600
|
),
|
|
3525
|
-
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */
|
|
3601
|
+
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */ jsx7(
|
|
3526
3602
|
StripeElements,
|
|
3527
3603
|
{
|
|
3528
3604
|
stripe: stripeInstance,
|
|
3529
3605
|
options: localInlineElementsOptions,
|
|
3530
|
-
children: /* @__PURE__ */
|
|
3606
|
+
children: /* @__PURE__ */ jsx7(
|
|
3531
3607
|
StripeMethodInlineForm,
|
|
3532
3608
|
{
|
|
3533
3609
|
method,
|
|
@@ -3568,15 +3644,10 @@ function SplitCardFormInner({
|
|
|
3568
3644
|
firstName,
|
|
3569
3645
|
lastName,
|
|
3570
3646
|
chv,
|
|
3571
|
-
submitLabel = "CONFIRM PAYMENT",
|
|
3572
3647
|
className,
|
|
3573
|
-
children,
|
|
3574
3648
|
isProcessing: externalProcessing,
|
|
3575
3649
|
error: externalError,
|
|
3576
3650
|
onErrorChange,
|
|
3577
|
-
onFullNameChange,
|
|
3578
|
-
onFirstNameChange,
|
|
3579
|
-
onLastNameChange,
|
|
3580
3651
|
showPayPal = true,
|
|
3581
3652
|
showStripe = true,
|
|
3582
3653
|
enabledPaymentMethods,
|
|
@@ -3615,17 +3686,14 @@ function SplitCardFormInner({
|
|
|
3615
3686
|
directPaypal,
|
|
3616
3687
|
isSubscription = false,
|
|
3617
3688
|
session,
|
|
3618
|
-
debug = false
|
|
3619
|
-
innerRef
|
|
3689
|
+
debug = false
|
|
3620
3690
|
}) {
|
|
3621
3691
|
const flopay = useFloPay();
|
|
3622
3692
|
const paypalFlopay = usePayPalFloPay();
|
|
3623
|
-
const
|
|
3624
|
-
const checkout = useContext3(CheckoutContext);
|
|
3693
|
+
const checkout = useContext2(CheckoutContext);
|
|
3625
3694
|
const contextBillingUrl = useBillingApiUrl();
|
|
3626
3695
|
const [processing, setProcessing] = useState3(false);
|
|
3627
3696
|
const [error, setError] = useState3(null);
|
|
3628
|
-
const [is3DSActive, setIs3DSActive] = useState3(false);
|
|
3629
3697
|
const [selectedCountry, setSelectedCountry] = useState3(countryProp ?? "US");
|
|
3630
3698
|
const [zipCode, setZipCode] = useState3(zipProp ?? "");
|
|
3631
3699
|
const [addressLine1, setAddressLine1] = useState3(addressLine1Prop ?? "");
|
|
@@ -3633,18 +3701,19 @@ function SplitCardFormInner({
|
|
|
3633
3701
|
const [city, setCity] = useState3(cityProp ?? "");
|
|
3634
3702
|
const [stateValue, setStateValue] = useState3(stateProp ?? "");
|
|
3635
3703
|
const [accountPatch, setAccountPatch] = useState3({});
|
|
3636
|
-
const zipCodeRef =
|
|
3637
|
-
const selectedCountryRef =
|
|
3638
|
-
const addressLine1Ref =
|
|
3639
|
-
const addressLine2Ref =
|
|
3640
|
-
const cityRef =
|
|
3641
|
-
const stateRef =
|
|
3704
|
+
const zipCodeRef = useRef4(zipProp ?? "");
|
|
3705
|
+
const selectedCountryRef = useRef4(countryProp ?? "US");
|
|
3706
|
+
const addressLine1Ref = useRef4(addressLine1Prop ?? "");
|
|
3707
|
+
const addressLine2Ref = useRef4(addressLine2Prop ?? "");
|
|
3708
|
+
const cityRef = useRef4(cityProp ?? "");
|
|
3709
|
+
const stateRef = useRef4(stateProp ?? "");
|
|
3642
3710
|
const avsConfig = useMemo3(() => resolveAVSConfig(enableAVSProp), [enableAVSProp]);
|
|
3643
3711
|
const enableAVS = avsConfig !== null;
|
|
3644
3712
|
const vaultBlockReady = Boolean(session?.vault?.html);
|
|
3645
3713
|
const vaultGatewayAdvertised = Boolean(session?.gateways?.pcivault);
|
|
3714
|
+
const vaultCapabilityAvailable = vaultBlockReady || vaultGatewayAdvertised;
|
|
3646
3715
|
const vaultActive = Boolean(
|
|
3647
|
-
showStripe &&
|
|
3716
|
+
showStripe && vaultCapabilityAvailable && flopay && sessionId
|
|
3648
3717
|
);
|
|
3649
3718
|
const cardCapture = useMemo3(() => {
|
|
3650
3719
|
if (!flopay || !vaultActive || !sessionId) return null;
|
|
@@ -3676,7 +3745,9 @@ function SplitCardFormInner({
|
|
|
3676
3745
|
const [vaultMount, setVaultMount] = useState3(
|
|
3677
3746
|
() => toVaultMount(session?.vault)
|
|
3678
3747
|
);
|
|
3679
|
-
const [viewState, setViewState] = useState3(
|
|
3748
|
+
const [viewState, setViewState] = useState3(
|
|
3749
|
+
initialCardOpen && vaultCapabilityAvailable ? "card" : "buttons"
|
|
3750
|
+
);
|
|
3680
3751
|
const [expandedApmMethod, setExpandedApmMethod] = useState3(null);
|
|
3681
3752
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
3682
3753
|
const TRANSITION_MS = 280;
|
|
@@ -3700,18 +3771,16 @@ function SplitCardFormInner({
|
|
|
3700
3771
|
setExpandedApmMethod(null);
|
|
3701
3772
|
}, TRANSITION_MS);
|
|
3702
3773
|
}, []);
|
|
3703
|
-
|
|
3704
|
-
if (layout === "buttons" && initialCardOpen) {
|
|
3774
|
+
useEffect4(() => {
|
|
3775
|
+
if (layout === "buttons" && initialCardOpen && vaultCapabilityAvailable) {
|
|
3705
3776
|
setViewState("card");
|
|
3706
3777
|
}
|
|
3707
|
-
}, [layout, initialCardOpen]);
|
|
3708
|
-
const [fullName, setFullName] = useState3("");
|
|
3709
|
-
const [formReady, setFormReady] = useState3(false);
|
|
3778
|
+
}, [layout, initialCardOpen, vaultCapabilityAvailable]);
|
|
3710
3779
|
const [overlayStatus, setOverlayStatus] = useState3(null);
|
|
3711
|
-
const processingRef =
|
|
3780
|
+
const processingRef = useRef4(false);
|
|
3712
3781
|
const [paypalDirectRetry, setPaypalDirectRetry] = useState3(null);
|
|
3713
|
-
const paypalDirectRetryRef =
|
|
3714
|
-
|
|
3782
|
+
const paypalDirectRetryRef = useRef4(paypalDirectRetry);
|
|
3783
|
+
useEffect4(() => {
|
|
3715
3784
|
paypalDirectRetryRef.current = paypalDirectRetry;
|
|
3716
3785
|
}, [paypalDirectRetry]);
|
|
3717
3786
|
const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
|
|
@@ -3759,7 +3828,6 @@ function SplitCardFormInner({
|
|
|
3759
3828
|
}, [appearance, bStyles, layout]);
|
|
3760
3829
|
const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
|
|
3761
3830
|
const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
|
|
3762
|
-
const isSelfContained = !onTokenizedBody;
|
|
3763
3831
|
const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
|
|
3764
3832
|
const resolvedAccount = useMemo3(() => mergeAccountPatch({
|
|
3765
3833
|
userId,
|
|
@@ -3769,6 +3837,7 @@ function SplitCardFormInner({
|
|
|
3769
3837
|
country: countryProp,
|
|
3770
3838
|
zip: zipProp
|
|
3771
3839
|
}, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
|
|
3840
|
+
const resolvedBillingName = [resolvedAccount.firstName, resolvedAccount.lastName].filter((part) => Boolean(part?.trim())).join(" ");
|
|
3772
3841
|
const stripeInstance = useMemo3(() => {
|
|
3773
3842
|
if (!flopay) return null;
|
|
3774
3843
|
return flopay.getRawProvider();
|
|
@@ -3825,11 +3894,11 @@ function SplitCardFormInner({
|
|
|
3825
3894
|
},
|
|
3826
3895
|
[onErrorChange]
|
|
3827
3896
|
);
|
|
3828
|
-
|
|
3897
|
+
useEffect4(() => {
|
|
3829
3898
|
if (!vaultActive || !cardCapture) return;
|
|
3830
3899
|
cardCapture.setCardFieldOrder?.(cardFieldOrder ?? null, avsConfig == null);
|
|
3831
3900
|
}, [vaultActive, cardCapture, cardFieldOrder, avsConfig]);
|
|
3832
|
-
|
|
3901
|
+
useEffect4(() => {
|
|
3833
3902
|
if (viewState === "expanding" || viewState === "collapsing" || viewState === "apm-expanding" || viewState === "apm-collapsing") {
|
|
3834
3903
|
updateError(null);
|
|
3835
3904
|
}
|
|
@@ -3864,7 +3933,7 @@ function SplitCardFormInner({
|
|
|
3864
3933
|
},
|
|
3865
3934
|
[layout, onError, updateError]
|
|
3866
3935
|
);
|
|
3867
|
-
|
|
3936
|
+
useEffect4(() => {
|
|
3868
3937
|
if (!vaultActive || !sessionId) {
|
|
3869
3938
|
setVaultMount(null);
|
|
3870
3939
|
return;
|
|
@@ -3902,13 +3971,12 @@ function SplitCardFormInner({
|
|
|
3902
3971
|
nonce,
|
|
3903
3972
|
updateError
|
|
3904
3973
|
]);
|
|
3905
|
-
const vaultOutcomeRef =
|
|
3974
|
+
const vaultOutcomeRef = useRef4({
|
|
3906
3975
|
onComplete,
|
|
3907
3976
|
onError,
|
|
3908
3977
|
updateError,
|
|
3909
3978
|
emitDecline,
|
|
3910
3979
|
resolvedAccount,
|
|
3911
|
-
fullName,
|
|
3912
3980
|
avsConfig,
|
|
3913
3981
|
avsCheckProp,
|
|
3914
3982
|
sessionId,
|
|
@@ -3921,16 +3989,15 @@ function SplitCardFormInner({
|
|
|
3921
3989
|
updateError,
|
|
3922
3990
|
emitDecline,
|
|
3923
3991
|
resolvedAccount,
|
|
3924
|
-
fullName,
|
|
3925
3992
|
avsConfig,
|
|
3926
3993
|
avsCheckProp,
|
|
3927
3994
|
sessionId,
|
|
3928
3995
|
nonce,
|
|
3929
3996
|
baseUrl
|
|
3930
3997
|
};
|
|
3931
|
-
const vaultCompletedRef =
|
|
3998
|
+
const vaultCompletedRef = useRef4(false);
|
|
3932
3999
|
const buildVaultAccountSnapshot = useCallback3(() => {
|
|
3933
|
-
const { resolvedAccount: resolvedAccount2, avsConfig: avsConfig2,
|
|
4000
|
+
const { resolvedAccount: resolvedAccount2, avsConfig: avsConfig2, avsCheckProp: avsCheckProp2 } = vaultOutcomeRef.current;
|
|
3934
4001
|
const cc = selectedCountryRef.current || resolvedAccount2.country || "US";
|
|
3935
4002
|
const stateVisible = avsConfig2 ? isAVSFieldVisible(avsConfig2.state, cc) : false;
|
|
3936
4003
|
const line1Visible = avsConfig2 ? isAVSFieldVisible(avsConfig2.address_line_1, cc) : false;
|
|
@@ -3943,8 +4010,8 @@ function SplitCardFormInner({
|
|
|
3943
4010
|
accountData: {
|
|
3944
4011
|
userId: resolvedAccount2.userId ?? "",
|
|
3945
4012
|
email: resolvedAccount2.email ?? "",
|
|
3946
|
-
firstName: resolvedAccount2.firstName ??
|
|
3947
|
-
lastName: resolvedAccount2.lastName ??
|
|
4013
|
+
firstName: resolvedAccount2.firstName ?? "",
|
|
4014
|
+
lastName: resolvedAccount2.lastName ?? "",
|
|
3948
4015
|
...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
|
|
3949
4016
|
...cityVisible && cityRef.current ? { city: cityRef.current } : {},
|
|
3950
4017
|
...stateValue2 ? { state: stateValue2 } : {},
|
|
@@ -3965,11 +4032,11 @@ function SplitCardFormInner({
|
|
|
3965
4032
|
} : {}
|
|
3966
4033
|
};
|
|
3967
4034
|
}, []);
|
|
3968
|
-
|
|
4035
|
+
useEffect4(() => {
|
|
3969
4036
|
if (!vaultActive || !cardCapture) return;
|
|
3970
4037
|
cardCapture.setSubmitGate?.(avsInvalid);
|
|
3971
4038
|
}, [vaultActive, cardCapture, avsInvalid]);
|
|
3972
|
-
|
|
4039
|
+
useEffect4(() => {
|
|
3973
4040
|
if (!vaultActive || !cardCapture) return;
|
|
3974
4041
|
vaultCompletedRef.current = false;
|
|
3975
4042
|
let cancelled = false;
|
|
@@ -4072,21 +4139,25 @@ function SplitCardFormInner({
|
|
|
4072
4139
|
const [walletLoadState, setWalletLoadState] = useState3("loading");
|
|
4073
4140
|
const [paymentElementLoadState, setPaymentElementLoadState] = useState3("loading");
|
|
4074
4141
|
const [directPaypalReady, setDirectPaypalReady] = useState3(false);
|
|
4142
|
+
const [directPaypalInitializationState, setDirectPaypalInitializationState] = useState3("loading");
|
|
4075
4143
|
const [inAppBrowserDetected, setInAppBrowserDetected] = useState3();
|
|
4076
|
-
|
|
4144
|
+
useEffect4(() => {
|
|
4077
4145
|
setInAppBrowserDetected(isInAppBrowser());
|
|
4078
4146
|
}, []);
|
|
4079
4147
|
const shouldShowPayPal = showPayPal && (directPaypalConfigured || (hasEnabledMethodsPayload ? paypalEnabled : inAppBrowserDetected === false));
|
|
4080
4148
|
const shouldShowWallets = showStripe && showWallets;
|
|
4081
4149
|
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
4082
|
-
const
|
|
4150
|
+
const directPaypalUnavailable = directPaypalInitializationState === "retrying" || directPaypalInitializationState === "exhausted";
|
|
4151
|
+
const shouldRenderStripePayPal = shouldShowPayPal && !!paypalStripeInstance && (!directPaypalConfigured || directPaypalUnavailable);
|
|
4083
4152
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
4084
4153
|
const shouldRenderPaymentElement = showStripe && hasEnabledMethods && paymentElementMethodsForCurrency.length > 0 && !!stripeInstance;
|
|
4085
|
-
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
4154
|
+
const shouldDisplayPayPalRow = shouldRenderDirectPayPal && !directPaypalUnavailable ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
4086
4155
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
4087
4156
|
const shouldDisplayPaymentElementRow = shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
4088
|
-
const
|
|
4089
|
-
|
|
4157
|
+
const expressSurfaceUsable = (state) => state === "loading" || state === "ready";
|
|
4158
|
+
const hasUsableNonCardCapability = shouldRenderDirectPayPal || shouldRenderStripePayPal && expressSurfaceUsable(paypalLoadState) || shouldRenderWallets && expressSurfaceUsable(walletLoadState) || shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
4159
|
+
const validationFiredRef = useRef4(false);
|
|
4160
|
+
useEffect4(() => {
|
|
4090
4161
|
if (validationFiredRef.current) return;
|
|
4091
4162
|
if (!showStripe && !showPayPal) {
|
|
4092
4163
|
validationFiredRef.current = true;
|
|
@@ -4104,10 +4175,29 @@ function SplitCardFormInner({
|
|
|
4104
4175
|
);
|
|
4105
4176
|
onError?.(err);
|
|
4106
4177
|
updateError(err.message);
|
|
4178
|
+
} else if (inAppBrowserDetected !== void 0 && !vaultCapabilityAvailable && !hasUsableNonCardCapability) {
|
|
4179
|
+
validationFiredRef.current = true;
|
|
4180
|
+
const err = new FloPayError3(
|
|
4181
|
+
"FloPay: this checkout session has no vault card capability and no usable supported non-card payment methods. Upgrade the billing backend integration.",
|
|
4182
|
+
"api_error",
|
|
4183
|
+
{ code: "UnsupportedBackendVaultCapability" }
|
|
4184
|
+
);
|
|
4185
|
+
onError?.(err);
|
|
4186
|
+
updateError(err.message);
|
|
4107
4187
|
}
|
|
4108
|
-
}, [
|
|
4109
|
-
|
|
4110
|
-
|
|
4188
|
+
}, [
|
|
4189
|
+
showStripe,
|
|
4190
|
+
showPayPal,
|
|
4191
|
+
directPaypalConfigured,
|
|
4192
|
+
paypalStripeInstance,
|
|
4193
|
+
inAppBrowserDetected,
|
|
4194
|
+
vaultCapabilityAvailable,
|
|
4195
|
+
hasUsableNonCardCapability,
|
|
4196
|
+
onError,
|
|
4197
|
+
updateError
|
|
4198
|
+
]);
|
|
4199
|
+
const deprecationLoggedRef = useRef4(false);
|
|
4200
|
+
useEffect4(() => {
|
|
4111
4201
|
if (deprecationLoggedRef.current) return;
|
|
4112
4202
|
if (!hasEnabledMethods) return;
|
|
4113
4203
|
const stale = [];
|
|
@@ -4119,13 +4209,6 @@ function SplitCardFormInner({
|
|
|
4119
4209
|
`[FloPay] ${stale.join(" / ")} ${stale.length === 1 ? "is" : "are"} deprecated: the Apple Pay / Google Pay surface is now driven by \`gateways.stripe.enabledPaymentMethods\` on the session response. Remove the legacy prop(s) to silence this warning.`
|
|
4120
4210
|
);
|
|
4121
4211
|
}, [hasEnabledMethods, showApplePay, showGooglePay]);
|
|
4122
|
-
const handleNameChange = useCallback3((value) => {
|
|
4123
|
-
setFullName(value);
|
|
4124
|
-
onFullNameChange?.(value);
|
|
4125
|
-
const parts = value.trim().split(/\s+/);
|
|
4126
|
-
onFirstNameChange?.(parts[0] ?? "");
|
|
4127
|
-
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
4128
|
-
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
4129
4212
|
const applyInlineSessionPatch = useCallback3(
|
|
4130
4213
|
(patch, method) => {
|
|
4131
4214
|
if (!checkout.applyInlineSessionPatch) {
|
|
@@ -4206,8 +4289,8 @@ function SplitCardFormInner({
|
|
|
4206
4289
|
accountData: {
|
|
4207
4290
|
userId: effectiveAccount.userId ?? "",
|
|
4208
4291
|
email: effectiveAccount.email ?? "",
|
|
4209
|
-
firstName: effectiveAccount.firstName ??
|
|
4210
|
-
lastName: effectiveAccount.lastName ??
|
|
4292
|
+
firstName: effectiveAccount.firstName ?? "",
|
|
4293
|
+
lastName: effectiveAccount.lastName ?? "",
|
|
4211
4294
|
...avsConfig ? (() => {
|
|
4212
4295
|
const c = selectedCountryRef.current;
|
|
4213
4296
|
const stateVisible = isAVSFieldVisible(avsConfig.state, c);
|
|
@@ -4255,70 +4338,6 @@ function SplitCardFormInner({
|
|
|
4255
4338
|
return;
|
|
4256
4339
|
}
|
|
4257
4340
|
const json = await response.json().catch(() => null);
|
|
4258
|
-
if (json?.type === "3ds_required") {
|
|
4259
|
-
const secret = json["threeDSecureToken"];
|
|
4260
|
-
if (!flopay || !secret) {
|
|
4261
|
-
setOverlayStatus("error");
|
|
4262
|
-
updateError("3DS authentication required but no token provided.");
|
|
4263
|
-
return;
|
|
4264
|
-
}
|
|
4265
|
-
setIs3DSActive(true);
|
|
4266
|
-
try {
|
|
4267
|
-
const retryBillingAddress = {};
|
|
4268
|
-
const retryCC = selectedCountryRef.current;
|
|
4269
|
-
const retryCountry = enableAVS ? retryCC : effectiveAccount.country;
|
|
4270
|
-
if (retryCountry) retryBillingAddress["country"] = retryCountry;
|
|
4271
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.postal_code, retryCC) && zipCodeRef.current.trim()) {
|
|
4272
|
-
retryBillingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
4273
|
-
} else if (!avsConfig && effectiveAccount.zip) {
|
|
4274
|
-
retryBillingAddress["postal_code"] = effectiveAccount.zip;
|
|
4275
|
-
}
|
|
4276
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.address_line_1, retryCC) && addressLine1Ref.current.trim()) retryBillingAddress["line1"] = addressLine1Ref.current.trim();
|
|
4277
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.address_line_2, retryCC) && addressLine2Ref.current.trim()) retryBillingAddress["line2"] = addressLine2Ref.current.trim();
|
|
4278
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.city, retryCC) && cityRef.current.trim()) retryBillingAddress["city"] = cityRef.current.trim();
|
|
4279
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.state, retryCC) && stateRef.current.trim()) {
|
|
4280
|
-
retryBillingAddress["state"] = stateRef.current.trim();
|
|
4281
|
-
} else if (avsConfig && isAVSFieldVisible(avsConfig.address_line_1, retryCC) && !isAVSFieldVisible(avsConfig.state, retryCC) && isAVSFieldVisible(avsConfig.postal_code, retryCC)) {
|
|
4282
|
-
const derivedRetryState = getStateFromPostalCode(retryCC, zipCodeRef.current.trim());
|
|
4283
|
-
if (derivedRetryState) retryBillingAddress["state"] = derivedRetryState;
|
|
4284
|
-
}
|
|
4285
|
-
const result = await flopay.confirmPayment({
|
|
4286
|
-
clientSecret: secret,
|
|
4287
|
-
returnUrl: window.location.href,
|
|
4288
|
-
billingDetails: {
|
|
4289
|
-
...effectiveAccount.email ? { email: effectiveAccount.email } : {},
|
|
4290
|
-
...fullName.trim() ? { name: fullName.trim() } : {},
|
|
4291
|
-
...Object.keys(retryBillingAddress).length > 0 ? { address: retryBillingAddress } : {}
|
|
4292
|
-
}
|
|
4293
|
-
});
|
|
4294
|
-
if (result.error) {
|
|
4295
|
-
setOverlayStatus("error");
|
|
4296
|
-
updateError(result.error.message);
|
|
4297
|
-
onError?.(result.error);
|
|
4298
|
-
emitDecline("card", result.error);
|
|
4299
|
-
return;
|
|
4300
|
-
}
|
|
4301
|
-
if (result.status === "succeeded" || result.status === "processing") {
|
|
4302
|
-
processingRef.current = false;
|
|
4303
|
-
await processPaymentInternal({
|
|
4304
|
-
id: result.paymentIntentId,
|
|
4305
|
-
type: "card",
|
|
4306
|
-
threeDSecureActionResultTokenId: result.paymentIntentId
|
|
4307
|
-
}, {
|
|
4308
|
-
// Preserve the session/nonce/account overrides resolved
|
|
4309
|
-
// above so the retry talks to the same (possibly
|
|
4310
|
-
// freshly bootstrapped) session as the original attempt.
|
|
4311
|
-
accountPatch: overrides?.accountPatch,
|
|
4312
|
-
sessionId: effectiveSessionId,
|
|
4313
|
-
nonce: effectiveNonce,
|
|
4314
|
-
completionPaymentMethodId: resolvedCompletionPaymentMethodId
|
|
4315
|
-
});
|
|
4316
|
-
}
|
|
4317
|
-
} finally {
|
|
4318
|
-
setIs3DSActive(false);
|
|
4319
|
-
}
|
|
4320
|
-
return;
|
|
4321
|
-
}
|
|
4322
4341
|
if (json?.type === "paypal_redirect_required") {
|
|
4323
4342
|
const secret = json["threeDSecureToken"];
|
|
4324
4343
|
const savedPmId = json["paymentMethodId"] || tokenizedBody.id || "";
|
|
@@ -4372,6 +4391,8 @@ function SplitCardFormInner({
|
|
|
4372
4391
|
emitDecline("paypal", "paypal_direct_required retry limit exceeded");
|
|
4373
4392
|
return;
|
|
4374
4393
|
}
|
|
4394
|
+
setDirectPaypalReady(false);
|
|
4395
|
+
setDirectPaypalInitializationState("loading");
|
|
4375
4396
|
setPaypalDirectRetry({ orderId, attempts: prevAttempts + 1 });
|
|
4376
4397
|
setOverlayStatus(null);
|
|
4377
4398
|
return;
|
|
@@ -4394,7 +4415,7 @@ function SplitCardFormInner({
|
|
|
4394
4415
|
processingRef.current = false;
|
|
4395
4416
|
}
|
|
4396
4417
|
},
|
|
4397
|
-
[baseUrl, sessionId, nonce, resolvedAccount,
|
|
4418
|
+
[baseUrl, sessionId, nonce, resolvedAccount, resolvedBillingName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
|
|
4398
4419
|
);
|
|
4399
4420
|
const dispatchTokenizedBody = useCallback3(
|
|
4400
4421
|
(tokenizedBody, overrides) => {
|
|
@@ -4406,35 +4427,8 @@ function SplitCardFormInner({
|
|
|
4406
4427
|
},
|
|
4407
4428
|
[onTokenizedBody, processPaymentInternal]
|
|
4408
4429
|
);
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
if (!flopay) return;
|
|
4412
|
-
setIs3DSActive(true);
|
|
4413
|
-
try {
|
|
4414
|
-
const result = await flopay.confirmPayment({
|
|
4415
|
-
clientSecret: secret,
|
|
4416
|
-
returnUrl: window.location.href
|
|
4417
|
-
});
|
|
4418
|
-
if (result.error) {
|
|
4419
|
-
updateError(result.error.message);
|
|
4420
|
-
onError?.(result.error);
|
|
4421
|
-
emitDecline("card", result.error);
|
|
4422
|
-
} else if (result.status === "succeeded" || result.status === "processing") {
|
|
4423
|
-
dispatchTokenizedBody({
|
|
4424
|
-
id: result.paymentIntentId,
|
|
4425
|
-
type: "card",
|
|
4426
|
-
threeDSecureActionResultTokenId: result.paymentIntentId
|
|
4427
|
-
});
|
|
4428
|
-
}
|
|
4429
|
-
} catch (err) {
|
|
4430
|
-
updateError(err instanceof Error ? err.message : "Payment authentication failed.");
|
|
4431
|
-
} finally {
|
|
4432
|
-
setIs3DSActive(false);
|
|
4433
|
-
}
|
|
4434
|
-
}
|
|
4435
|
-
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
4436
|
-
const stripeResumeAttemptedRef = useRef5(false);
|
|
4437
|
-
useEffect5(() => {
|
|
4430
|
+
const stripeResumeAttemptedRef = useRef4(false);
|
|
4431
|
+
useEffect4(() => {
|
|
4438
4432
|
if (typeof window === "undefined" || stripeResumeAttemptedRef.current) return;
|
|
4439
4433
|
const params = new URLSearchParams(window.location.search);
|
|
4440
4434
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -4512,166 +4506,12 @@ function SplitCardFormInner({
|
|
|
4512
4506
|
}, persistedOverrides);
|
|
4513
4507
|
})();
|
|
4514
4508
|
}, [sessionId, dispatchTokenizedBody, flopay, updateError, emitDecline]);
|
|
4515
|
-
const handleSubmit = useCallback3(
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
if (vaultActive) return;
|
|
4520
|
-
if (layout !== "buttons") {
|
|
4521
|
-
onButtonClick?.("card");
|
|
4522
|
-
}
|
|
4523
|
-
setProcessing(true);
|
|
4524
|
-
setOverlayStatus("processing");
|
|
4525
|
-
updateError(null);
|
|
4526
|
-
let handedOff = false;
|
|
4527
|
-
try {
|
|
4528
|
-
if (avsConfig) {
|
|
4529
|
-
const country = selectedCountryRef.current;
|
|
4530
|
-
const postal = computePostalCodeState(
|
|
4531
|
-
country,
|
|
4532
|
-
zipCodeRef.current,
|
|
4533
|
-
isAVSFieldVisible(avsConfig.postal_code, country)
|
|
4534
|
-
);
|
|
4535
|
-
if (postal.empty) {
|
|
4536
|
-
setZipTouched(true);
|
|
4537
|
-
updateError(getPostalCodeLabel(country) + " is required");
|
|
4538
|
-
return;
|
|
4539
|
-
}
|
|
4540
|
-
if (postal.malformed) {
|
|
4541
|
-
setZipTouched(true);
|
|
4542
|
-
updateError(malformedPostcodeMessage(country));
|
|
4543
|
-
return;
|
|
4544
|
-
}
|
|
4545
|
-
if (isAVSFieldVisible(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
|
|
4546
|
-
updateError("Street address is required");
|
|
4547
|
-
return;
|
|
4548
|
-
}
|
|
4549
|
-
if (isAVSFieldVisible(avsConfig.city, country) && !cityRef.current.trim()) {
|
|
4550
|
-
updateError("City is required");
|
|
4551
|
-
return;
|
|
4552
|
-
}
|
|
4553
|
-
if (isAVSFieldVisible(avsConfig.state, country) && !stateRef.current.trim()) {
|
|
4554
|
-
updateError(getStateLabel(country) + " is required");
|
|
4555
|
-
return;
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
if (!vaultActive) {
|
|
4559
|
-
const submitResult = await flopay.submitElements();
|
|
4560
|
-
if (submitResult.error) {
|
|
4561
|
-
updateError(submitResult.error.message);
|
|
4562
|
-
onError?.(submitResult.error);
|
|
4563
|
-
return;
|
|
4564
|
-
}
|
|
4565
|
-
}
|
|
4566
|
-
const billingAddress = {};
|
|
4567
|
-
const cc = selectedCountryRef.current;
|
|
4568
|
-
const avsCountry = enableAVS ? cc : resolvedAccount.country;
|
|
4569
|
-
if (avsCountry) billingAddress["country"] = avsCountry;
|
|
4570
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.postal_code, cc) && zipCodeRef.current.trim()) {
|
|
4571
|
-
billingAddress["postal_code"] = zipCodeRef.current.trim();
|
|
4572
|
-
} else if (!avsConfig && resolvedAccount.zip) {
|
|
4573
|
-
billingAddress["postal_code"] = resolvedAccount.zip;
|
|
4574
|
-
}
|
|
4575
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.address_line_1, cc) && addressLine1Ref.current.trim()) billingAddress["line1"] = addressLine1Ref.current.trim();
|
|
4576
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.address_line_2, cc) && addressLine2Ref.current.trim()) billingAddress["line2"] = addressLine2Ref.current.trim();
|
|
4577
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.city, cc) && cityRef.current.trim()) billingAddress["city"] = cityRef.current.trim();
|
|
4578
|
-
if (avsConfig && isAVSFieldVisible(avsConfig.state, cc) && stateRef.current.trim()) {
|
|
4579
|
-
billingAddress["state"] = stateRef.current.trim();
|
|
4580
|
-
} else if (avsConfig && isAVSFieldVisible(avsConfig.address_line_1, cc) && !isAVSFieldVisible(avsConfig.state, cc) && isAVSFieldVisible(avsConfig.postal_code, cc)) {
|
|
4581
|
-
const derivedSubmitState = getStateFromPostalCode(cc, zipCodeRef.current.trim());
|
|
4582
|
-
if (derivedSubmitState) billingAddress["state"] = derivedSubmitState;
|
|
4583
|
-
}
|
|
4584
|
-
const billingDetails = {
|
|
4585
|
-
...resolvedAccount.email ? { email: resolvedAccount.email } : {},
|
|
4586
|
-
...fullName.trim() ? { name: fullName.trim() } : {},
|
|
4587
|
-
...Object.keys(billingAddress).length > 0 ? { address: billingAddress } : {}
|
|
4588
|
-
};
|
|
4589
|
-
if (!sessionId || !resolvedAccount.email) {
|
|
4590
|
-
throw new FloPayError3("Missing sessionId or email", "validation_error");
|
|
4591
|
-
}
|
|
4592
|
-
{
|
|
4593
|
-
const pmResult = await flopay.createPaymentMethod(billingDetails);
|
|
4594
|
-
if (pmResult.error || !pmResult.paymentMethodId) {
|
|
4595
|
-
updateError(pmResult.error?.message ?? "Failed to create payment method.");
|
|
4596
|
-
return;
|
|
4597
|
-
}
|
|
4598
|
-
const intentHeaders = intentRequestHeaders(nonce);
|
|
4599
|
-
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
4600
|
-
method: "POST",
|
|
4601
|
-
headers: intentHeaders,
|
|
4602
|
-
body: JSON.stringify({
|
|
4603
|
-
sessionId,
|
|
4604
|
-
email: resolvedAccount.email,
|
|
4605
|
-
paymentMethodType: pmResult.paymentMethodId,
|
|
4606
|
-
isPaypal: false
|
|
4607
|
-
})
|
|
4608
|
-
});
|
|
4609
|
-
if (!intentResponse.ok) {
|
|
4610
|
-
const intentError = await buildFloPayApiErrorFromResponse(
|
|
4611
|
-
intentResponse,
|
|
4612
|
-
"Failed to create payment intent"
|
|
4613
|
-
);
|
|
4614
|
-
setOverlayStatus("error");
|
|
4615
|
-
updateError(intentError.message);
|
|
4616
|
-
onError?.(intentError);
|
|
4617
|
-
emitDecline("card", intentError);
|
|
4618
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
4619
|
-
return;
|
|
4620
|
-
}
|
|
4621
|
-
const intentJson = await intentResponse.json();
|
|
4622
|
-
const intentClientSecret = intentJson.data?.id;
|
|
4623
|
-
if (!intentClientSecret) throw new FloPayError3("No client_secret in payment intent response", "api_error");
|
|
4624
|
-
const confirmResult = await flopay.confirmCardPayment({
|
|
4625
|
-
clientSecret: intentClientSecret,
|
|
4626
|
-
paymentMethodId: pmResult.paymentMethodId
|
|
4627
|
-
});
|
|
4628
|
-
if (confirmResult.error) {
|
|
4629
|
-
setOverlayStatus("error");
|
|
4630
|
-
updateError(confirmResult.error.message);
|
|
4631
|
-
onError?.(confirmResult.error);
|
|
4632
|
-
emitDecline("card", confirmResult.error);
|
|
4633
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
4634
|
-
return;
|
|
4635
|
-
}
|
|
4636
|
-
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
4637
|
-
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
4638
|
-
rawProvider,
|
|
4639
|
-
intentClientSecret
|
|
4640
|
-
);
|
|
4641
|
-
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
4642
|
-
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
4643
|
-
if (!paymentIntentId) {
|
|
4644
|
-
const error2 = new FloPayError3("No payment intent returned after confirmation.", "api_error");
|
|
4645
|
-
setOverlayStatus("error");
|
|
4646
|
-
updateError(error2.message);
|
|
4647
|
-
onError?.(error2);
|
|
4648
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
4649
|
-
return;
|
|
4650
|
-
}
|
|
4651
|
-
handedOff = isSelfContained;
|
|
4652
|
-
dispatchTokenizedBody({
|
|
4653
|
-
id: paymentMethodId,
|
|
4654
|
-
type: "card",
|
|
4655
|
-
threeDSecureActionResultTokenId: paymentIntentId,
|
|
4656
|
-
originalPaymentMethodId: pmResult.paymentMethodId
|
|
4657
|
-
});
|
|
4658
|
-
}
|
|
4659
|
-
} catch (err) {
|
|
4660
|
-
setOverlayStatus("error");
|
|
4661
|
-
updateError(err instanceof Error ? err.message : "An unexpected error occurred");
|
|
4662
|
-
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
4663
|
-
} finally {
|
|
4664
|
-
if (!handedOff) {
|
|
4665
|
-
setProcessing(false);
|
|
4666
|
-
setOverlayStatus(null);
|
|
4667
|
-
}
|
|
4668
|
-
}
|
|
4669
|
-
},
|
|
4670
|
-
[flopay, elements, isSubmitting, sessionId, nonce, resolvedAccount.email, baseUrl, isSelfContained, vaultActive, dispatchTokenizedBody, onButtonClick, onError, updateError, emitDecline, layout]
|
|
4671
|
-
);
|
|
4672
|
-
const isReady = flopay !== null && (vaultActive || elements !== null);
|
|
4509
|
+
const handleSubmit = useCallback3((event) => {
|
|
4510
|
+
event.preventDefault();
|
|
4511
|
+
}, []);
|
|
4512
|
+
const isReady = flopay !== null;
|
|
4673
4513
|
if (!isReady) {
|
|
4674
|
-
return /* @__PURE__ */
|
|
4514
|
+
return /* @__PURE__ */ jsx7("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
|
|
4675
4515
|
}
|
|
4676
4516
|
const isButtons = layout === "buttons";
|
|
4677
4517
|
const appearanceVars = appearance?.variables;
|
|
@@ -4712,25 +4552,10 @@ function SplitCardFormInner({
|
|
|
4712
4552
|
"--flopay-input-font-family": resolvedInputFontFamily,
|
|
4713
4553
|
"--flopay-input-font-weight": String(resolvedInputFontWeight)
|
|
4714
4554
|
};
|
|
4715
|
-
const stripeElementStyle = {
|
|
4716
|
-
style: {
|
|
4717
|
-
base: {
|
|
4718
|
-
...sharedInputTypography,
|
|
4719
|
-
fontSmoothing: "antialiased",
|
|
4720
|
-
"::placeholder": {
|
|
4721
|
-
color: resolvedPlaceholderColor,
|
|
4722
|
-
fontSize: resolvedInputFontSize,
|
|
4723
|
-
fontFamily: resolvedInputFontFamily,
|
|
4724
|
-
fontWeight: resolvedInputFontWeight
|
|
4725
|
-
}
|
|
4726
|
-
},
|
|
4727
|
-
invalid: { color: "#ef4444" }
|
|
4728
|
-
}
|
|
4729
|
-
};
|
|
4730
4555
|
const containerOverrides = bStyles.cardFormContainer ?? {};
|
|
4731
4556
|
const containerPadding = containerOverrides.padding ?? (isButtons ? "0" : "1rem");
|
|
4732
4557
|
const containerRadius = containerOverrides.borderRadius ?? resolvedBorderRadius;
|
|
4733
|
-
const vaultCardFieldsNode = cardCapture && vaultMount ? /* @__PURE__ */
|
|
4558
|
+
const vaultCardFieldsNode = cardCapture && vaultMount ? /* @__PURE__ */ jsx7(
|
|
4734
4559
|
VaultCardFields,
|
|
4735
4560
|
{
|
|
4736
4561
|
capture: cardCapture,
|
|
@@ -4739,7 +4564,6 @@ function SplitCardFormInner({
|
|
|
4739
4564
|
expectedOrigin: vaultMount.expectedOrigin,
|
|
4740
4565
|
theme: vaultThemeColors,
|
|
4741
4566
|
onReady: () => {
|
|
4742
|
-
setFormReady(true);
|
|
4743
4567
|
if (!avsConfig || typeof document === "undefined") return;
|
|
4744
4568
|
const focusFirstAvs = () => {
|
|
4745
4569
|
const block = document.querySelector('[data-testid="flopay-avs-fields"]');
|
|
@@ -4768,7 +4592,7 @@ function SplitCardFormInner({
|
|
|
4768
4592
|
if (message) setOverlayStatus(null);
|
|
4769
4593
|
}
|
|
4770
4594
|
}
|
|
4771
|
-
) : /* @__PURE__ */
|
|
4595
|
+
) : /* @__PURE__ */ jsx7(
|
|
4772
4596
|
"div",
|
|
4773
4597
|
{
|
|
4774
4598
|
"data-testid": "flopay-vault-loading",
|
|
@@ -4796,7 +4620,7 @@ function SplitCardFormInner({
|
|
|
4796
4620
|
display: "flex",
|
|
4797
4621
|
flexDirection: "column"
|
|
4798
4622
|
}, children: [
|
|
4799
|
-
/* @__PURE__ */
|
|
4623
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
4800
4624
|
.flopay-shared-input::placeholder {
|
|
4801
4625
|
color: var(--flopay-input-placeholder-color);
|
|
4802
4626
|
opacity: 1;
|
|
@@ -4834,7 +4658,7 @@ function SplitCardFormInner({
|
|
|
4834
4658
|
},
|
|
4835
4659
|
"aria-label": "Back to payment methods",
|
|
4836
4660
|
children: [
|
|
4837
|
-
/* @__PURE__ */
|
|
4661
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
4838
4662
|
display: "inline-flex",
|
|
4839
4663
|
alignItems: "center",
|
|
4840
4664
|
justifyContent: "center",
|
|
@@ -4844,12 +4668,12 @@ function SplitCardFormInner({
|
|
|
4844
4668
|
backgroundColor: "#f3f4f6",
|
|
4845
4669
|
transition: "background-color 0.15s",
|
|
4846
4670
|
...bStyles.backButtonIcon
|
|
4847
|
-
}, children: /* @__PURE__ */
|
|
4848
|
-
/* @__PURE__ */
|
|
4671
|
+
}, 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" }) }) }),
|
|
4672
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
4849
4673
|
]
|
|
4850
4674
|
}
|
|
4851
4675
|
),
|
|
4852
|
-
hideTitle ? /* @__PURE__ */
|
|
4676
|
+
hideTitle ? /* @__PURE__ */ jsx7("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx7("div", { style: {
|
|
4853
4677
|
flex: 1,
|
|
4854
4678
|
textAlign: "center",
|
|
4855
4679
|
fontWeight: 600,
|
|
@@ -4857,9 +4681,9 @@ function SplitCardFormInner({
|
|
|
4857
4681
|
color: "#262833",
|
|
4858
4682
|
paddingRight: 80,
|
|
4859
4683
|
...bStyles.title
|
|
4860
|
-
}, children: /* @__PURE__ */
|
|
4684
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) })
|
|
4861
4685
|
] }),
|
|
4862
|
-
!isButtons && !hideTitle && /* @__PURE__ */
|
|
4686
|
+
!isButtons && !hideTitle && /* @__PURE__ */ jsx7("div", { style: {
|
|
4863
4687
|
textAlign: "center",
|
|
4864
4688
|
fontWeight: 600,
|
|
4865
4689
|
fontSize: "1.1rem",
|
|
@@ -4869,70 +4693,8 @@ function SplitCardFormInner({
|
|
|
4869
4693
|
// (-2) and AVS block (-1) are ordered below it but above the card form.
|
|
4870
4694
|
order: vaultActive ? -3 : 0,
|
|
4871
4695
|
...bStyles.title
|
|
4872
|
-
}, children: /* @__PURE__ */
|
|
4873
|
-
|
|
4874
|
-
/* @__PURE__ */ jsx8("div", { style: {
|
|
4875
|
-
backgroundColor: cardInputBg,
|
|
4876
|
-
border: `1px solid ${resolvedBorder}`,
|
|
4877
|
-
borderTopLeftRadius: resolvedBorderRadius,
|
|
4878
|
-
borderTopRightRadius: resolvedBorderRadius,
|
|
4879
|
-
padding: "10px"
|
|
4880
|
-
}, children: /* @__PURE__ */ jsx8(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
|
|
4881
|
-
/* @__PURE__ */ jsxs5("div", { style: { display: "flex" }, children: [
|
|
4882
|
-
/* @__PURE__ */ jsx8("div", { style: {
|
|
4883
|
-
flex: 1,
|
|
4884
|
-
backgroundColor: cardInputBg,
|
|
4885
|
-
// Longhand only — mixing `border` shorthand with per-side
|
|
4886
|
-
// overrides triggers React's "shorthand vs longhand" warning
|
|
4887
|
-
// because render order isn't deterministic.
|
|
4888
|
-
borderTop: "none",
|
|
4889
|
-
borderRight: "none",
|
|
4890
|
-
borderBottom: `1px solid ${resolvedBorder}`,
|
|
4891
|
-
borderLeft: `1px solid ${resolvedBorder}`,
|
|
4892
|
-
borderBottomLeftRadius: resolvedBorderRadius,
|
|
4893
|
-
padding: "10px"
|
|
4894
|
-
}, children: /* @__PURE__ */ jsx8(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
4895
|
-
/* @__PURE__ */ jsx8("div", { style: {
|
|
4896
|
-
flex: 1,
|
|
4897
|
-
backgroundColor: cardInputBg,
|
|
4898
|
-
borderTop: "none",
|
|
4899
|
-
borderRight: `1px solid ${resolvedBorder}`,
|
|
4900
|
-
borderBottom: `1px solid ${resolvedBorder}`,
|
|
4901
|
-
borderLeft: `1px solid ${resolvedBorder}`,
|
|
4902
|
-
borderBottomRightRadius: resolvedBorderRadius,
|
|
4903
|
-
padding: "10px"
|
|
4904
|
-
}, children: /* @__PURE__ */ jsx8(CardCvcElement, { options: stripeElementStyle }) })
|
|
4905
|
-
] })
|
|
4906
|
-
] }),
|
|
4907
|
-
!vaultActive && /* @__PURE__ */ jsx8("div", { style: {
|
|
4908
|
-
backgroundColor: cardInputBg,
|
|
4909
|
-
border: `1px solid ${resolvedBorder}`,
|
|
4910
|
-
borderRadius: resolvedBorderRadius,
|
|
4911
|
-
marginTop: "0.5rem",
|
|
4912
|
-
padding: "10px"
|
|
4913
|
-
}, children: /* @__PURE__ */ jsx8(
|
|
4914
|
-
"input",
|
|
4915
|
-
{
|
|
4916
|
-
className: "flopay-shared-input",
|
|
4917
|
-
id: "flopay-cc-name",
|
|
4918
|
-
name: "cc-name",
|
|
4919
|
-
placeholder: "Full Name on Card",
|
|
4920
|
-
autoComplete: "cc-name",
|
|
4921
|
-
value: fullName,
|
|
4922
|
-
onChange: (e) => handleNameChange(e.target.value),
|
|
4923
|
-
disabled: isSubmitting,
|
|
4924
|
-
required: true,
|
|
4925
|
-
style: {
|
|
4926
|
-
width: "100%",
|
|
4927
|
-
border: "none",
|
|
4928
|
-
outline: "none",
|
|
4929
|
-
background: "transparent",
|
|
4930
|
-
...sharedInputTypography,
|
|
4931
|
-
...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
|
|
4932
|
-
}
|
|
4933
|
-
}
|
|
4934
|
-
) }),
|
|
4935
|
-
avsConfig && /* @__PURE__ */ jsx8("div", { style: { order: vaultActive ? -1 : 0 }, "data-testid": "flopay-avs-fields", children: (() => {
|
|
4696
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) }),
|
|
4697
|
+
avsConfig && /* @__PURE__ */ jsx7("div", { style: { order: vaultActive ? -1 : 0 }, "data-testid": "flopay-avs-fields", children: (() => {
|
|
4936
4698
|
const cc = selectedCountry;
|
|
4937
4699
|
const inputWrapStyle = (invalid = false) => ({
|
|
4938
4700
|
backgroundColor: cardInputBg,
|
|
@@ -4950,7 +4712,7 @@ function SplitCardFormInner({
|
|
|
4950
4712
|
});
|
|
4951
4713
|
const stateOpts = getStateOptions(cc);
|
|
4952
4714
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
4953
|
-
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */
|
|
4715
|
+
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(invalidAvsFields.line1), children: /* @__PURE__ */ jsx7(
|
|
4954
4716
|
"input",
|
|
4955
4717
|
{
|
|
4956
4718
|
className: "flopay-shared-input",
|
|
@@ -4969,7 +4731,7 @@ function SplitCardFormInner({
|
|
|
4969
4731
|
style: inputFieldStyle()
|
|
4970
4732
|
}
|
|
4971
4733
|
) }),
|
|
4972
|
-
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */
|
|
4734
|
+
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(), children: /* @__PURE__ */ jsx7(
|
|
4973
4735
|
"input",
|
|
4974
4736
|
{
|
|
4975
4737
|
className: "flopay-shared-input",
|
|
@@ -4992,7 +4754,7 @@ function SplitCardFormInner({
|
|
|
4992
4754
|
gap: "0",
|
|
4993
4755
|
marginTop: "0.5rem"
|
|
4994
4756
|
}, children: [
|
|
4995
|
-
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */
|
|
4757
|
+
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
4996
4758
|
flex: 1,
|
|
4997
4759
|
backgroundColor: cardInputBg,
|
|
4998
4760
|
borderTop: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
@@ -5003,7 +4765,7 @@ function SplitCardFormInner({
|
|
|
5003
4765
|
borderTopLeftRadius: resolvedBorderRadius,
|
|
5004
4766
|
borderBottomLeftRadius: resolvedBorderRadius,
|
|
5005
4767
|
...isAVSFieldVisible(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: resolvedBorderRadius }
|
|
5006
|
-
}, children: /* @__PURE__ */
|
|
4768
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5007
4769
|
"input",
|
|
5008
4770
|
{
|
|
5009
4771
|
className: "flopay-shared-input",
|
|
@@ -5022,7 +4784,7 @@ function SplitCardFormInner({
|
|
|
5022
4784
|
style: inputFieldStyle()
|
|
5023
4785
|
}
|
|
5024
4786
|
) }),
|
|
5025
|
-
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */
|
|
4787
|
+
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5026
4788
|
flex: 1,
|
|
5027
4789
|
backgroundColor: cardInputBg,
|
|
5028
4790
|
border: `1px solid ${avsBorderColor(invalidAvsFields.state)}`,
|
|
@@ -5046,11 +4808,11 @@ function SplitCardFormInner({
|
|
|
5046
4808
|
"data-testid": "flopay-state",
|
|
5047
4809
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
5048
4810
|
children: [
|
|
5049
|
-
/* @__PURE__ */
|
|
5050
|
-
stateOpts.map((s) => /* @__PURE__ */
|
|
4811
|
+
/* @__PURE__ */ jsx7("option", { value: "", children: getStateLabel(cc) }),
|
|
4812
|
+
stateOpts.map((s) => /* @__PURE__ */ jsx7("option", { value: s.code, children: s.name }, s.code))
|
|
5051
4813
|
]
|
|
5052
4814
|
}
|
|
5053
|
-
) : /* @__PURE__ */
|
|
4815
|
+
) : /* @__PURE__ */ jsx7(
|
|
5054
4816
|
"input",
|
|
5055
4817
|
{
|
|
5056
4818
|
className: "flopay-shared-input",
|
|
@@ -5076,7 +4838,7 @@ function SplitCardFormInner({
|
|
|
5076
4838
|
gap: avsLayoutProp === "column" ? "0.5rem" : "0",
|
|
5077
4839
|
marginTop: "0.5rem"
|
|
5078
4840
|
}, children: [
|
|
5079
|
-
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */
|
|
4841
|
+
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5080
4842
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
5081
4843
|
backgroundColor: cardInputBg,
|
|
5082
4844
|
borderTop: `1px solid ${resolvedBorder}`,
|
|
@@ -5085,7 +4847,7 @@ function SplitCardFormInner({
|
|
|
5085
4847
|
borderLeft: `1px solid ${resolvedBorder}`,
|
|
5086
4848
|
padding: "10px",
|
|
5087
4849
|
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: resolvedBorderRadius, borderBottomLeftRadius: resolvedBorderRadius, borderRight: "none" } : { borderRadius: resolvedBorderRadius }
|
|
5088
|
-
}, children: /* @__PURE__ */
|
|
4850
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5089
4851
|
"select",
|
|
5090
4852
|
{
|
|
5091
4853
|
id: "flopay-billing-country",
|
|
@@ -5109,13 +4871,13 @@ function SplitCardFormInner({
|
|
|
5109
4871
|
] }, c.code))
|
|
5110
4872
|
}
|
|
5111
4873
|
) }),
|
|
5112
|
-
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */
|
|
4874
|
+
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5113
4875
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
5114
4876
|
backgroundColor: cardInputBg,
|
|
5115
4877
|
border: `1px solid ${zipBorderColor}`,
|
|
5116
4878
|
padding: "10px",
|
|
5117
4879
|
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: resolvedBorderRadius, borderBottomRightRadius: resolvedBorderRadius } : { borderRadius: resolvedBorderRadius }
|
|
5118
|
-
}, children: /* @__PURE__ */
|
|
4880
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5119
4881
|
"input",
|
|
5120
4882
|
{
|
|
5121
4883
|
className: "flopay-shared-input",
|
|
@@ -5139,7 +4901,7 @@ function SplitCardFormInner({
|
|
|
5139
4901
|
}
|
|
5140
4902
|
) })
|
|
5141
4903
|
] }),
|
|
5142
|
-
showPostcodeError && /* @__PURE__ */
|
|
4904
|
+
showPostcodeError && /* @__PURE__ */ jsx7(
|
|
5143
4905
|
"div",
|
|
5144
4906
|
{
|
|
5145
4907
|
id: "flopay-billing-postal-code-error",
|
|
@@ -5156,39 +4918,9 @@ function SplitCardFormInner({
|
|
|
5156
4918
|
)
|
|
5157
4919
|
] });
|
|
5158
4920
|
})() }),
|
|
5159
|
-
vaultActive && cardPreFormSlot && /* @__PURE__ */
|
|
4921
|
+
vaultActive && cardPreFormSlot && /* @__PURE__ */ jsx7("div", { style: { order: -2, width: "100%" }, children: cardPreFormSlot }),
|
|
5160
4922
|
vaultActive && vaultCardFieldsNode,
|
|
5161
|
-
displayError && /* @__PURE__ */
|
|
5162
|
-
!vaultActive && (children ?? /* @__PURE__ */ jsx8(
|
|
5163
|
-
"button",
|
|
5164
|
-
{
|
|
5165
|
-
type: "submit",
|
|
5166
|
-
disabled: !formReady || isSubmitting,
|
|
5167
|
-
"data-testid": "flopay-submit",
|
|
5168
|
-
onMouseEnter: (e) => {
|
|
5169
|
-
if (formReady && !isSubmitting) e.currentTarget.style.backgroundColor = resolvedPrimaryHoverColor;
|
|
5170
|
-
},
|
|
5171
|
-
onMouseLeave: (e) => {
|
|
5172
|
-
e.currentTarget.style.backgroundColor = bStyles.submitButton?.backgroundColor ?? resolvedPrimaryColor;
|
|
5173
|
-
},
|
|
5174
|
-
style: {
|
|
5175
|
-
width: "100%",
|
|
5176
|
-
padding: "0.875rem",
|
|
5177
|
-
marginTop: "1rem",
|
|
5178
|
-
backgroundColor: resolvedPrimaryColor,
|
|
5179
|
-
color: "white",
|
|
5180
|
-
border: "none",
|
|
5181
|
-
borderRadius: resolvedBorderRadius,
|
|
5182
|
-
fontSize: bStyles.submitButtonFontSize ?? "1rem",
|
|
5183
|
-
fontWeight: 600,
|
|
5184
|
-
cursor: !formReady || isSubmitting ? "not-allowed" : "pointer",
|
|
5185
|
-
opacity: !formReady || isSubmitting ? 0.5 : 1,
|
|
5186
|
-
transition: "background-color 0.15s",
|
|
5187
|
-
...bStyles.submitButton
|
|
5188
|
-
},
|
|
5189
|
-
children: isSubmitting ? "PROCESSING..." : submitLabel
|
|
5190
|
-
}
|
|
5191
|
-
))
|
|
4923
|
+
displayError && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.75rem 0", styleOverride: bStyles.errorBanner, children: displayError })
|
|
5192
4924
|
] });
|
|
5193
4925
|
const gateDebugStyle = {
|
|
5194
4926
|
margin: 0,
|
|
@@ -5204,9 +4936,9 @@ function SplitCardFormInner({
|
|
|
5204
4936
|
const renderDirectPaypalGateDebug = (testId) => {
|
|
5205
4937
|
if (!debug) return null;
|
|
5206
4938
|
if (!showPayPal || !directPaypalConfigured) {
|
|
5207
|
-
return /* @__PURE__ */
|
|
4939
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/DirectPayPal-debug - not enabled" });
|
|
5208
4940
|
}
|
|
5209
|
-
return /* @__PURE__ */
|
|
4941
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
5210
4942
|
"FloPay/DirectPayPal-debug (parent gate)",
|
|
5211
4943
|
` showPayPal=${showPayPal}`,
|
|
5212
4944
|
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
@@ -5219,9 +4951,9 @@ function SplitCardFormInner({
|
|
|
5219
4951
|
const renderStripeGateDebug = (testId) => {
|
|
5220
4952
|
if (!debug) return null;
|
|
5221
4953
|
if (!showStripe || !stripeInstance) {
|
|
5222
|
-
return /* @__PURE__ */
|
|
4954
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/Stripe-debug - not enabled" });
|
|
5223
4955
|
}
|
|
5224
|
-
return /* @__PURE__ */
|
|
4956
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
5225
4957
|
"FloPay/Stripe-debug (parent gate)",
|
|
5226
4958
|
` showStripe=${showStripe}`,
|
|
5227
4959
|
` currency=${currency}`,
|
|
@@ -5251,8 +4983,8 @@ function SplitCardFormInner({
|
|
|
5251
4983
|
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;
|
|
5252
4984
|
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;
|
|
5253
4985
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5254
|
-
/* @__PURE__ */
|
|
5255
|
-
overlayStatus && /* @__PURE__ */
|
|
4986
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
4987
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5256
4988
|
/* @__PURE__ */ jsxs5("div", { style: { display: "grid" }, children: [
|
|
5257
4989
|
/* @__PURE__ */ jsxs5(
|
|
5258
4990
|
"div",
|
|
@@ -5272,7 +5004,7 @@ function SplitCardFormInner({
|
|
|
5272
5004
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug"),
|
|
5273
5005
|
renderStripeGateDebug("flopay-stripe-gate-debug"),
|
|
5274
5006
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
5275
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
5007
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
5276
5008
|
"div",
|
|
5277
5009
|
{
|
|
5278
5010
|
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
@@ -5288,7 +5020,7 @@ function SplitCardFormInner({
|
|
|
5288
5020
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
5289
5021
|
}
|
|
5290
5022
|
),
|
|
5291
|
-
/* @__PURE__ */
|
|
5023
|
+
/* @__PURE__ */ jsx7(
|
|
5292
5024
|
DirectPayPalButton,
|
|
5293
5025
|
{
|
|
5294
5026
|
sessionId,
|
|
@@ -5308,6 +5040,7 @@ function SplitCardFormInner({
|
|
|
5308
5040
|
runBeforeButtonClick,
|
|
5309
5041
|
isProcessing: isSubmitting,
|
|
5310
5042
|
onLoadStateChange: setDirectPaypalReady,
|
|
5043
|
+
onInitializationStateChange: setDirectPaypalInitializationState,
|
|
5311
5044
|
session: session ?? null,
|
|
5312
5045
|
existingOrderId: paypalDirectRetry?.orderId,
|
|
5313
5046
|
debug
|
|
@@ -5315,7 +5048,7 @@ function SplitCardFormInner({
|
|
|
5315
5048
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
5316
5049
|
)
|
|
5317
5050
|
] }),
|
|
5318
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
5051
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
5319
5052
|
PayPalButtonInner,
|
|
5320
5053
|
{
|
|
5321
5054
|
sessionId,
|
|
@@ -5333,13 +5066,14 @@ function SplitCardFormInner({
|
|
|
5333
5066
|
placeholderBorderRadius: buttonBorderRadius
|
|
5334
5067
|
}
|
|
5335
5068
|
) }),
|
|
5336
|
-
shouldRenderWallets ? /* @__PURE__ */
|
|
5069
|
+
shouldRenderWallets ? /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
5337
5070
|
WalletButtonInner,
|
|
5338
5071
|
{
|
|
5339
5072
|
sessionId,
|
|
5340
5073
|
nonce,
|
|
5341
5074
|
email: resolvedAccount.email,
|
|
5342
5075
|
billingApiUrl: resolvedBillingApiUrl,
|
|
5076
|
+
intentKind: totalAmount > 0 ? "payment" : "setup",
|
|
5343
5077
|
expressMethods: walletExpressMethods,
|
|
5344
5078
|
onTokenizedBody: dispatchTokenizedBody,
|
|
5345
5079
|
onErrorChange: updateError,
|
|
@@ -5350,8 +5084,8 @@ function SplitCardFormInner({
|
|
|
5350
5084
|
onLoadStateChange: setWalletLoadState,
|
|
5351
5085
|
placeholderBorderRadius: buttonBorderRadius
|
|
5352
5086
|
}
|
|
5353
|
-
) }) : shouldShowWallets ? /* @__PURE__ */
|
|
5354
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
5087
|
+
) }) : 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,
|
|
5088
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
5355
5089
|
StripePaymentElementInner,
|
|
5356
5090
|
{
|
|
5357
5091
|
sessionId,
|
|
@@ -5383,7 +5117,7 @@ function SplitCardFormInner({
|
|
|
5383
5117
|
}
|
|
5384
5118
|
}
|
|
5385
5119
|
),
|
|
5386
|
-
|
|
5120
|
+
vaultActive && /* @__PURE__ */ jsx7(
|
|
5387
5121
|
"button",
|
|
5388
5122
|
{
|
|
5389
5123
|
type: "button",
|
|
@@ -5439,19 +5173,19 @@ function SplitCardFormInner({
|
|
|
5439
5173
|
onMouseUp: (e) => {
|
|
5440
5174
|
e.currentTarget.style.transform = "scale(1)";
|
|
5441
5175
|
},
|
|
5442
|
-
children: /* @__PURE__ */
|
|
5176
|
+
children: /* @__PURE__ */ jsx7(CardButtonContentSlot, { content: cardButtonContent })
|
|
5443
5177
|
}
|
|
5444
5178
|
),
|
|
5445
|
-
displayError && viewState === "buttons" && /* @__PURE__ */
|
|
5179
|
+
displayError && viewState === "buttons" && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.25rem 0", styleOverride: bStyles.errorBanner, children: displayError })
|
|
5446
5180
|
]
|
|
5447
5181
|
}
|
|
5448
5182
|
),
|
|
5449
|
-
|
|
5183
|
+
vaultActive && isCardView && /* @__PURE__ */ jsx7("div", { style: {
|
|
5450
5184
|
gridArea: "1 / 1",
|
|
5451
5185
|
...cardAnim ? { animation: cardAnim } : {},
|
|
5452
5186
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
5453
5187
|
}, children: cardFormBlock }),
|
|
5454
|
-
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */
|
|
5188
|
+
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */ jsx7("div", { style: {
|
|
5455
5189
|
gridArea: "1 / 1",
|
|
5456
5190
|
...apmAnim ? { animation: apmAnim } : {},
|
|
5457
5191
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
@@ -5489,7 +5223,7 @@ function SplitCardFormInner({
|
|
|
5489
5223
|
},
|
|
5490
5224
|
"aria-label": "Back to payment methods",
|
|
5491
5225
|
children: [
|
|
5492
|
-
/* @__PURE__ */
|
|
5226
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
5493
5227
|
display: "inline-flex",
|
|
5494
5228
|
alignItems: "center",
|
|
5495
5229
|
justifyContent: "center",
|
|
@@ -5499,12 +5233,12 @@ function SplitCardFormInner({
|
|
|
5499
5233
|
backgroundColor: "#f3f4f6",
|
|
5500
5234
|
transition: "background-color 0.15s",
|
|
5501
5235
|
...bStyles.backButtonIcon
|
|
5502
|
-
}, children: /* @__PURE__ */
|
|
5503
|
-
/* @__PURE__ */
|
|
5236
|
+
}, 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" }) }) }),
|
|
5237
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
5504
5238
|
]
|
|
5505
5239
|
}
|
|
5506
5240
|
),
|
|
5507
|
-
/* @__PURE__ */
|
|
5241
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5508
5242
|
flex: 1,
|
|
5509
5243
|
textAlign: "center",
|
|
5510
5244
|
fontWeight: 600,
|
|
@@ -5514,12 +5248,12 @@ function SplitCardFormInner({
|
|
|
5514
5248
|
...bStyles.title
|
|
5515
5249
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
5516
5250
|
] }),
|
|
5517
|
-
/* @__PURE__ */
|
|
5251
|
+
/* @__PURE__ */ jsx7(
|
|
5518
5252
|
StripeElements,
|
|
5519
5253
|
{
|
|
5520
5254
|
stripe: stripeInstance,
|
|
5521
5255
|
options: apmInlineOptions,
|
|
5522
|
-
children: /* @__PURE__ */
|
|
5256
|
+
children: /* @__PURE__ */ jsx7(
|
|
5523
5257
|
StripeMethodInlineForm,
|
|
5524
5258
|
{
|
|
5525
5259
|
method: expandedApmMethod,
|
|
@@ -5550,9 +5284,9 @@ function SplitCardFormInner({
|
|
|
5550
5284
|
}
|
|
5551
5285
|
if (isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && showStripe) {
|
|
5552
5286
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5553
|
-
/* @__PURE__ */
|
|
5554
|
-
overlayStatus && /* @__PURE__ */
|
|
5555
|
-
/* @__PURE__ */
|
|
5287
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
5288
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5289
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5556
5290
|
...apmAnim ? { animation: apmAnim } : {},
|
|
5557
5291
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
5558
5292
|
}, children: /* @__PURE__ */ jsxs5("div", { style: {
|
|
@@ -5589,7 +5323,7 @@ function SplitCardFormInner({
|
|
|
5589
5323
|
},
|
|
5590
5324
|
"aria-label": "Back to payment methods",
|
|
5591
5325
|
children: [
|
|
5592
|
-
/* @__PURE__ */
|
|
5326
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
5593
5327
|
display: "inline-flex",
|
|
5594
5328
|
alignItems: "center",
|
|
5595
5329
|
justifyContent: "center",
|
|
@@ -5599,12 +5333,12 @@ function SplitCardFormInner({
|
|
|
5599
5333
|
backgroundColor: "#f3f4f6",
|
|
5600
5334
|
transition: "background-color 0.15s",
|
|
5601
5335
|
...bStyles.backButtonIcon
|
|
5602
|
-
}, children: /* @__PURE__ */
|
|
5603
|
-
/* @__PURE__ */
|
|
5336
|
+
}, 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" }) }) }),
|
|
5337
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
5604
5338
|
]
|
|
5605
5339
|
}
|
|
5606
5340
|
),
|
|
5607
|
-
/* @__PURE__ */
|
|
5341
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5608
5342
|
flex: 1,
|
|
5609
5343
|
textAlign: "center",
|
|
5610
5344
|
fontWeight: 600,
|
|
@@ -5614,12 +5348,12 @@ function SplitCardFormInner({
|
|
|
5614
5348
|
...bStyles.title
|
|
5615
5349
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
5616
5350
|
] }),
|
|
5617
|
-
/* @__PURE__ */
|
|
5351
|
+
/* @__PURE__ */ jsx7(
|
|
5618
5352
|
StripeElements,
|
|
5619
5353
|
{
|
|
5620
5354
|
stripe: stripeInstance,
|
|
5621
5355
|
options: apmInlineOptions,
|
|
5622
|
-
children: /* @__PURE__ */
|
|
5356
|
+
children: /* @__PURE__ */ jsx7(
|
|
5623
5357
|
StripeMethodInlineForm,
|
|
5624
5358
|
{
|
|
5625
5359
|
method: expandedApmMethod,
|
|
@@ -5648,13 +5382,13 @@ function SplitCardFormInner({
|
|
|
5648
5382
|
] });
|
|
5649
5383
|
}
|
|
5650
5384
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5651
|
-
/* @__PURE__ */
|
|
5652
|
-
overlayStatus && /* @__PURE__ */
|
|
5385
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
5386
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5653
5387
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
5654
5388
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug-default"),
|
|
5655
5389
|
renderStripeGateDebug("flopay-stripe-gate-debug-default"),
|
|
5656
5390
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
5657
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
5391
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
5658
5392
|
"div",
|
|
5659
5393
|
{
|
|
5660
5394
|
"data-testid": "flopay-paypal-direct-retry-notice-default",
|
|
@@ -5670,7 +5404,7 @@ function SplitCardFormInner({
|
|
|
5670
5404
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
5671
5405
|
}
|
|
5672
5406
|
),
|
|
5673
|
-
/* @__PURE__ */
|
|
5407
|
+
/* @__PURE__ */ jsx7(
|
|
5674
5408
|
DirectPayPalButton,
|
|
5675
5409
|
{
|
|
5676
5410
|
sessionId,
|
|
@@ -5690,6 +5424,7 @@ function SplitCardFormInner({
|
|
|
5690
5424
|
runBeforeButtonClick,
|
|
5691
5425
|
isProcessing: isSubmitting,
|
|
5692
5426
|
onLoadStateChange: setDirectPaypalReady,
|
|
5427
|
+
onInitializationStateChange: setDirectPaypalInitializationState,
|
|
5693
5428
|
session: session ?? null,
|
|
5694
5429
|
existingOrderId: paypalDirectRetry?.orderId,
|
|
5695
5430
|
debug
|
|
@@ -5697,7 +5432,7 @@ function SplitCardFormInner({
|
|
|
5697
5432
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
5698
5433
|
)
|
|
5699
5434
|
] }),
|
|
5700
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
5435
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
5701
5436
|
PayPalButtonInner,
|
|
5702
5437
|
{
|
|
5703
5438
|
sessionId,
|
|
@@ -5715,13 +5450,14 @@ function SplitCardFormInner({
|
|
|
5715
5450
|
placeholderBorderRadius: buttonBorderRadius
|
|
5716
5451
|
}
|
|
5717
5452
|
) }),
|
|
5718
|
-
shouldRenderWallets && /* @__PURE__ */
|
|
5453
|
+
shouldRenderWallets && /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
5719
5454
|
WalletButtonInner,
|
|
5720
5455
|
{
|
|
5721
5456
|
sessionId,
|
|
5722
5457
|
nonce,
|
|
5723
5458
|
email: resolvedAccount.email,
|
|
5724
5459
|
billingApiUrl: resolvedBillingApiUrl,
|
|
5460
|
+
intentKind: totalAmount > 0 ? "payment" : "setup",
|
|
5725
5461
|
expressMethods: walletExpressMethods,
|
|
5726
5462
|
onTokenizedBody: dispatchTokenizedBody,
|
|
5727
5463
|
onErrorChange: updateError,
|
|
@@ -5733,7 +5469,7 @@ function SplitCardFormInner({
|
|
|
5733
5469
|
placeholderBorderRadius: buttonBorderRadius
|
|
5734
5470
|
}
|
|
5735
5471
|
) }),
|
|
5736
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
5472
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
5737
5473
|
StripePaymentElementInner,
|
|
5738
5474
|
{
|
|
5739
5475
|
sessionId,
|
|
@@ -5766,7 +5502,7 @@ function SplitCardFormInner({
|
|
|
5766
5502
|
}
|
|
5767
5503
|
)
|
|
5768
5504
|
] }),
|
|
5769
|
-
|
|
5505
|
+
vaultActive && (shouldDisplayWalletRow || shouldDisplayPayPalRow || shouldDisplayPaymentElementRow) && /* @__PURE__ */ jsxs5("div", { style: {
|
|
5770
5506
|
display: "flex",
|
|
5771
5507
|
alignItems: "center",
|
|
5772
5508
|
gap: "0.75rem",
|
|
@@ -5774,11 +5510,11 @@ function SplitCardFormInner({
|
|
|
5774
5510
|
color: "#999",
|
|
5775
5511
|
fontSize: "0.85rem"
|
|
5776
5512
|
}, children: [
|
|
5777
|
-
/* @__PURE__ */
|
|
5778
|
-
/* @__PURE__ */
|
|
5779
|
-
/* @__PURE__ */
|
|
5513
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
|
|
5514
|
+
/* @__PURE__ */ jsx7("span", { children: "or pay with card" }),
|
|
5515
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
5780
5516
|
] }),
|
|
5781
|
-
|
|
5517
|
+
vaultActive && cardFormBlock
|
|
5782
5518
|
] });
|
|
5783
5519
|
}
|
|
5784
5520
|
|
|
@@ -6477,7 +6213,7 @@ async function loadSavedPaymentProviders({
|
|
|
6477
6213
|
}
|
|
6478
6214
|
|
|
6479
6215
|
// src/flopay-checkout.tsx
|
|
6480
|
-
import { Fragment as Fragment3, jsx as
|
|
6216
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6481
6217
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
6482
6218
|
var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
|
|
6483
6219
|
var sessionInflightMap = /* @__PURE__ */ new Map();
|
|
@@ -6623,7 +6359,6 @@ function FloPayCheckout({
|
|
|
6623
6359
|
onComplete,
|
|
6624
6360
|
onError,
|
|
6625
6361
|
onDecline,
|
|
6626
|
-
onFullNameChange,
|
|
6627
6362
|
onCountryChange,
|
|
6628
6363
|
onZipChange,
|
|
6629
6364
|
showPayPal = true,
|
|
@@ -6645,7 +6380,6 @@ function FloPayCheckout({
|
|
|
6645
6380
|
cardFieldOrder,
|
|
6646
6381
|
cardPreFormSlot,
|
|
6647
6382
|
avsLayout,
|
|
6648
|
-
submitLabel,
|
|
6649
6383
|
className,
|
|
6650
6384
|
initialErrorMessage = null,
|
|
6651
6385
|
children,
|
|
@@ -6661,9 +6395,9 @@ function FloPayCheckout({
|
|
|
6661
6395
|
const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
|
|
6662
6396
|
const [unified, setUnified] = useState4(null);
|
|
6663
6397
|
const [flopay, setFloPay] = useState4(null);
|
|
6664
|
-
const flopayRef =
|
|
6398
|
+
const flopayRef = useRef5(null);
|
|
6665
6399
|
const [paypalFlopay, setPaypalFloPay] = useState4(null);
|
|
6666
|
-
const paypalFlopayRef =
|
|
6400
|
+
const paypalFlopayRef = useRef5(null);
|
|
6667
6401
|
const [session, setSession] = useState4(null);
|
|
6668
6402
|
const [resolvedSessionId, setResolvedSessionId] = useState4(sessionIdProp ?? "");
|
|
6669
6403
|
const activeSessionId = sessionIdProp ?? resolvedSessionId;
|
|
@@ -6678,28 +6412,53 @@ function FloPayCheckout({
|
|
|
6678
6412
|
const [createSessionPatch, setCreateSessionPatch] = useState4(void 0);
|
|
6679
6413
|
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = useState4("");
|
|
6680
6414
|
const [cardBootstrapPending, setCardBootstrapPending] = useState4(false);
|
|
6681
|
-
const
|
|
6682
|
-
const
|
|
6683
|
-
const
|
|
6415
|
+
const [paypalInitializationState, setPaypalInitializationState] = useState4("loading");
|
|
6416
|
+
const [paypalManualRetryGeneration, setPaypalManualRetryGeneration] = useState4(0);
|
|
6417
|
+
const autoCheckoutAttempted = useRef5(false);
|
|
6418
|
+
const paypalResumeAttempted = useRef5(false);
|
|
6419
|
+
const paypalInitializationErrorEmittedRef = useRef5(false);
|
|
6420
|
+
const savedPaymentKeysRef = useRef5(null);
|
|
6684
6421
|
const telemetryCheckoutContext = useMemo4(() => ({
|
|
6685
6422
|
checkoutMode: checkoutModeProp ?? currentMode,
|
|
6686
6423
|
layout: children ? "unknown" : layout === "buttons" ? "buttons" : "embedded"
|
|
6687
6424
|
}), [checkoutModeProp, children, currentMode, layout]);
|
|
6688
|
-
const onCompleteRef =
|
|
6425
|
+
const onCompleteRef = useRef5(onComplete);
|
|
6689
6426
|
onCompleteRef.current = onComplete;
|
|
6690
|
-
const onErrorRef =
|
|
6427
|
+
const onErrorRef = useRef5(onError);
|
|
6691
6428
|
onErrorRef.current = onError;
|
|
6692
|
-
const onDeclineRef =
|
|
6429
|
+
const onDeclineRef = useRef5(onDecline);
|
|
6693
6430
|
onDeclineRef.current = onDecline;
|
|
6694
|
-
|
|
6431
|
+
useEffect5(() => {
|
|
6695
6432
|
getFloPayTelemetryBridge(flopay)?.setCheckoutContext(telemetryCheckoutContext);
|
|
6696
6433
|
if (paypalFlopay && paypalFlopay !== flopay) {
|
|
6697
6434
|
getFloPayTelemetryBridge(paypalFlopay)?.setCheckoutContext(telemetryCheckoutContext);
|
|
6698
6435
|
}
|
|
6699
6436
|
}, [flopay, paypalFlopay, telemetryCheckoutContext]);
|
|
6700
|
-
const onSessionCompletedRef =
|
|
6437
|
+
const onSessionCompletedRef = useRef5(onSessionCompleted);
|
|
6701
6438
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
6702
|
-
|
|
6439
|
+
const handlePayPalInitializationStateChange = useCallback4(
|
|
6440
|
+
(state) => {
|
|
6441
|
+
setPaypalInitializationState(state);
|
|
6442
|
+
if (state !== "exhausted" || paypalInitializationErrorEmittedRef.current) return;
|
|
6443
|
+
paypalInitializationErrorEmittedRef.current = true;
|
|
6444
|
+
onErrorRef.current?.(new FloPayError5(
|
|
6445
|
+
"PayPal is temporarily unavailable. Please try again.",
|
|
6446
|
+
"api_error",
|
|
6447
|
+
{ code: "paypal_init_timeout" }
|
|
6448
|
+
));
|
|
6449
|
+
},
|
|
6450
|
+
[]
|
|
6451
|
+
);
|
|
6452
|
+
const retryPayPalInitialization = useCallback4(() => {
|
|
6453
|
+
setPaypalInitializationState("retrying");
|
|
6454
|
+
setPaypalManualRetryGeneration((generation) => generation + 1);
|
|
6455
|
+
}, []);
|
|
6456
|
+
useEffect5(() => {
|
|
6457
|
+
setPaypalInitializationState("loading");
|
|
6458
|
+
setPaypalManualRetryGeneration(0);
|
|
6459
|
+
paypalInitializationErrorEmittedRef.current = false;
|
|
6460
|
+
}, [activeSessionId]);
|
|
6461
|
+
useEffect5(() => {
|
|
6703
6462
|
console.info("[FloPay] Checkout initialized", {
|
|
6704
6463
|
sdk_version: SDK_VERSION2,
|
|
6705
6464
|
checkout_type: checkoutType,
|
|
@@ -6727,11 +6486,11 @@ function FloPayCheckout({
|
|
|
6727
6486
|
} : void 0,
|
|
6728
6487
|
[effectiveCreateSessionBase, effectiveCreateSessionMode]
|
|
6729
6488
|
);
|
|
6730
|
-
|
|
6489
|
+
useEffect5(() => {
|
|
6731
6490
|
setCreateSessionPatch(void 0);
|
|
6732
6491
|
setCreateSessionPatchBaseHash(baseCreateSessionHash);
|
|
6733
6492
|
}, [baseCreateSessionHash]);
|
|
6734
|
-
|
|
6493
|
+
useEffect5(() => {
|
|
6735
6494
|
setModeError(initialErrorMessage);
|
|
6736
6495
|
}, [initialErrorMessage]);
|
|
6737
6496
|
const emitDecline = useCallback4(
|
|
@@ -7008,7 +6767,7 @@ function FloPayCheckout({
|
|
|
7008
6767
|
telemetryCheckoutContext
|
|
7009
6768
|
]
|
|
7010
6769
|
);
|
|
7011
|
-
|
|
6770
|
+
useEffect5(() => {
|
|
7012
6771
|
if (typeof window === "undefined" || paypalResumeAttempted.current) {
|
|
7013
6772
|
return;
|
|
7014
6773
|
}
|
|
@@ -7211,7 +6970,7 @@ function FloPayCheckout({
|
|
|
7211
6970
|
}
|
|
7212
6971
|
})();
|
|
7213
6972
|
}, [emitDecline, invokeMerchantCallback, locale, normalizeSavedPaymentError, resolvedBillingUrl, telemetry]);
|
|
7214
|
-
const initializedHashRef =
|
|
6973
|
+
const initializedHashRef = useRef5(null);
|
|
7215
6974
|
function hashCreateParams(params) {
|
|
7216
6975
|
const key = JSON.stringify({
|
|
7217
6976
|
c: params?.clientId,
|
|
@@ -7248,12 +7007,12 @@ function FloPayCheckout({
|
|
|
7248
7007
|
() => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
|
|
7249
7008
|
[effectiveCreateSession]
|
|
7250
7009
|
);
|
|
7251
|
-
const createSessionParamsRef =
|
|
7010
|
+
const createSessionParamsRef = useRef5(effectiveCreateSession);
|
|
7252
7011
|
createSessionParamsRef.current = effectiveCreateSession;
|
|
7253
|
-
|
|
7012
|
+
useEffect5(() => {
|
|
7254
7013
|
setResolvedSessionId(sessionIdProp ?? "");
|
|
7255
7014
|
}, [sessionIdProp]);
|
|
7256
|
-
|
|
7015
|
+
useEffect5(() => {
|
|
7257
7016
|
autoCheckoutAttempted.current = false;
|
|
7258
7017
|
setModeError(initialErrorMessage);
|
|
7259
7018
|
setModeOverlayError(null);
|
|
@@ -7445,7 +7204,7 @@ function FloPayCheckout({
|
|
|
7445
7204
|
resolvedSessionId,
|
|
7446
7205
|
session
|
|
7447
7206
|
]);
|
|
7448
|
-
|
|
7207
|
+
useEffect5(() => {
|
|
7449
7208
|
let cancelled = false;
|
|
7450
7209
|
setLoadError(null);
|
|
7451
7210
|
if (createSessionHash) {
|
|
@@ -7692,7 +7451,7 @@ function FloPayCheckout({
|
|
|
7692
7451
|
]
|
|
7693
7452
|
);
|
|
7694
7453
|
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
|
|
7695
|
-
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */
|
|
7454
|
+
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ jsx8(
|
|
7696
7455
|
ProcessingOverlay,
|
|
7697
7456
|
{
|
|
7698
7457
|
status: modeOverlayStatus,
|
|
@@ -7708,7 +7467,7 @@ function FloPayCheckout({
|
|
|
7708
7467
|
}
|
|
7709
7468
|
if (layout === "buttons") {
|
|
7710
7469
|
const bundleRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
7711
|
-
const skeletonBar = (h) => /* @__PURE__ */
|
|
7470
|
+
const skeletonBar = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
7712
7471
|
height: h,
|
|
7713
7472
|
borderRadius: bundleRadius,
|
|
7714
7473
|
background: "#e5e7eb",
|
|
@@ -7719,14 +7478,14 @@ function FloPayCheckout({
|
|
|
7719
7478
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7720
7479
|
showStripe && (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7721
7480
|
showStripe && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7722
|
-
/* @__PURE__ */
|
|
7481
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
7723
7482
|
] }),
|
|
7724
7483
|
modeOverlay
|
|
7725
7484
|
] });
|
|
7726
7485
|
}
|
|
7727
7486
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7728
7487
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
|
|
7729
|
-
/* @__PURE__ */
|
|
7488
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
7730
7489
|
width: 24,
|
|
7731
7490
|
height: 24,
|
|
7732
7491
|
border: "2px solid #e5e7eb",
|
|
@@ -7734,16 +7493,16 @@ function FloPayCheckout({
|
|
|
7734
7493
|
borderRadius: "50%",
|
|
7735
7494
|
animation: "spin 0.6s linear infinite"
|
|
7736
7495
|
} }),
|
|
7737
|
-
/* @__PURE__ */
|
|
7496
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
7738
7497
|
] }),
|
|
7739
7498
|
modeOverlay
|
|
7740
7499
|
] });
|
|
7741
7500
|
}
|
|
7742
7501
|
if (loadError) {
|
|
7743
7502
|
if (errorNode) {
|
|
7744
|
-
return /* @__PURE__ */
|
|
7503
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
|
|
7745
7504
|
}
|
|
7746
|
-
return /* @__PURE__ */
|
|
7505
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
7747
7506
|
"div",
|
|
7748
7507
|
{
|
|
7749
7508
|
role: "alert",
|
|
@@ -7760,7 +7519,7 @@ function FloPayCheckout({
|
|
|
7760
7519
|
}
|
|
7761
7520
|
if (shouldShowInterimButtons) {
|
|
7762
7521
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7763
|
-
/* @__PURE__ */
|
|
7522
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
7764
7523
|
InterimButtonsView,
|
|
7765
7524
|
{
|
|
7766
7525
|
onButtonClick,
|
|
@@ -7781,27 +7540,42 @@ function FloPayCheckout({
|
|
|
7781
7540
|
}
|
|
7782
7541
|
if (isPaypalOnlySession && session && directPaypalConfig) {
|
|
7783
7542
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7784
|
-
/* @__PURE__ */
|
|
7785
|
-
modeError && /* @__PURE__ */
|
|
7786
|
-
/* @__PURE__ */
|
|
7787
|
-
|
|
7543
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsxs6("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
7544
|
+
modeError && /* @__PURE__ */ jsx8(ErrorBanner, { icon: false, children: modeError }),
|
|
7545
|
+
paypalInitializationState === "retrying" && /* @__PURE__ */ jsx8("div", { role: "status", "aria-live": "polite", children: "PayPal is temporarily unavailable. Retrying\u2026" }),
|
|
7546
|
+
paypalInitializationState === "exhausted" && /* @__PURE__ */ jsxs6("div", { role: "alert", children: [
|
|
7547
|
+
/* @__PURE__ */ jsx8("div", { children: "PayPal is temporarily unavailable. Please try again." }),
|
|
7548
|
+
/* @__PURE__ */ jsx8("button", { type: "button", onClick: retryPayPalInitialization, children: "Retry PayPal" })
|
|
7549
|
+
] }),
|
|
7550
|
+
paypalInitializationState !== "exhausted" && /* @__PURE__ */ jsx8(
|
|
7551
|
+
"div",
|
|
7788
7552
|
{
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7553
|
+
"aria-hidden": paypalInitializationState === "retrying" ? true : void 0,
|
|
7554
|
+
style: paypalInitializationState === "retrying" ? { position: "relative", height: 0, opacity: 0, pointerEvents: "none" } : void 0,
|
|
7555
|
+
children: /* @__PURE__ */ jsx8(
|
|
7556
|
+
InstrumentedDirectPayPalButton,
|
|
7557
|
+
{
|
|
7558
|
+
sessionId: activeSessionId,
|
|
7559
|
+
nonce: session.clientSecret || void 0,
|
|
7560
|
+
billingApiUrl: resolvedBillingUrl,
|
|
7561
|
+
email: session.customer?.email,
|
|
7562
|
+
clientId: directPaypalConfig.clientId,
|
|
7563
|
+
environment: directPaypalConfig.environment,
|
|
7564
|
+
currency: (session.currency ?? "usd").toUpperCase(),
|
|
7565
|
+
isSubscription: session.mode === "subscription",
|
|
7566
|
+
onComplete,
|
|
7567
|
+
onErrorChange: setModeError,
|
|
7568
|
+
onDecline,
|
|
7569
|
+
onButtonClick,
|
|
7570
|
+
onInitializationStateChange: handlePayPalInitializationStateChange,
|
|
7571
|
+
allowAutomaticRetry: paypalManualRetryGeneration === 0,
|
|
7572
|
+
session,
|
|
7573
|
+
telemetry,
|
|
7574
|
+
telemetryContext: telemetryCheckoutContext,
|
|
7575
|
+
debug
|
|
7576
|
+
},
|
|
7577
|
+
`paypal-init-${paypalManualRetryGeneration}`
|
|
7578
|
+
)
|
|
7805
7579
|
}
|
|
7806
7580
|
)
|
|
7807
7581
|
] }) }),
|
|
@@ -7809,12 +7583,12 @@ function FloPayCheckout({
|
|
|
7809
7583
|
] });
|
|
7810
7584
|
}
|
|
7811
7585
|
if (!flopay || !providerOptions) {
|
|
7812
|
-
return /* @__PURE__ */
|
|
7586
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: modeOverlay });
|
|
7813
7587
|
}
|
|
7814
7588
|
if (currentMode === "confirm") {
|
|
7815
7589
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7816
|
-
/* @__PURE__ */
|
|
7817
|
-
modeError && /* @__PURE__ */
|
|
7590
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ jsxs6("div", { className, children: [
|
|
7591
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
7818
7592
|
"div",
|
|
7819
7593
|
{
|
|
7820
7594
|
style: {
|
|
@@ -7829,7 +7603,7 @@ function FloPayCheckout({
|
|
|
7829
7603
|
renderConfirmButton ? renderConfirmButton({
|
|
7830
7604
|
onConfirm: handleConfirmCheckout,
|
|
7831
7605
|
isProcessing: confirmProcessing
|
|
7832
|
-
}) : /* @__PURE__ */
|
|
7606
|
+
}) : /* @__PURE__ */ jsx8(
|
|
7833
7607
|
"button",
|
|
7834
7608
|
{
|
|
7835
7609
|
type: "button",
|
|
@@ -7855,8 +7629,8 @@ function FloPayCheckout({
|
|
|
7855
7629
|
] });
|
|
7856
7630
|
}
|
|
7857
7631
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7858
|
-
/* @__PURE__ */
|
|
7859
|
-
modeError && /* @__PURE__ */
|
|
7632
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7633
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
7860
7634
|
"div",
|
|
7861
7635
|
{
|
|
7862
7636
|
style: {
|
|
@@ -7871,7 +7645,7 @@ function FloPayCheckout({
|
|
|
7871
7645
|
children: modeError
|
|
7872
7646
|
}
|
|
7873
7647
|
),
|
|
7874
|
-
/* @__PURE__ */
|
|
7648
|
+
/* @__PURE__ */ jsx8(
|
|
7875
7649
|
SessionInjector,
|
|
7876
7650
|
{
|
|
7877
7651
|
sessionId: activeSessionId,
|
|
@@ -7881,7 +7655,7 @@ function FloPayCheckout({
|
|
|
7881
7655
|
children
|
|
7882
7656
|
}
|
|
7883
7657
|
)
|
|
7884
|
-
] }) : /* @__PURE__ */
|
|
7658
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
7885
7659
|
SplitCardForm,
|
|
7886
7660
|
{
|
|
7887
7661
|
sessionId: activeSessionId,
|
|
@@ -7897,7 +7671,6 @@ function FloPayCheckout({
|
|
|
7897
7671
|
onDecline,
|
|
7898
7672
|
error: modeError,
|
|
7899
7673
|
onErrorChange: setModeError,
|
|
7900
|
-
onFullNameChange,
|
|
7901
7674
|
showPayPal,
|
|
7902
7675
|
showStripe,
|
|
7903
7676
|
enabledPaymentMethods: unified?.data.stripe?.enabledPaymentMethods,
|
|
@@ -7926,7 +7699,6 @@ function FloPayCheckout({
|
|
|
7926
7699
|
avsCheck: !!enableAVS,
|
|
7927
7700
|
checkoutType: createSessionParams ? "embedded_checkout" : "standard_checkout",
|
|
7928
7701
|
checkoutLayout: children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout",
|
|
7929
|
-
submitLabel,
|
|
7930
7702
|
className,
|
|
7931
7703
|
directPaypal: resolveDirectPaypalConfig(unified),
|
|
7932
7704
|
isSubscription: session?.mode === "subscription",
|
|
@@ -7944,8 +7716,8 @@ function SessionInjector({
|
|
|
7944
7716
|
session,
|
|
7945
7717
|
children
|
|
7946
7718
|
}) {
|
|
7947
|
-
return /* @__PURE__ */
|
|
7948
|
-
if (!
|
|
7719
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: React8.Children.map(children, (child) => {
|
|
7720
|
+
if (!React8.isValidElement(child)) return child;
|
|
7949
7721
|
const existing = child.props;
|
|
7950
7722
|
const injected = {};
|
|
7951
7723
|
if (!existing.sessionId) injected.sessionId = sessionId;
|
|
@@ -7960,7 +7732,7 @@ function SessionInjector({
|
|
|
7960
7732
|
injected.lastName = session.customer.lastName;
|
|
7961
7733
|
}
|
|
7962
7734
|
if (Object.keys(injected).length === 0) return child;
|
|
7963
|
-
return
|
|
7735
|
+
return React8.cloneElement(child, injected);
|
|
7964
7736
|
}) });
|
|
7965
7737
|
}
|
|
7966
7738
|
function InterimButtonsView({
|
|
@@ -7993,7 +7765,7 @@ function InterimButtonsView({
|
|
|
7993
7765
|
};
|
|
7994
7766
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
7995
7767
|
const skeletonRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
7996
|
-
const skeleton = (h) => /* @__PURE__ */
|
|
7768
|
+
const skeleton = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
7997
7769
|
height: h,
|
|
7998
7770
|
borderRadius: skeletonRadius,
|
|
7999
7771
|
background: "#e5e7eb",
|
|
@@ -8035,7 +7807,7 @@ function InterimButtonsView({
|
|
|
8035
7807
|
...bStyles.backButton
|
|
8036
7808
|
},
|
|
8037
7809
|
children: [
|
|
8038
|
-
/* @__PURE__ */
|
|
7810
|
+
/* @__PURE__ */ jsx8("span", { style: {
|
|
8039
7811
|
display: "inline-flex",
|
|
8040
7812
|
alignItems: "center",
|
|
8041
7813
|
justifyContent: "center",
|
|
@@ -8044,12 +7816,12 @@ function InterimButtonsView({
|
|
|
8044
7816
|
borderRadius: "50%",
|
|
8045
7817
|
backgroundColor: "#f3f4f6",
|
|
8046
7818
|
...bStyles.backButtonIcon
|
|
8047
|
-
}, children: /* @__PURE__ */
|
|
8048
|
-
/* @__PURE__ */
|
|
7819
|
+
}, 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" }) }) }),
|
|
7820
|
+
/* @__PURE__ */ jsx8(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
8049
7821
|
]
|
|
8050
7822
|
}
|
|
8051
7823
|
),
|
|
8052
|
-
hideTitle ? /* @__PURE__ */
|
|
7824
|
+
hideTitle ? /* @__PURE__ */ jsx8("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx8("div", { style: {
|
|
8053
7825
|
flex: 1,
|
|
8054
7826
|
textAlign: "center",
|
|
8055
7827
|
fontWeight: 600,
|
|
@@ -8057,11 +7829,11 @@ function InterimButtonsView({
|
|
|
8057
7829
|
color: "#262833",
|
|
8058
7830
|
paddingRight: 80,
|
|
8059
7831
|
...bStyles.title
|
|
8060
|
-
}, children: /* @__PURE__ */
|
|
7832
|
+
}, children: /* @__PURE__ */ jsx8(TitleContentSlot, { content: cardTitleContent }) })
|
|
8061
7833
|
] }),
|
|
8062
|
-
/* @__PURE__ */
|
|
7834
|
+
/* @__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" } }) }),
|
|
8063
7835
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex" }, children: [
|
|
8064
|
-
/* @__PURE__ */
|
|
7836
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8065
7837
|
flex: 1,
|
|
8066
7838
|
backgroundColor: inputBg,
|
|
8067
7839
|
borderTop: "none",
|
|
@@ -8071,8 +7843,8 @@ function InterimButtonsView({
|
|
|
8071
7843
|
borderBottomLeftRadius: 8,
|
|
8072
7844
|
padding: 12,
|
|
8073
7845
|
height: 45
|
|
8074
|
-
}, children: /* @__PURE__ */
|
|
8075
|
-
/* @__PURE__ */
|
|
7846
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
7847
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8076
7848
|
flex: 1,
|
|
8077
7849
|
backgroundColor: inputBg,
|
|
8078
7850
|
borderTop: "none",
|
|
@@ -8082,10 +7854,10 @@ function InterimButtonsView({
|
|
|
8082
7854
|
borderBottomRightRadius: 8,
|
|
8083
7855
|
padding: 12,
|
|
8084
7856
|
height: 45
|
|
8085
|
-
}, children: /* @__PURE__ */
|
|
7857
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
8086
7858
|
] }),
|
|
8087
|
-
/* @__PURE__ */
|
|
8088
|
-
/* @__PURE__ */
|
|
7859
|
+
/* @__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" } }) }),
|
|
7860
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8089
7861
|
height: 50,
|
|
8090
7862
|
borderRadius: 8,
|
|
8091
7863
|
marginTop: 16,
|
|
@@ -8094,7 +7866,7 @@ function InterimButtonsView({
|
|
|
8094
7866
|
...bStyles.submitButton,
|
|
8095
7867
|
opacity: 0.5
|
|
8096
7868
|
} }),
|
|
8097
|
-
/* @__PURE__ */
|
|
7869
|
+
/* @__PURE__ */ jsx8("style", { children: `
|
|
8098
7870
|
@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
8099
7871
|
@keyframes flopay-interim-expand {
|
|
8100
7872
|
0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
|
|
@@ -8107,7 +7879,7 @@ function InterimButtonsView({
|
|
|
8107
7879
|
return /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
8108
7880
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
8109
7881
|
showStripe && (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
8110
|
-
showStripe && /* @__PURE__ */
|
|
7882
|
+
showStripe && /* @__PURE__ */ jsx8(
|
|
8111
7883
|
"button",
|
|
8112
7884
|
{
|
|
8113
7885
|
type: "button",
|
|
@@ -8141,362 +7913,80 @@ function InterimButtonsView({
|
|
|
8141
7913
|
onMouseUp: (e) => {
|
|
8142
7914
|
e.currentTarget.style.transform = "scale(1)";
|
|
8143
7915
|
},
|
|
8144
|
-
children: /* @__PURE__ */
|
|
7916
|
+
children: /* @__PURE__ */ jsx8(CardButtonContentSlot, { content: cardButtonContent })
|
|
8145
7917
|
}
|
|
8146
7918
|
),
|
|
8147
|
-
/* @__PURE__ */
|
|
7919
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
8148
7920
|
] });
|
|
8149
7921
|
}
|
|
8150
7922
|
|
|
8151
|
-
// src/
|
|
8152
|
-
import {
|
|
8153
|
-
import {
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
children,
|
|
8177
|
-
firstName,
|
|
8178
|
-
lastName,
|
|
8179
|
-
chv,
|
|
8180
|
-
isProcessing: externalProcessing,
|
|
8181
|
-
error: externalError,
|
|
8182
|
-
onErrorChange,
|
|
8183
|
-
innerRef
|
|
8184
|
-
}) {
|
|
8185
|
-
const flopay = useFloPay();
|
|
8186
|
-
const paypalFlopay = usePayPalFloPay();
|
|
8187
|
-
const elements = useElements();
|
|
8188
|
-
const contextBillingUrl = useBillingApiUrl();
|
|
8189
|
-
const [processing, setProcessing] = useState5(false);
|
|
8190
|
-
const [error, setError] = useState5(null);
|
|
8191
|
-
const [is3DSActive, setIs3DSActive] = useState5(false);
|
|
8192
|
-
const displayError = externalError ?? error;
|
|
8193
|
-
const isSubmitting = externalProcessing ?? processing;
|
|
8194
|
-
const isSelfContained = !onTokenizedBody;
|
|
8195
|
-
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
8196
|
-
const updateError = useCallback5(
|
|
8197
|
-
(err) => {
|
|
8198
|
-
setError(err);
|
|
8199
|
-
onErrorChange?.(err);
|
|
8200
|
-
},
|
|
8201
|
-
[onErrorChange]
|
|
8202
|
-
);
|
|
8203
|
-
const emitDecline = useCallback5(
|
|
8204
|
-
(input, overrides) => {
|
|
8205
|
-
onDecline?.(buildDeclineEvent("card", input, overrides));
|
|
8206
|
-
},
|
|
8207
|
-
[onDecline]
|
|
8208
|
-
);
|
|
8209
|
-
const processPaymentInternal = useCallback5(
|
|
8210
|
-
async (tokenizedBody, completionPaymentMethodId) => {
|
|
8211
|
-
setProcessing(true);
|
|
8212
|
-
updateError(null);
|
|
8213
|
-
const resolvedCompletionPaymentMethodId = completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
|
|
8214
|
-
const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
|
|
8215
|
-
try {
|
|
8216
|
-
const api = new PaymentAPI5(baseUrl);
|
|
8217
|
-
const response = await api.processPayment(userId ?? "", {
|
|
8218
|
-
sessionId,
|
|
8219
|
-
nonce,
|
|
8220
|
-
tokenizedData: requestTokenizedBody,
|
|
8221
|
-
accountData: {
|
|
8222
|
-
userId: userId ?? "",
|
|
8223
|
-
email: email ?? "",
|
|
8224
|
-
firstName: firstName ?? "",
|
|
8225
|
-
lastName: lastName ?? ""
|
|
8226
|
-
},
|
|
8227
|
-
chv
|
|
8228
|
-
});
|
|
8229
|
-
if (response.ok) {
|
|
8230
|
-
onComplete?.({
|
|
8231
|
-
status: "succeeded",
|
|
8232
|
-
paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
|
|
8233
|
-
paymentMethodId: resolvedCompletionPaymentMethodId,
|
|
8234
|
-
checkoutMethod: tokenizedBody.isPaypal ? "paypal" : "card"
|
|
8235
|
-
});
|
|
8236
|
-
return;
|
|
8237
|
-
}
|
|
8238
|
-
const json = await response.json().catch(() => null);
|
|
8239
|
-
if (json?.type === "3ds_required") {
|
|
8240
|
-
const secret = json["threeDSecureToken"];
|
|
8241
|
-
if (!flopay || !secret) {
|
|
8242
|
-
updateError("3DS authentication required but no token provided.");
|
|
8243
|
-
return;
|
|
8244
|
-
}
|
|
8245
|
-
setIs3DSActive(true);
|
|
8246
|
-
try {
|
|
8247
|
-
const retryFullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
|
|
8248
|
-
const result = await flopay.confirmPayment({
|
|
8249
|
-
clientSecret: secret,
|
|
8250
|
-
returnUrl: window.location.href,
|
|
8251
|
-
billingDetails: {
|
|
8252
|
-
...email ? { email } : {},
|
|
8253
|
-
...retryFullName ? { name: retryFullName } : {}
|
|
8254
|
-
}
|
|
8255
|
-
});
|
|
8256
|
-
if (result.error) {
|
|
8257
|
-
updateError(result.error.message);
|
|
8258
|
-
onError?.(result.error);
|
|
8259
|
-
emitDecline(result.error);
|
|
8260
|
-
return;
|
|
8261
|
-
}
|
|
8262
|
-
if (result.status === "succeeded" || result.status === "processing") {
|
|
8263
|
-
await processPaymentInternal({
|
|
8264
|
-
id: result.paymentIntentId,
|
|
8265
|
-
type: "card",
|
|
8266
|
-
threeDSecureActionResultTokenId: result.paymentIntentId
|
|
8267
|
-
}, resolvedCompletionPaymentMethodId);
|
|
8268
|
-
}
|
|
8269
|
-
} finally {
|
|
8270
|
-
setIs3DSActive(false);
|
|
8271
|
-
}
|
|
8272
|
-
return;
|
|
8273
|
-
}
|
|
8274
|
-
if (json?.type === "paypal_redirect_required") {
|
|
8275
|
-
const secret = json["threeDSecureToken"] ?? json["clientSecret"];
|
|
8276
|
-
const pmId = json["paymentMethodId"];
|
|
8277
|
-
const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
|
|
8278
|
-
if (!paypalStripe || !secret) {
|
|
8279
|
-
const message = "PayPal is not available.";
|
|
8280
|
-
updateError(message);
|
|
8281
|
-
onDecline?.(buildDeclineEvent("paypal", message));
|
|
8282
|
-
return;
|
|
8283
|
-
}
|
|
8284
|
-
localStorage.setItem(WALLET_RESUME_KEY, JSON.stringify({
|
|
8285
|
-
sessionId,
|
|
8286
|
-
paymentIntentId: "",
|
|
8287
|
-
tokenType: "card",
|
|
8288
|
-
tokenId: pmId ?? "",
|
|
8289
|
-
status: "pending_redirect"
|
|
8290
|
-
}));
|
|
8291
|
-
const confirmParams = {
|
|
8292
|
-
return_url: window.location.href
|
|
8293
|
-
};
|
|
8294
|
-
if (pmId) confirmParams["payment_method"] = pmId;
|
|
8295
|
-
const { error: confirmError } = await paypalStripe.confirmPayment({
|
|
8296
|
-
clientSecret: secret,
|
|
8297
|
-
confirmParams,
|
|
8298
|
-
redirect: "if_required"
|
|
8299
|
-
});
|
|
8300
|
-
if (confirmError) {
|
|
8301
|
-
const message = confirmError.message ?? "PayPal payment failed.";
|
|
8302
|
-
updateError(message);
|
|
8303
|
-
onDecline?.(buildDeclineEvent("paypal", message, { code: confirmError.code }));
|
|
8304
|
-
}
|
|
8305
|
-
return;
|
|
8306
|
-
}
|
|
8307
|
-
const errorMessage = json?.message ?? "Payment failed. Please try again.";
|
|
8308
|
-
updateError(errorMessage);
|
|
8309
|
-
emitDecline(errorMessage, {
|
|
8310
|
-
code: json?.code,
|
|
8311
|
-
declineCode: json?.declineCode ?? json?.gatewayDeclineReason
|
|
8312
|
-
});
|
|
8313
|
-
} catch (err) {
|
|
8314
|
-
updateError(err instanceof Error ? err.message : "An unexpected error occurred");
|
|
8315
|
-
} finally {
|
|
8316
|
-
setProcessing(false);
|
|
8317
|
-
}
|
|
8318
|
-
},
|
|
8319
|
-
[baseUrl, sessionId, nonce, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
|
|
8320
|
-
);
|
|
8321
|
-
const dispatchTokenizedBody = useCallback5(
|
|
8322
|
-
(tokenizedBody) => {
|
|
8323
|
-
if (onTokenizedBody) {
|
|
8324
|
-
onTokenizedBody(tokenizedBody);
|
|
8325
|
-
} else {
|
|
8326
|
-
processPaymentInternal(tokenizedBody);
|
|
8327
|
-
}
|
|
8328
|
-
},
|
|
8329
|
-
[onTokenizedBody, processPaymentInternal]
|
|
8330
|
-
);
|
|
8331
|
-
useImperativeHandle2(innerRef, () => ({
|
|
8332
|
-
async handleNextAction(secret) {
|
|
8333
|
-
if (!flopay) return;
|
|
8334
|
-
setIs3DSActive(true);
|
|
8335
|
-
try {
|
|
8336
|
-
const result = await flopay.confirmPayment({
|
|
8337
|
-
clientSecret: secret,
|
|
8338
|
-
returnUrl: window.location.href
|
|
8339
|
-
});
|
|
8340
|
-
if (result.error) {
|
|
8341
|
-
updateError(result.error.message);
|
|
8342
|
-
onError?.(result.error);
|
|
8343
|
-
emitDecline(result.error);
|
|
8344
|
-
} else if (result.status === "succeeded" || result.status === "processing") {
|
|
8345
|
-
dispatchTokenizedBody({
|
|
8346
|
-
id: result.paymentIntentId,
|
|
8347
|
-
type: "card",
|
|
8348
|
-
threeDSecureActionResultTokenId: result.paymentIntentId
|
|
8349
|
-
});
|
|
8350
|
-
}
|
|
8351
|
-
} catch (err) {
|
|
8352
|
-
updateError(err instanceof Error ? err.message : "Payment authentication failed.");
|
|
8353
|
-
} finally {
|
|
8354
|
-
setIs3DSActive(false);
|
|
8355
|
-
}
|
|
8356
|
-
}
|
|
8357
|
-
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
8358
|
-
useEffect7(() => {
|
|
8359
|
-
if (typeof window === "undefined") return;
|
|
8360
|
-
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
8361
|
-
if (!stored) return;
|
|
8362
|
-
try {
|
|
8363
|
-
const payload = JSON.parse(stored);
|
|
8364
|
-
if (payload.sessionId === sessionId) {
|
|
8365
|
-
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
8366
|
-
dispatchTokenizedBody({
|
|
8367
|
-
id: payload.tokenId,
|
|
8368
|
-
type: payload.tokenType,
|
|
8369
|
-
threeDSecureActionResultTokenId: payload.paymentIntentId
|
|
8370
|
-
});
|
|
8371
|
-
}
|
|
8372
|
-
} catch {
|
|
8373
|
-
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
8374
|
-
}
|
|
8375
|
-
}, [sessionId, dispatchTokenizedBody]);
|
|
8376
|
-
const handleSubmit = useCallback5(
|
|
8377
|
-
async (e) => {
|
|
8378
|
-
e.preventDefault();
|
|
8379
|
-
if (!flopay || !elements || isSubmitting) return;
|
|
8380
|
-
setProcessing(true);
|
|
8381
|
-
updateError(null);
|
|
8382
|
-
let handedOff = false;
|
|
8383
|
-
try {
|
|
8384
|
-
const submitResult = await flopay.submitElements();
|
|
8385
|
-
if (submitResult.error) {
|
|
8386
|
-
updateError(submitResult.error.message);
|
|
8387
|
-
onError?.(submitResult.error);
|
|
8388
|
-
return;
|
|
8389
|
-
}
|
|
8390
|
-
const fullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
|
|
8391
|
-
const pmResult = await flopay.createPaymentMethod({
|
|
8392
|
-
...email ? { email } : {},
|
|
8393
|
-
...fullName ? { name: fullName } : {}
|
|
8394
|
-
});
|
|
8395
|
-
if (pmResult.error || !pmResult.paymentMethodId) {
|
|
8396
|
-
updateError(pmResult.error?.message ?? "Failed to create payment method.");
|
|
8397
|
-
return;
|
|
8398
|
-
}
|
|
8399
|
-
if (!sessionId || !email) {
|
|
8400
|
-
throw new FloPayError6("Missing sessionId or email", "validation_error");
|
|
8401
|
-
}
|
|
8402
|
-
const intentHeaders = intentRequestHeaders(nonce);
|
|
8403
|
-
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
8404
|
-
method: "POST",
|
|
8405
|
-
headers: intentHeaders,
|
|
8406
|
-
body: JSON.stringify({
|
|
8407
|
-
sessionId,
|
|
8408
|
-
email,
|
|
8409
|
-
paymentMethodType: pmResult.paymentMethodId,
|
|
8410
|
-
isPaypal: false
|
|
8411
|
-
})
|
|
8412
|
-
});
|
|
8413
|
-
if (!intentResponse.ok) {
|
|
8414
|
-
const intentError = await buildFloPayApiErrorFromResponse(
|
|
8415
|
-
intentResponse,
|
|
8416
|
-
"Failed to create payment intent"
|
|
8417
|
-
);
|
|
8418
|
-
updateError(intentError.message);
|
|
8419
|
-
onError?.(intentError);
|
|
8420
|
-
emitDecline(intentError);
|
|
8421
|
-
return;
|
|
8422
|
-
}
|
|
8423
|
-
const intentJson = await intentResponse.json();
|
|
8424
|
-
const intentClientSecret = intentJson.data?.id;
|
|
8425
|
-
if (!intentClientSecret) throw new FloPayError6("No client_secret in payment intent response", "api_error");
|
|
8426
|
-
const confirmResult = await flopay.confirmCardPayment({
|
|
8427
|
-
clientSecret: intentClientSecret,
|
|
8428
|
-
paymentMethodId: pmResult.paymentMethodId
|
|
8429
|
-
});
|
|
8430
|
-
if (confirmResult.error) {
|
|
8431
|
-
updateError(confirmResult.error.message);
|
|
8432
|
-
onError?.(confirmResult.error);
|
|
8433
|
-
emitDecline(confirmResult.error);
|
|
8434
|
-
return;
|
|
7923
|
+
// src/elements.tsx
|
|
7924
|
+
import { useEffect as useEffect6, useRef as useRef6, useContext as useContext3 } from "react";
|
|
7925
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
7926
|
+
function createElementComponent(elementType, displayName) {
|
|
7927
|
+
function ElementComponent({
|
|
7928
|
+
className,
|
|
7929
|
+
id,
|
|
7930
|
+
style,
|
|
7931
|
+
options,
|
|
7932
|
+
onChange,
|
|
7933
|
+
onReady,
|
|
7934
|
+
onFocus,
|
|
7935
|
+
onBlur,
|
|
7936
|
+
onEscape
|
|
7937
|
+
}) {
|
|
7938
|
+
const containerRef = useRef6(null);
|
|
7939
|
+
const elementRef = useRef6(null);
|
|
7940
|
+
const { elements, reportInteractive } = useContext3(FloPayContext);
|
|
7941
|
+
useEffect6(() => {
|
|
7942
|
+
if (!elements || !containerRef.current) return;
|
|
7943
|
+
let mounted = true;
|
|
7944
|
+
(async () => {
|
|
7945
|
+
let element = elements.getElement(elementType);
|
|
7946
|
+
if (!element) {
|
|
7947
|
+
element = await elements.create(elementType, options);
|
|
8435
7948
|
}
|
|
8436
|
-
|
|
8437
|
-
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
8438
|
-
rawProvider,
|
|
8439
|
-
intentClientSecret
|
|
8440
|
-
);
|
|
8441
|
-
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
8442
|
-
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
8443
|
-
if (!paymentIntentId) {
|
|
8444
|
-
const error2 = new FloPayError6("No payment intent returned after confirmation.", "api_error");
|
|
8445
|
-
updateError(error2.message);
|
|
8446
|
-
onError?.(error2);
|
|
7949
|
+
if (!mounted || !containerRef.current) {
|
|
8447
7950
|
return;
|
|
8448
7951
|
}
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
7952
|
+
element.mount(containerRef.current);
|
|
7953
|
+
elementRef.current = element;
|
|
7954
|
+
if (onChange) element.on("change", onChange);
|
|
7955
|
+
element.on("ready", () => {
|
|
7956
|
+
reportInteractive?.();
|
|
7957
|
+
onReady?.();
|
|
8455
7958
|
});
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
(is3DSActive || isSubmitting) && /* @__PURE__ */ jsx10("div", { "data-testid": "flopay-overlay", style: {
|
|
8469
|
-
position: "absolute",
|
|
8470
|
-
inset: 0,
|
|
8471
|
-
background: "rgba(255,255,255,0.7)",
|
|
8472
|
-
display: "flex",
|
|
8473
|
-
alignItems: "center",
|
|
8474
|
-
justifyContent: "center",
|
|
8475
|
-
zIndex: 10
|
|
8476
|
-
}, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
|
|
8477
|
-
!isReady && /* @__PURE__ */ jsx10("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
|
|
8478
|
-
isReady && /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
8479
|
-
/* @__PURE__ */ jsx10(PaymentElement, { options: { layout } }),
|
|
8480
|
-
showAddress && /* @__PURE__ */ jsx10(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
|
|
8481
|
-
displayError && /* @__PURE__ */ jsx10("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
|
|
8482
|
-
children ?? /* @__PURE__ */ jsx10(
|
|
8483
|
-
"button",
|
|
8484
|
-
{
|
|
8485
|
-
type: "submit",
|
|
8486
|
-
disabled: isSubmitting || !isReady,
|
|
8487
|
-
"data-testid": "flopay-submit",
|
|
8488
|
-
children: isSubmitting ? "Processing..." : submitLabel
|
|
7959
|
+
if (onFocus) element.on("focus", onFocus);
|
|
7960
|
+
if (onBlur) element.on("blur", onBlur);
|
|
7961
|
+
if (onEscape) element.on("escape", onEscape);
|
|
7962
|
+
})();
|
|
7963
|
+
return () => {
|
|
7964
|
+
mounted = false;
|
|
7965
|
+
if (elementRef.current) {
|
|
7966
|
+
try {
|
|
7967
|
+
elementRef.current.unmount();
|
|
7968
|
+
} catch {
|
|
7969
|
+
}
|
|
7970
|
+
elementRef.current = null;
|
|
8489
7971
|
}
|
|
8490
|
-
|
|
8491
|
-
]
|
|
8492
|
-
|
|
7972
|
+
};
|
|
7973
|
+
}, [elements, reportInteractive]);
|
|
7974
|
+
return /* @__PURE__ */ jsx9("div", { ref: containerRef, className, id, style });
|
|
7975
|
+
}
|
|
7976
|
+
ElementComponent.displayName = displayName;
|
|
7977
|
+
return ElementComponent;
|
|
8493
7978
|
}
|
|
7979
|
+
var PaymentElement2 = createElementComponent(
|
|
7980
|
+
"payment",
|
|
7981
|
+
"PaymentElement"
|
|
7982
|
+
);
|
|
7983
|
+
var AddressElement = createElementComponent("address", "AddressElement");
|
|
8494
7984
|
|
|
8495
7985
|
// src/paypal-button.tsx
|
|
8496
|
-
import { PaymentAPI as
|
|
8497
|
-
import { FloPayError as
|
|
8498
|
-
import { useCallback as
|
|
8499
|
-
import { Fragment as
|
|
7986
|
+
import { PaymentAPI as PaymentAPI5 } from "@flopay/js";
|
|
7987
|
+
import { FloPayError as FloPayError6 } from "@flopay/shared";
|
|
7988
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef7, useState as useState5 } from "react";
|
|
7989
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8500
7990
|
function PayPalButton({
|
|
8501
7991
|
sessionId,
|
|
8502
7992
|
nonce,
|
|
@@ -8514,14 +8004,14 @@ function PayPalButton({
|
|
|
8514
8004
|
const flopay = useFloPay();
|
|
8515
8005
|
const elements = useElements();
|
|
8516
8006
|
const contextBillingUrl = useBillingApiUrl();
|
|
8517
|
-
const [ready, setReady] =
|
|
8518
|
-
const [submitting, setSubmitting] =
|
|
8007
|
+
const [ready, setReady] = useState5(false);
|
|
8008
|
+
const [submitting, setSubmitting] = useState5(false);
|
|
8519
8009
|
const paypalResumeAttempted = useRef7(false);
|
|
8520
8010
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
8521
|
-
const processPaymentInternal =
|
|
8011
|
+
const processPaymentInternal = useCallback5(
|
|
8522
8012
|
async (tokenizedBody) => {
|
|
8523
8013
|
try {
|
|
8524
|
-
const api = new
|
|
8014
|
+
const api = new PaymentAPI5(baseUrl);
|
|
8525
8015
|
const response = await api.processPayment(userId ?? "", {
|
|
8526
8016
|
sessionId,
|
|
8527
8017
|
nonce,
|
|
@@ -8546,7 +8036,7 @@ function PayPalButton({
|
|
|
8546
8036
|
},
|
|
8547
8037
|
[baseUrl, sessionId, nonce, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
|
|
8548
8038
|
);
|
|
8549
|
-
const dispatchTokenizedBody =
|
|
8039
|
+
const dispatchTokenizedBody = useCallback5(
|
|
8550
8040
|
(body) => {
|
|
8551
8041
|
if (onTokenizedBody) {
|
|
8552
8042
|
onTokenizedBody(body);
|
|
@@ -8556,7 +8046,7 @@ function PayPalButton({
|
|
|
8556
8046
|
},
|
|
8557
8047
|
[onTokenizedBody, processPaymentInternal]
|
|
8558
8048
|
);
|
|
8559
|
-
|
|
8049
|
+
useEffect7(() => {
|
|
8560
8050
|
if (!flopay || paypalResumeAttempted.current) return;
|
|
8561
8051
|
const params = new URLSearchParams(window.location.search);
|
|
8562
8052
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -8604,13 +8094,13 @@ function PayPalButton({
|
|
|
8604
8094
|
}
|
|
8605
8095
|
})();
|
|
8606
8096
|
}, [flopay, dispatchTokenizedBody, onErrorChange]);
|
|
8607
|
-
const handlePayPalConfirm =
|
|
8097
|
+
const handlePayPalConfirm = useCallback5(async () => {
|
|
8608
8098
|
if (!flopay || !elements) return;
|
|
8609
8099
|
try {
|
|
8610
8100
|
setSubmitting(true);
|
|
8611
8101
|
onErrorChange?.(null);
|
|
8612
8102
|
if (!sessionId || !email) {
|
|
8613
|
-
throw new
|
|
8103
|
+
throw new FloPayError6("Missing sessionId or email for PayPal payment", "validation_error");
|
|
8614
8104
|
}
|
|
8615
8105
|
const result = await flopay.confirmPayPalPayment({
|
|
8616
8106
|
billingApiUrl: baseUrl,
|
|
@@ -8638,11 +8128,11 @@ function PayPalButton({
|
|
|
8638
8128
|
}
|
|
8639
8129
|
}, [flopay, elements, sessionId, nonce, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
|
|
8640
8130
|
if (!flopay || !elements) {
|
|
8641
|
-
return /* @__PURE__ */
|
|
8131
|
+
return /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
|
|
8642
8132
|
}
|
|
8643
|
-
return /* @__PURE__ */
|
|
8644
|
-
!ready && /* @__PURE__ */
|
|
8645
|
-
/* @__PURE__ */
|
|
8133
|
+
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
8134
|
+
!ready && /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
|
|
8135
|
+
/* @__PURE__ */ jsx10("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ jsx10(
|
|
8646
8136
|
"button",
|
|
8647
8137
|
{
|
|
8648
8138
|
type: "button",
|
|
@@ -8664,7 +8154,7 @@ function PayPalButton({
|
|
|
8664
8154
|
children: submitting ? "Processing..." : "PayPal"
|
|
8665
8155
|
}
|
|
8666
8156
|
) }),
|
|
8667
|
-
(submitting || isProcessing) && /* @__PURE__ */
|
|
8157
|
+
(submitting || isProcessing) && /* @__PURE__ */ jsx10("div", { style: {
|
|
8668
8158
|
position: "fixed",
|
|
8669
8159
|
inset: 0,
|
|
8670
8160
|
background: "rgba(0,0,0,0.4)",
|
|
@@ -8672,7 +8162,7 @@ function PayPalButton({
|
|
|
8672
8162
|
alignItems: "center",
|
|
8673
8163
|
justifyContent: "center",
|
|
8674
8164
|
zIndex: 1e3
|
|
8675
|
-
}, children: /* @__PURE__ */
|
|
8165
|
+
}, children: /* @__PURE__ */ jsx10("div", { style: {
|
|
8676
8166
|
background: "white",
|
|
8677
8167
|
borderRadius: 8,
|
|
8678
8168
|
padding: "1.5rem",
|
|
@@ -8684,19 +8174,19 @@ function PayPalButton({
|
|
|
8684
8174
|
}
|
|
8685
8175
|
|
|
8686
8176
|
// src/automatic-payment-button.tsx
|
|
8687
|
-
import { useCallback as
|
|
8688
|
-
import { PaymentAPI as
|
|
8689
|
-
import { FloPayError as
|
|
8690
|
-
import { Fragment as
|
|
8177
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef8, useState as useState6 } from "react";
|
|
8178
|
+
import { PaymentAPI as PaymentAPI6 } from "@flopay/js";
|
|
8179
|
+
import { FloPayError as FloPayError7, resolveBillingApiUrl as resolveBillingApiUrl4, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme3, resolveTheme as resolveTheme3 } from "@flopay/shared";
|
|
8180
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
8691
8181
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
|
|
8692
8182
|
function sleep2(ms) {
|
|
8693
8183
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8694
8184
|
}
|
|
8695
8185
|
function coerceError(err, fallbackMessage) {
|
|
8696
|
-
if (err instanceof
|
|
8186
|
+
if (err instanceof FloPayError7) {
|
|
8697
8187
|
return err;
|
|
8698
8188
|
}
|
|
8699
|
-
return new
|
|
8189
|
+
return new FloPayError7(
|
|
8700
8190
|
err instanceof Error ? err.message : fallbackMessage,
|
|
8701
8191
|
"api_error"
|
|
8702
8192
|
);
|
|
@@ -8799,36 +8289,36 @@ function FloPayAutomaticPaymentButton({
|
|
|
8799
8289
|
utmMetadata
|
|
8800
8290
|
]
|
|
8801
8291
|
);
|
|
8802
|
-
const [isProcessing, setIsProcessing] =
|
|
8803
|
-
const [overlayStatus, setOverlayStatus] =
|
|
8804
|
-
const [overlayError, setOverlayError] =
|
|
8805
|
-
const [fallbackSession, setFallbackSession] =
|
|
8292
|
+
const [isProcessing, setIsProcessing] = useState6(false);
|
|
8293
|
+
const [overlayStatus, setOverlayStatus] = useState6(null);
|
|
8294
|
+
const [overlayError, setOverlayError] = useState6(null);
|
|
8295
|
+
const [fallbackSession, setFallbackSession] = useState6(null);
|
|
8806
8296
|
const isMountedRef = useRef8(true);
|
|
8807
8297
|
const threeDsAbortRef = useRef8(null);
|
|
8808
8298
|
const fallbackSessionRef = useRef8(fallbackSession);
|
|
8809
8299
|
const onSuccessRef = useRef8(onSuccess);
|
|
8810
8300
|
const onErrorRef = useRef8(onError);
|
|
8811
8301
|
const onDeclineRef = useRef8(onDecline);
|
|
8812
|
-
|
|
8302
|
+
useEffect8(() => {
|
|
8813
8303
|
fallbackSessionRef.current = fallbackSession;
|
|
8814
8304
|
}, [fallbackSession]);
|
|
8815
|
-
|
|
8305
|
+
useEffect8(() => {
|
|
8816
8306
|
onSuccessRef.current = onSuccess;
|
|
8817
8307
|
}, [onSuccess]);
|
|
8818
|
-
|
|
8308
|
+
useEffect8(() => {
|
|
8819
8309
|
onErrorRef.current = onError;
|
|
8820
8310
|
}, [onError]);
|
|
8821
|
-
|
|
8311
|
+
useEffect8(() => {
|
|
8822
8312
|
onDeclineRef.current = onDecline;
|
|
8823
8313
|
}, [onDecline]);
|
|
8824
|
-
|
|
8314
|
+
useEffect8(() => {
|
|
8825
8315
|
isMountedRef.current = true;
|
|
8826
8316
|
return () => {
|
|
8827
8317
|
isMountedRef.current = false;
|
|
8828
8318
|
threeDsAbortRef.current?.abort();
|
|
8829
8319
|
};
|
|
8830
8320
|
}, []);
|
|
8831
|
-
|
|
8321
|
+
useEffect8(() => {
|
|
8832
8322
|
if (typeof window === "undefined") {
|
|
8833
8323
|
return;
|
|
8834
8324
|
}
|
|
@@ -8842,13 +8332,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
8842
8332
|
window.removeEventListener("keydown", handleKeyDown);
|
|
8843
8333
|
};
|
|
8844
8334
|
}, []);
|
|
8845
|
-
const emitDecline =
|
|
8335
|
+
const emitDecline = useCallback6((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
|
|
8846
8336
|
onDeclineRef.current?.(buildDeclineEvent(method, error, {
|
|
8847
8337
|
code: error.code,
|
|
8848
8338
|
declineCode: error.declineCode
|
|
8849
8339
|
}));
|
|
8850
8340
|
}, []);
|
|
8851
|
-
const showSuccess =
|
|
8341
|
+
const showSuccess = useCallback6(async (event) => {
|
|
8852
8342
|
if (!isMountedRef.current) return;
|
|
8853
8343
|
setOverlayError(null);
|
|
8854
8344
|
setOverlayStatus("success");
|
|
@@ -8856,7 +8346,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
8856
8346
|
if (!isMountedRef.current) return;
|
|
8857
8347
|
onSuccessRef.current?.(event);
|
|
8858
8348
|
}, []);
|
|
8859
|
-
const showError =
|
|
8349
|
+
const showError = useCallback6(async (error, options) => {
|
|
8860
8350
|
if (!isMountedRef.current) return;
|
|
8861
8351
|
onErrorRef.current?.(error);
|
|
8862
8352
|
if (options?.emitDecline) {
|
|
@@ -8866,10 +8356,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
8866
8356
|
setOverlayStatus("error");
|
|
8867
8357
|
await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
|
|
8868
8358
|
}, [emitDecline]);
|
|
8869
|
-
const processResolvedSession =
|
|
8359
|
+
const processResolvedSession = useCallback6(async (apiResult, resolvedSessionId, options) => {
|
|
8870
8360
|
const session = apiResult.data.session ?? null;
|
|
8871
8361
|
if (!session) {
|
|
8872
|
-
throw new
|
|
8362
|
+
throw new FloPayError7("No session data returned", "api_error");
|
|
8873
8363
|
}
|
|
8874
8364
|
const effectiveNonce = session.clientSecret || nonce;
|
|
8875
8365
|
if (session.status === "complete") {
|
|
@@ -8882,19 +8372,19 @@ function FloPayAutomaticPaymentButton({
|
|
|
8882
8372
|
return;
|
|
8883
8373
|
}
|
|
8884
8374
|
if (session.status === "expired") {
|
|
8885
|
-
throw new
|
|
8375
|
+
throw new FloPayError7("Checkout session has expired.", "api_error", {
|
|
8886
8376
|
code: "checkout_session_expired"
|
|
8887
8377
|
});
|
|
8888
8378
|
}
|
|
8889
8379
|
try {
|
|
8890
8380
|
if (apiResult.autoProcessingPending) {
|
|
8891
|
-
const api = new
|
|
8381
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
8892
8382
|
const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
|
|
8893
8383
|
initialDelayMs: apiResult.autoProcessingPending.retryAfterMs
|
|
8894
8384
|
});
|
|
8895
8385
|
const completedSession = completed.data.session;
|
|
8896
8386
|
if (!completedSession || completedSession.status !== "complete") {
|
|
8897
|
-
throw new
|
|
8387
|
+
throw new FloPayError7("Automatic payment failed. Please try again.", "api_error", {
|
|
8898
8388
|
code: completedSession?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
8899
8389
|
});
|
|
8900
8390
|
}
|
|
@@ -8937,7 +8427,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
8937
8427
|
}
|
|
8938
8428
|
);
|
|
8939
8429
|
}
|
|
8940
|
-
const api = new
|
|
8430
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
8941
8431
|
const completed = await api.waitForCheckoutSessionCompletion(resolvedSessionId, {
|
|
8942
8432
|
initialDelayMs: 0,
|
|
8943
8433
|
nonce: effectiveNonce
|
|
@@ -9022,14 +8512,14 @@ function FloPayAutomaticPaymentButton({
|
|
|
9022
8512
|
showError,
|
|
9023
8513
|
showSuccess
|
|
9024
8514
|
]);
|
|
9025
|
-
const handleButtonClick =
|
|
8515
|
+
const handleButtonClick = useCallback6(async (event) => {
|
|
9026
8516
|
buttonProps.onClick?.(event);
|
|
9027
8517
|
if (event.defaultPrevented || disabled || isProcessing) {
|
|
9028
8518
|
return;
|
|
9029
8519
|
}
|
|
9030
8520
|
setFallbackSession(null);
|
|
9031
8521
|
if (sessionId && createSessionDraft) {
|
|
9032
|
-
const error = new
|
|
8522
|
+
const error = new FloPayError7(
|
|
9033
8523
|
"Provide either sessionId or create-session props, not both.",
|
|
9034
8524
|
"validation_error"
|
|
9035
8525
|
);
|
|
@@ -9041,7 +8531,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9041
8531
|
return;
|
|
9042
8532
|
}
|
|
9043
8533
|
if (!sessionId && !createSessionDraft) {
|
|
9044
|
-
const error = new
|
|
8534
|
+
const error = new FloPayError7(
|
|
9045
8535
|
"Provide a sessionId or the props required to create an automatic payment session.",
|
|
9046
8536
|
"validation_error"
|
|
9047
8537
|
);
|
|
@@ -9056,7 +8546,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9056
8546
|
setOverlayError(null);
|
|
9057
8547
|
setOverlayStatus("processing");
|
|
9058
8548
|
try {
|
|
9059
|
-
const api = new
|
|
8549
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
9060
8550
|
if (sessionId) {
|
|
9061
8551
|
const result = await api.getUnifiedCheckoutSession(sessionId, nonce);
|
|
9062
8552
|
await processResolvedSession(result, sessionId);
|
|
@@ -9070,7 +8560,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9070
8560
|
fromCreateSession: true
|
|
9071
8561
|
});
|
|
9072
8562
|
} catch (err) {
|
|
9073
|
-
if (err instanceof
|
|
8563
|
+
if (err instanceof FloPayError7 && err.code === "session_auto_completed") {
|
|
9074
8564
|
await showSuccess({
|
|
9075
8565
|
result: { status: "succeeded" },
|
|
9076
8566
|
session: null,
|
|
@@ -9104,7 +8594,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9104
8594
|
showError,
|
|
9105
8595
|
showSuccess
|
|
9106
8596
|
]);
|
|
9107
|
-
const handleFallbackComplete =
|
|
8597
|
+
const handleFallbackComplete = useCallback6((result) => {
|
|
9108
8598
|
const activeFallback = fallbackSessionRef.current;
|
|
9109
8599
|
setFallbackSession(null);
|
|
9110
8600
|
onSuccessRef.current?.({
|
|
@@ -9114,10 +8604,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
9114
8604
|
autoCompleted: false
|
|
9115
8605
|
});
|
|
9116
8606
|
}, []);
|
|
9117
|
-
const handleFallbackError =
|
|
8607
|
+
const handleFallbackError = useCallback6((error) => {
|
|
9118
8608
|
onErrorRef.current?.(error);
|
|
9119
8609
|
}, []);
|
|
9120
|
-
const handleFallbackDecline =
|
|
8610
|
+
const handleFallbackDecline = useCallback6((decline) => {
|
|
9121
8611
|
onDeclineRef.current?.(decline);
|
|
9122
8612
|
}, []);
|
|
9123
8613
|
const themeBundle = useMemo5(() => resolveTheme3(theme), [theme]);
|
|
@@ -9148,8 +8638,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
9148
8638
|
const resolvedPrimaryHoverColor = resolvedAppearanceVars?.colorPrimaryHover ?? darkenHex(resolvedPrimaryColor, 0.12);
|
|
9149
8639
|
const resolvedButtonBorderRadius = resolvedAppearanceVars?.borderRadius ?? "8px";
|
|
9150
8640
|
const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
9151
|
-
return /* @__PURE__ */
|
|
9152
|
-
/* @__PURE__ */
|
|
8641
|
+
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
8642
|
+
/* @__PURE__ */ jsx11(
|
|
9153
8643
|
"button",
|
|
9154
8644
|
{
|
|
9155
8645
|
...buttonProps,
|
|
@@ -9213,17 +8703,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
9213
8703
|
e.currentTarget.style.transform = "scale(1)";
|
|
9214
8704
|
}
|
|
9215
8705
|
},
|
|
9216
|
-
children: /* @__PURE__ */
|
|
8706
|
+
children: /* @__PURE__ */ jsx11(CardButtonContentSlot, { content: children })
|
|
9217
8707
|
}
|
|
9218
8708
|
),
|
|
9219
|
-
overlayStatus && /* @__PURE__ */
|
|
8709
|
+
overlayStatus && /* @__PURE__ */ jsx11(
|
|
9220
8710
|
ProcessingOverlay,
|
|
9221
8711
|
{
|
|
9222
8712
|
status: overlayStatus,
|
|
9223
8713
|
errorMessage: overlayError
|
|
9224
8714
|
}
|
|
9225
8715
|
),
|
|
9226
|
-
fallbackSession && /* @__PURE__ */
|
|
8716
|
+
fallbackSession && /* @__PURE__ */ jsx11(
|
|
9227
8717
|
"div",
|
|
9228
8718
|
{
|
|
9229
8719
|
"data-testid": "flopay-automatic-payment-fallback",
|
|
@@ -9244,7 +8734,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9244
8734
|
padding: "1.5rem",
|
|
9245
8735
|
zIndex: 1100
|
|
9246
8736
|
},
|
|
9247
|
-
children: /* @__PURE__ */
|
|
8737
|
+
children: /* @__PURE__ */ jsx11(
|
|
9248
8738
|
"div",
|
|
9249
8739
|
{
|
|
9250
8740
|
style: {
|
|
@@ -9260,7 +8750,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9260
8750
|
flexDirection: "column",
|
|
9261
8751
|
gap: "1rem"
|
|
9262
8752
|
},
|
|
9263
|
-
children: /* @__PURE__ */
|
|
8753
|
+
children: /* @__PURE__ */ jsx11(
|
|
9264
8754
|
FloPayCheckout,
|
|
9265
8755
|
{
|
|
9266
8756
|
sessionId: fallbackSession.sessionId,
|
|
@@ -9287,17 +8777,12 @@ function FloPayAutomaticPaymentButton({
|
|
|
9287
8777
|
}
|
|
9288
8778
|
export {
|
|
9289
8779
|
AddressElement,
|
|
9290
|
-
CardCvcElement,
|
|
9291
|
-
CardElement,
|
|
9292
|
-
CardExpiryElement,
|
|
9293
|
-
CardNumberElement,
|
|
9294
|
-
CheckoutForm,
|
|
9295
8780
|
DirectPayPalButton,
|
|
9296
8781
|
FloPayAutomaticPaymentButton,
|
|
9297
8782
|
FloPayCheckout,
|
|
9298
8783
|
FloPayProvider,
|
|
9299
8784
|
PayPalButton,
|
|
9300
|
-
PaymentElement,
|
|
8785
|
+
PaymentElement2 as PaymentElement,
|
|
9301
8786
|
SplitCardForm,
|
|
9302
8787
|
VaultCardFields,
|
|
9303
8788
|
useCheckout,
|