@flopay/react 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -165
- package/dist/index.cjs +1135 -1654
- 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 +923 -1435
- 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,25 @@ 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
|
+
// Always 'payment': the backend derives order vs subscription from the session's
|
|
1572
|
+
// products and returns it as the response providerObjectType. The order/subscription
|
|
1573
|
+
// split still drives the PayPal JS SDK call locally (see createOrder/createSubscription).
|
|
1574
|
+
intentKind: "payment"
|
|
1575
|
+
},
|
|
1576
|
+
{ idempotencyKey: paypalIntentIdempotencyKey }
|
|
1577
|
+
);
|
|
1578
|
+
if (isInactive()) {
|
|
1579
|
+
throw supersededRenderError();
|
|
1575
1580
|
}
|
|
1576
|
-
|
|
1577
|
-
if (!id) {
|
|
1581
|
+
if (intent.provider !== "paypal") {
|
|
1578
1582
|
throw new Error(fallbackMessage);
|
|
1579
1583
|
}
|
|
1580
1584
|
telemetrySource.log({
|
|
@@ -1585,7 +1589,24 @@ function DirectPayPalButtonImplementation({
|
|
|
1585
1589
|
requestCategory: "intent_create",
|
|
1586
1590
|
statusClass: "2xx"
|
|
1587
1591
|
});
|
|
1588
|
-
return
|
|
1592
|
+
return intent.providerObjectId;
|
|
1593
|
+
};
|
|
1594
|
+
const reportPayPalDecline = (error, context) => {
|
|
1595
|
+
const currentNonce = context?.nonce ?? nonceRef.current;
|
|
1596
|
+
if (!currentNonce) return;
|
|
1597
|
+
const effectiveSessionId = context?.sessionId ?? sessionId;
|
|
1598
|
+
const providerDeclineReason = getProviderDeclineCode(error) ?? getProviderErrorCode(error) ?? "provider_declined";
|
|
1599
|
+
void new PaymentAPI(baseUrl, { telemetry: false }).reportSessionIntentDecline(
|
|
1600
|
+
effectiveSessionId,
|
|
1601
|
+
currentNonce,
|
|
1602
|
+
{
|
|
1603
|
+
provider: "paypal",
|
|
1604
|
+
paymentMethodCategory: "wallet",
|
|
1605
|
+
paymentMethodType: "paypal",
|
|
1606
|
+
providerDeclineReason
|
|
1607
|
+
}
|
|
1608
|
+
).catch(() => {
|
|
1609
|
+
});
|
|
1589
1610
|
};
|
|
1590
1611
|
const effectRenderGeneration = renderGeneration;
|
|
1591
1612
|
appendDebug("loadScript:scheduled (deferred 1 tick)");
|
|
@@ -1614,9 +1635,11 @@ function DirectPayPalButtonImplementation({
|
|
|
1614
1635
|
...paypalSdkEnv === "sandbox" ? { dataNamespace: "paypal_sandbox" } : {}
|
|
1615
1636
|
});
|
|
1616
1637
|
loadPromise.then((paypal) => {
|
|
1617
|
-
appendDebug(`loadScript:resolved
|
|
1618
|
-
if (
|
|
1619
|
-
|
|
1638
|
+
appendDebug(`loadScript:resolved inactive=${isInactive()} ns=${!!paypal} buttons=${!!paypal?.Buttons}`);
|
|
1639
|
+
if (isInactive()) return;
|
|
1640
|
+
if (!paypal?.Buttons) {
|
|
1641
|
+
appendDebug("FAIL: namespace missing Buttons factory");
|
|
1642
|
+
handlePreRenderFailure("PayPal SDK did not expose the Buttons factory.");
|
|
1620
1643
|
return;
|
|
1621
1644
|
}
|
|
1622
1645
|
telemetrySource.log({
|
|
@@ -1626,7 +1649,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1626
1649
|
paymentMethodCategory: "paypal"
|
|
1627
1650
|
});
|
|
1628
1651
|
const handleApprove = async (data) => {
|
|
1629
|
-
if (
|
|
1652
|
+
if (isInactive() || activeRenderGenerationRef.current !== effectRenderGeneration) return;
|
|
1630
1653
|
const token = data.subscriptionID ?? data.orderID ?? "";
|
|
1631
1654
|
const context = token ? approvalContextByTokenRef.current.get(token) : attemptContextBySurfaceRef.current.get(effectRenderGeneration);
|
|
1632
1655
|
if (!context || !isAttemptActive(context.generation)) return;
|
|
@@ -1651,7 +1674,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1651
1674
|
} catch (err) {
|
|
1652
1675
|
forwardError(err instanceof Error ? err.message : "PayPal capture failed.");
|
|
1653
1676
|
} finally {
|
|
1654
|
-
setSubmitting(false);
|
|
1677
|
+
if (!isInactive()) setSubmitting(false);
|
|
1655
1678
|
}
|
|
1656
1679
|
};
|
|
1657
1680
|
const buttons = paypal.Buttons({
|
|
@@ -1662,11 +1685,20 @@ function DirectPayPalButtonImplementation({
|
|
|
1662
1685
|
// inline-session/account patches land before the order is created,
|
|
1663
1686
|
// matching the Stripe-rendered PayPal flow.
|
|
1664
1687
|
onClick: async (_data, actions) => {
|
|
1688
|
+
if (isInactive()) {
|
|
1689
|
+
await actions.reject();
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
beginPaypalIntentAttempt();
|
|
1665
1693
|
const runner = runBeforeButtonClickRef.current;
|
|
1666
1694
|
let prepared = {};
|
|
1667
1695
|
if (runner) {
|
|
1668
1696
|
try {
|
|
1669
1697
|
const beforeClick = await runner("paypal");
|
|
1698
|
+
if (isInactive()) {
|
|
1699
|
+
await actions.reject();
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1670
1702
|
if (!beforeClick.proceed) {
|
|
1671
1703
|
beforeClickRef.current = null;
|
|
1672
1704
|
attemptContextBySurfaceRef.current.delete(effectRenderGeneration);
|
|
@@ -1720,10 +1752,11 @@ function DirectPayPalButtonImplementation({
|
|
|
1720
1752
|
// prior backend round-trip (the `paypal_direct_required` retry
|
|
1721
1753
|
// path), feed it straight to PayPal instead of creating a new one.
|
|
1722
1754
|
// Otherwise fall back to the normal create-intent call.
|
|
1723
|
-
createOrder: isSubscription ? void 0 : existingOrderId ? () =>
|
|
1724
|
-
createSubscription: isSubscription ? existingOrderId ? () =>
|
|
1755
|
+
createOrder: isSubscription ? void 0 : existingOrderId ? () => resolveExistingOrder(existingOrderId).then(registerApprovalContext) : () => createPaypalIntent("Failed to create PayPal order.").then(registerApprovalContext),
|
|
1756
|
+
createSubscription: isSubscription ? existingOrderId ? () => resolveExistingOrder(existingOrderId).then(registerApprovalContext) : () => createPaypalIntent("Failed to create PayPal subscription.").then(registerApprovalContext) : void 0,
|
|
1725
1757
|
onApprove: handleApprove,
|
|
1726
1758
|
onCancel: () => {
|
|
1759
|
+
if (isInactive()) return;
|
|
1727
1760
|
const context = attemptContextBySurfaceRef.current.get(effectRenderGeneration) ?? beforeClickRef.current;
|
|
1728
1761
|
if (context) attemptContextBySurfaceRef.current.delete(context.surfaceKey);
|
|
1729
1762
|
beforeClickRef.current = null;
|
|
@@ -1737,7 +1770,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1737
1770
|
invalidateAttempt({ generation: context?.generation, remount: true, focus: false });
|
|
1738
1771
|
},
|
|
1739
1772
|
onError: (err) => {
|
|
1740
|
-
if (
|
|
1773
|
+
if (isInactive() || activeRenderGenerationRef.current !== effectRenderGeneration) return;
|
|
1741
1774
|
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1742
1775
|
appendDebug(`onError rendered=${rendered} msg=${message.slice(0, 120)}`);
|
|
1743
1776
|
if (rendered) {
|
|
@@ -1757,13 +1790,16 @@ function DirectPayPalButtonImplementation({
|
|
|
1757
1790
|
paymentMethodCategory: "paypal",
|
|
1758
1791
|
requestCategory: "provider_sdk"
|
|
1759
1792
|
});
|
|
1793
|
+
if (isProviderDecline(err)) {
|
|
1794
|
+
reportPayPalDecline(err, context);
|
|
1795
|
+
}
|
|
1760
1796
|
if (context) attemptContextBySurfaceRef.current.delete(context.surfaceKey);
|
|
1761
1797
|
beforeClickRef.current = null;
|
|
1762
1798
|
invalidateAttempt({ generation: context?.generation, remount: true, showRetry: true, focus: true });
|
|
1763
1799
|
notifyTechnicalFailure(err, { code: "paypal_runtime_failed" });
|
|
1764
1800
|
return;
|
|
1765
1801
|
}
|
|
1766
|
-
|
|
1802
|
+
handlePreRenderFailure(message);
|
|
1767
1803
|
}
|
|
1768
1804
|
});
|
|
1769
1805
|
const eligible = buttons.isEligible();
|
|
@@ -1776,17 +1812,19 @@ function DirectPayPalButtonImplementation({
|
|
|
1776
1812
|
});
|
|
1777
1813
|
if (!eligible) {
|
|
1778
1814
|
setReady(false);
|
|
1779
|
-
|
|
1815
|
+
handlePreRenderFailure(
|
|
1780
1816
|
"PayPal buttons are not eligible to render in this context (paypal_ineligible)."
|
|
1781
1817
|
);
|
|
1782
1818
|
return;
|
|
1783
1819
|
}
|
|
1784
1820
|
const typedButtons = buttons;
|
|
1821
|
+
ownedButtons = typedButtons;
|
|
1785
1822
|
if (debug) {
|
|
1786
1823
|
appendDebug(`container:dims ${formatDims(container)} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"}`);
|
|
1787
1824
|
}
|
|
1788
1825
|
if (debug && typeof MutationObserver !== "undefined") {
|
|
1789
1826
|
containerObserver = new MutationObserver((mutations) => {
|
|
1827
|
+
if (isInactive()) return;
|
|
1790
1828
|
for (const mutation of mutations) {
|
|
1791
1829
|
if (mutation.type === "childList") {
|
|
1792
1830
|
mutation.addedNodes.forEach((node) => {
|
|
@@ -1814,7 +1852,7 @@ function DirectPayPalButtonImplementation({
|
|
|
1814
1852
|
});
|
|
1815
1853
|
}
|
|
1816
1854
|
const snapshotContainer = (when) => {
|
|
1817
|
-
if (
|
|
1855
|
+
if (isInactive() || rendered) return;
|
|
1818
1856
|
const iframes = container.querySelectorAll("iframe");
|
|
1819
1857
|
const hasStorageAccess = typeof document !== "undefined" && "hasStorageAccess" in document;
|
|
1820
1858
|
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 +1872,25 @@ function DirectPayPalButtonImplementation({
|
|
|
1834
1872
|
watchdogTimers.push(setTimeout(() => snapshotContainer("15s"), 15e3));
|
|
1835
1873
|
}
|
|
1836
1874
|
appendDebug("render:start");
|
|
1875
|
+
watchdogTimers.push(setTimeout(() => {
|
|
1876
|
+
if (isInactive() || rendered) return;
|
|
1877
|
+
appendDebug("watchdog:11s retryable render timeout");
|
|
1878
|
+
handlePreRenderFailure(
|
|
1879
|
+
"PayPal Buttons render did not settle within 11000ms.",
|
|
1880
|
+
true
|
|
1881
|
+
);
|
|
1882
|
+
}, PAYPAL_RENDER_WATCHDOG_MS));
|
|
1837
1883
|
buttons.render(container).then(() => {
|
|
1838
|
-
appendDebug(`render:resolved
|
|
1884
|
+
appendDebug(`render:resolved inactive=${isInactive()}`);
|
|
1839
1885
|
stopDiagnostics();
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
});
|
|
1886
|
+
if (isInactive()) {
|
|
1887
|
+
closeOwnedButtons();
|
|
1843
1888
|
return;
|
|
1844
1889
|
}
|
|
1845
|
-
activeButtons = typedButtons;
|
|
1846
1890
|
rendered = true;
|
|
1847
1891
|
setReady(true);
|
|
1892
|
+
setRecovering(false);
|
|
1893
|
+
onInitializationStateChangeRef.current?.("ready");
|
|
1848
1894
|
telemetrySource.log({
|
|
1849
1895
|
name: "provider.ready",
|
|
1850
1896
|
stage: "provider_ready",
|
|
@@ -1862,24 +1908,22 @@ function DirectPayPalButtonImplementation({
|
|
|
1862
1908
|
const message = err instanceof Error ? err.message : "PayPal failed to render.";
|
|
1863
1909
|
appendDebug(`render:rejected msg=${message.slice(0, 120)}`);
|
|
1864
1910
|
stopDiagnostics();
|
|
1865
|
-
|
|
1911
|
+
handlePreRenderFailure(message);
|
|
1866
1912
|
});
|
|
1867
1913
|
}).catch((err) => {
|
|
1868
1914
|
const message = err instanceof Error ? err.message : "PayPal SDK failed to load.";
|
|
1869
1915
|
appendDebug(`loadScript:rejected msg=${message.slice(0, 120)}`);
|
|
1870
|
-
|
|
1916
|
+
handlePreRenderFailure(message);
|
|
1871
1917
|
});
|
|
1872
1918
|
}, 0);
|
|
1873
1919
|
return () => {
|
|
1874
1920
|
cancelled = true;
|
|
1875
1921
|
clearTimeout(startTimer);
|
|
1922
|
+
if (retryTimer) clearTimeout(retryTimer);
|
|
1876
1923
|
stopDiagnostics();
|
|
1877
|
-
|
|
1878
|
-
activeButtons.close().catch(() => {
|
|
1879
|
-
});
|
|
1880
|
-
}
|
|
1924
|
+
closeOwnedButtons();
|
|
1881
1925
|
};
|
|
1882
|
-
}, [baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId, renderGeneration, telemetrySource]);
|
|
1926
|
+
}, [allowAutomaticRetry, baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId, renderGeneration, telemetrySource]);
|
|
1883
1927
|
const debugPanel = debug ? /* @__PURE__ */ jsxs4(
|
|
1884
1928
|
"pre",
|
|
1885
1929
|
{
|
|
@@ -1904,8 +1948,8 @@ ${debugLines.join("\n")}`
|
|
|
1904
1948
|
]
|
|
1905
1949
|
}
|
|
1906
1950
|
) : null;
|
|
1907
|
-
if (failed) {
|
|
1908
|
-
return debug ? /* @__PURE__ */
|
|
1951
|
+
if (failed && !initializationConfigChanged) {
|
|
1952
|
+
return debug ? /* @__PURE__ */ jsx6("div", { children: debugPanel }) : null;
|
|
1909
1953
|
}
|
|
1910
1954
|
return (
|
|
1911
1955
|
// Single wrapper so the parent flex container sees exactly one flex item
|
|
@@ -1914,39 +1958,52 @@ ${debugLines.join("\n")}`
|
|
|
1914
1958
|
// intentionally has no margin/padding so the parent owns all spacing.
|
|
1915
1959
|
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1916
1960
|
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
|
-
|
|
1961
|
+
/* @__PURE__ */ jsxs4(
|
|
1962
|
+
"div",
|
|
1963
|
+
{
|
|
1964
|
+
"aria-hidden": recovering ? true : void 0,
|
|
1965
|
+
style: recovering ? {
|
|
1966
|
+
position: "relative",
|
|
1967
|
+
height: 0,
|
|
1968
|
+
opacity: 0,
|
|
1969
|
+
pointerEvents: "none"
|
|
1970
|
+
} : { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT },
|
|
1971
|
+
children: [
|
|
1972
|
+
!ready && !recovering && /* @__PURE__ */ jsx6(
|
|
1973
|
+
"div",
|
|
1974
|
+
{
|
|
1975
|
+
"data-testid": "flopay-direct-paypal-placeholder",
|
|
1976
|
+
style: {
|
|
1977
|
+
position: "absolute",
|
|
1978
|
+
inset: 0,
|
|
1979
|
+
borderRadius: 8,
|
|
1980
|
+
background: "#e5e7eb",
|
|
1981
|
+
animation: "flopay-pulse 1.5s ease-in-out infinite",
|
|
1982
|
+
pointerEvents: "none"
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
),
|
|
1986
|
+
/* @__PURE__ */ jsx6(
|
|
1987
|
+
"div",
|
|
1988
|
+
{
|
|
1989
|
+
ref: containerRef,
|
|
1990
|
+
"data-testid": "flopay-direct-paypal-container",
|
|
1991
|
+
tabIndex: -1,
|
|
1992
|
+
"aria-label": "PayPal payment method",
|
|
1993
|
+
style: {
|
|
1994
|
+
minHeight: DEFAULT_BUTTON_HEIGHT,
|
|
1995
|
+
display: "flex",
|
|
1996
|
+
opacity: ready ? 1 : 0
|
|
1997
|
+
},
|
|
1998
|
+
"aria-busy": submitting || isProcessing
|
|
1999
|
+
},
|
|
2000
|
+
renderGeneration
|
|
2001
|
+
)
|
|
2002
|
+
]
|
|
2003
|
+
},
|
|
2004
|
+
renderGeneration
|
|
2005
|
+
),
|
|
2006
|
+
showRetryFocusTarget && /* @__PURE__ */ jsx6(
|
|
1950
2007
|
"button",
|
|
1951
2008
|
{
|
|
1952
2009
|
ref: focusTargetRef,
|
|
@@ -1961,18 +2018,34 @@ ${debugLines.join("\n")}`
|
|
|
1961
2018
|
);
|
|
1962
2019
|
}
|
|
1963
2020
|
function DirectPayPalButton(props) {
|
|
1964
|
-
return /* @__PURE__ */
|
|
2021
|
+
return /* @__PURE__ */ jsx6(DirectPayPalButtonImplementation, { ...props });
|
|
1965
2022
|
}
|
|
1966
2023
|
function InstrumentedDirectPayPalButton(props) {
|
|
1967
|
-
return /* @__PURE__ */
|
|
2024
|
+
return /* @__PURE__ */ jsx6(DirectPayPalButtonImplementation, { ...props });
|
|
1968
2025
|
}
|
|
1969
2026
|
|
|
1970
2027
|
// src/split-card-form.tsx
|
|
1971
2028
|
import { FloPayError as FloPayError3, isSetupIntentClientSecret as isSetupIntentClientSecret2, resolveTheme } from "@flopay/shared";
|
|
1972
|
-
import { Fragment as Fragment2, jsx as
|
|
2029
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1973
2030
|
var STRIPE_RESUME_KEY = "flopay_stripe_resume";
|
|
1974
2031
|
var LEGACY_WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
1975
2032
|
var PAYPAL_RESUME_KEY = "flopay_paypal_resume";
|
|
2033
|
+
async function reportNonCardDecline({
|
|
2034
|
+
billingApiUrl,
|
|
2035
|
+
sessionId,
|
|
2036
|
+
nonce,
|
|
2037
|
+
request
|
|
2038
|
+
}) {
|
|
2039
|
+
if (!sessionId || !nonce) return;
|
|
2040
|
+
try {
|
|
2041
|
+
await new PaymentAPI2(billingApiUrl, { telemetry: false }).reportSessionIntentDecline(
|
|
2042
|
+
sessionId,
|
|
2043
|
+
nonce,
|
|
2044
|
+
request
|
|
2045
|
+
);
|
|
2046
|
+
} catch {
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
1976
2049
|
function isAccountValidationError(err) {
|
|
1977
2050
|
return err instanceof FloPayError3 && typeof err.statusCode === "number" && err.statusCode >= 400 && err.statusCode < 500;
|
|
1978
2051
|
}
|
|
@@ -2084,9 +2157,9 @@ function buildExternalMethodRecoveryMessage(method, popupBlocked) {
|
|
|
2084
2157
|
return popupBlocked ? `${base} Allow pop-ups for this site, then try again.` : base;
|
|
2085
2158
|
}
|
|
2086
2159
|
function useExternalAttemptReconciliation(onMissingTerminal) {
|
|
2087
|
-
const generationRef =
|
|
2088
|
-
const invalidatedGenerationRef =
|
|
2089
|
-
const attemptRef =
|
|
2160
|
+
const generationRef = useRef4(0);
|
|
2161
|
+
const invalidatedGenerationRef = useRef4(null);
|
|
2162
|
+
const attemptRef = useRef4(null);
|
|
2090
2163
|
const clearAttemptTimer = useCallback3((targetAttempt = attemptRef.current) => {
|
|
2091
2164
|
const attempt = targetAttempt;
|
|
2092
2165
|
if (attempt?.timer) {
|
|
@@ -2160,7 +2233,7 @@ function useExternalAttemptReconciliation(onMissingTerminal) {
|
|
|
2160
2233
|
attempt.yieldedControl = true;
|
|
2161
2234
|
clearAttemptTimer(attempt);
|
|
2162
2235
|
}, [clearAttemptTimer]);
|
|
2163
|
-
|
|
2236
|
+
useEffect4(() => {
|
|
2164
2237
|
const handleVisibilityChange = () => {
|
|
2165
2238
|
if (document.visibilityState === "visible") {
|
|
2166
2239
|
scheduleRecoveryIfReturned();
|
|
@@ -2202,7 +2275,7 @@ function normalizeBeforeButtonClickError(method, err) {
|
|
|
2202
2275
|
);
|
|
2203
2276
|
}
|
|
2204
2277
|
function FloPayKeyframes() {
|
|
2205
|
-
return /* @__PURE__ */
|
|
2278
|
+
return /* @__PURE__ */ jsx7("style", { children: FLOPAY_KEYFRAMES });
|
|
2206
2279
|
}
|
|
2207
2280
|
function toCssSize(value) {
|
|
2208
2281
|
if (typeof value === "number") return `${value}px`;
|
|
@@ -2225,7 +2298,7 @@ function ExpressCheckoutReadySwap({
|
|
|
2225
2298
|
}) {
|
|
2226
2299
|
if (state === "unavailable" || state === "load_error") return null;
|
|
2227
2300
|
return /* @__PURE__ */ jsxs5("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
2228
|
-
/* @__PURE__ */
|
|
2301
|
+
/* @__PURE__ */ jsx7(
|
|
2229
2302
|
"div",
|
|
2230
2303
|
{
|
|
2231
2304
|
"data-testid": placeholderTestId,
|
|
@@ -2244,7 +2317,7 @@ function ExpressCheckoutReadySwap({
|
|
|
2244
2317
|
}
|
|
2245
2318
|
}
|
|
2246
2319
|
),
|
|
2247
|
-
/* @__PURE__ */
|
|
2320
|
+
/* @__PURE__ */ jsx7(
|
|
2248
2321
|
"div",
|
|
2249
2322
|
{
|
|
2250
2323
|
style: {
|
|
@@ -2262,11 +2335,9 @@ function ExpressCheckoutReadySwap({
|
|
|
2262
2335
|
function isExpressCheckoutRowVisible(state) {
|
|
2263
2336
|
return state !== "unavailable" && state !== "load_error";
|
|
2264
2337
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
}
|
|
2269
|
-
);
|
|
2338
|
+
function SplitCardForm(props) {
|
|
2339
|
+
return /* @__PURE__ */ jsx7(SplitCardFormInner, { ...props });
|
|
2340
|
+
}
|
|
2270
2341
|
function PayPalButtonInner({
|
|
2271
2342
|
sessionId,
|
|
2272
2343
|
nonce,
|
|
@@ -2286,18 +2357,17 @@ function PayPalButtonInner({
|
|
|
2286
2357
|
const stripe = useStripeRaw();
|
|
2287
2358
|
const elements = useStripeElements();
|
|
2288
2359
|
const [loadState, setLoadState] = useState3("loading");
|
|
2289
|
-
|
|
2360
|
+
useEffect4(() => {
|
|
2290
2361
|
onLoadStateChange?.(loadState);
|
|
2291
2362
|
}, [loadState, onLoadStateChange]);
|
|
2292
2363
|
const [submitting, setSubmitting] = useState3(false);
|
|
2293
|
-
const paypalResumeAttempted =
|
|
2294
|
-
const focusTargetRef =
|
|
2295
|
-
const recoveryActionRef =
|
|
2364
|
+
const paypalResumeAttempted = useRef4(false);
|
|
2365
|
+
const focusTargetRef = useRef4(null);
|
|
2366
|
+
const recoveryActionRef = useRef4(null);
|
|
2296
2367
|
const [surfaceKey, setSurfaceKey] = useState3(0);
|
|
2297
2368
|
const [showRecoveryAction, setShowRecoveryAction] = useState3(false);
|
|
2298
|
-
const pendingProviderFocusRef =
|
|
2299
|
-
const attemptContextBySurfaceRef =
|
|
2300
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
2369
|
+
const pendingProviderFocusRef = useRef4(false);
|
|
2370
|
+
const attemptContextBySurfaceRef = useRef4(/* @__PURE__ */ new Map());
|
|
2301
2371
|
const {
|
|
2302
2372
|
startAttempt,
|
|
2303
2373
|
finishAttempt,
|
|
@@ -2312,7 +2382,7 @@ function PayPalButtonInner({
|
|
|
2312
2382
|
setShowRecoveryAction(true);
|
|
2313
2383
|
setSurfaceKey((key) => key + 1);
|
|
2314
2384
|
});
|
|
2315
|
-
|
|
2385
|
+
useEffect4(() => {
|
|
2316
2386
|
if (showRecoveryAction) recoveryActionRef.current?.focus();
|
|
2317
2387
|
}, [showRecoveryAction, surfaceKey]);
|
|
2318
2388
|
const resetSurface = useCallback3(() => {
|
|
@@ -2330,7 +2400,7 @@ function PayPalButtonInner({
|
|
|
2330
2400
|
(target ?? focusTargetRef.current)?.focus();
|
|
2331
2401
|
}, 0);
|
|
2332
2402
|
}, []);
|
|
2333
|
-
|
|
2403
|
+
useEffect4(() => {
|
|
2334
2404
|
if (!pendingProviderFocusRef.current) return;
|
|
2335
2405
|
pendingProviderFocusRef.current = false;
|
|
2336
2406
|
focusProviderSurface();
|
|
@@ -2340,7 +2410,7 @@ function PayPalButtonInner({
|
|
|
2340
2410
|
onErrorChange?.(null);
|
|
2341
2411
|
focusProviderSurface();
|
|
2342
2412
|
}, [focusProviderSurface, onErrorChange]);
|
|
2343
|
-
|
|
2413
|
+
useEffect4(() => {
|
|
2344
2414
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
2345
2415
|
const params = new URLSearchParams(window.location.search);
|
|
2346
2416
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -2468,32 +2538,21 @@ function PayPalButtonInner({
|
|
|
2468
2538
|
event.paymentFailed({ reason: "fail" });
|
|
2469
2539
|
return;
|
|
2470
2540
|
}
|
|
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;
|
|
2541
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
2542
|
+
effectiveSessionId,
|
|
2543
|
+
effectiveNonce ?? "",
|
|
2544
|
+
{
|
|
2545
|
+
provider: "stripe",
|
|
2546
|
+
paymentMethodCategory: "wallet",
|
|
2547
|
+
paymentMethodType: "paypal",
|
|
2548
|
+
paymentMethodId: paymentMethod?.id ?? null,
|
|
2549
|
+
intentKind: "payment"
|
|
2550
|
+
}
|
|
2551
|
+
);
|
|
2552
|
+
if (intent.provider !== "stripe") {
|
|
2553
|
+
throw new Error("Invalid provider returned for PayPal intent");
|
|
2493
2554
|
}
|
|
2494
|
-
const
|
|
2495
|
-
const intentClientSecret = intentJson.data?.id;
|
|
2496
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2555
|
+
const intentClientSecret = intent.clientSecret;
|
|
2497
2556
|
const confirmParams = {
|
|
2498
2557
|
return_url: window.location.href
|
|
2499
2558
|
};
|
|
@@ -2530,6 +2589,17 @@ function PayPalButtonInner({
|
|
|
2530
2589
|
code: getProviderErrorCode(confirmError),
|
|
2531
2590
|
declineCode: getProviderDeclineCode(confirmError)
|
|
2532
2591
|
}));
|
|
2592
|
+
await reportNonCardDecline({
|
|
2593
|
+
billingApiUrl,
|
|
2594
|
+
sessionId: effectiveSessionId,
|
|
2595
|
+
nonce: effectiveNonce,
|
|
2596
|
+
request: {
|
|
2597
|
+
provider: "stripe",
|
|
2598
|
+
paymentMethodCategory: "wallet",
|
|
2599
|
+
paymentMethodType: "paypal",
|
|
2600
|
+
providerDeclineReason: getProviderErrorCode(confirmError) ?? "provider_declined"
|
|
2601
|
+
}
|
|
2602
|
+
});
|
|
2533
2603
|
} else {
|
|
2534
2604
|
recoverTechnicalFailure(confirmError, "stripe_paypal_confirm_failed", attemptContext?.generation);
|
|
2535
2605
|
}
|
|
@@ -2558,9 +2628,9 @@ function PayPalButtonInner({
|
|
|
2558
2628
|
} finally {
|
|
2559
2629
|
setSubmitting(false);
|
|
2560
2630
|
}
|
|
2561
|
-
}, [stripe, elements, sessionId, nonce, email,
|
|
2631
|
+
}, [stripe, elements, sessionId, nonce, email, billingApiUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick, recoverTechnicalFailure, finishAttempt, isAttemptCurrent, isAttemptInvalidated, surfaceKey]);
|
|
2562
2632
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2563
|
-
/* @__PURE__ */
|
|
2633
|
+
/* @__PURE__ */ jsx7(
|
|
2564
2634
|
ExpressCheckoutReadySwap,
|
|
2565
2635
|
{
|
|
2566
2636
|
state: loadState,
|
|
@@ -2575,7 +2645,7 @@ function PayPalButtonInner({
|
|
|
2575
2645
|
"aria-label": "PayPal payment method",
|
|
2576
2646
|
style: { borderRadius: 8, outlineOffset: 4 },
|
|
2577
2647
|
children: [
|
|
2578
|
-
showRecoveryAction && /* @__PURE__ */
|
|
2648
|
+
showRecoveryAction && /* @__PURE__ */ jsx7(
|
|
2579
2649
|
"button",
|
|
2580
2650
|
{
|
|
2581
2651
|
ref: recoveryActionRef,
|
|
@@ -2586,7 +2656,7 @@ function PayPalButtonInner({
|
|
|
2586
2656
|
children: "Try PayPal again"
|
|
2587
2657
|
}
|
|
2588
2658
|
),
|
|
2589
|
-
/* @__PURE__ */
|
|
2659
|
+
/* @__PURE__ */ jsx7(
|
|
2590
2660
|
ExpressCheckoutElement,
|
|
2591
2661
|
{
|
|
2592
2662
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
@@ -2626,7 +2696,7 @@ function PayPalButtonInner({
|
|
|
2626
2696
|
)
|
|
2627
2697
|
}
|
|
2628
2698
|
),
|
|
2629
|
-
submitting && /* @__PURE__ */
|
|
2699
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
2630
2700
|
] });
|
|
2631
2701
|
}
|
|
2632
2702
|
function WalletButtonInner({
|
|
@@ -2634,6 +2704,7 @@ function WalletButtonInner({
|
|
|
2634
2704
|
nonce,
|
|
2635
2705
|
email,
|
|
2636
2706
|
billingApiUrl,
|
|
2707
|
+
intentKind,
|
|
2637
2708
|
expressMethods,
|
|
2638
2709
|
onTokenizedBody,
|
|
2639
2710
|
onErrorChange,
|
|
@@ -2648,20 +2719,19 @@ function WalletButtonInner({
|
|
|
2648
2719
|
const stripe = useStripeRaw();
|
|
2649
2720
|
const elements = useStripeElements();
|
|
2650
2721
|
const [loadState, setLoadState] = useState3("loading");
|
|
2651
|
-
|
|
2722
|
+
useEffect4(() => {
|
|
2652
2723
|
onLoadStateChange?.(loadState);
|
|
2653
2724
|
}, [loadState, onLoadStateChange]);
|
|
2654
2725
|
const [submitting, setSubmitting] = useState3(false);
|
|
2655
|
-
const
|
|
2656
|
-
const
|
|
2657
|
-
const recoveryActionRef = useRef5(null);
|
|
2726
|
+
const focusTargetRef = useRef4(null);
|
|
2727
|
+
const recoveryActionRef = useRef4(null);
|
|
2658
2728
|
const [surfaceKey, setSurfaceKey] = useState3(0);
|
|
2659
2729
|
const [showRecoveryAction, setShowRecoveryAction] = useState3(false);
|
|
2660
2730
|
const [recoveryActionMethod, setRecoveryActionMethod] = useState3("google_pay");
|
|
2661
|
-
const pendingProviderFocusRef =
|
|
2662
|
-
const lastWalletProviderMethodRef =
|
|
2663
|
-
const lastWalletMethodRef =
|
|
2664
|
-
const attemptContextBySurfaceRef =
|
|
2731
|
+
const pendingProviderFocusRef = useRef4(false);
|
|
2732
|
+
const lastWalletProviderMethodRef = useRef4("google_pay");
|
|
2733
|
+
const lastWalletMethodRef = useRef4("google_pay");
|
|
2734
|
+
const attemptContextBySurfaceRef = useRef4(/* @__PURE__ */ new Map());
|
|
2665
2735
|
const {
|
|
2666
2736
|
startAttempt,
|
|
2667
2737
|
finishAttempt,
|
|
@@ -2677,7 +2747,7 @@ function WalletButtonInner({
|
|
|
2677
2747
|
setShowRecoveryAction(true);
|
|
2678
2748
|
setSurfaceKey((key) => key + 1);
|
|
2679
2749
|
});
|
|
2680
|
-
|
|
2750
|
+
useEffect4(() => {
|
|
2681
2751
|
if (showRecoveryAction) recoveryActionRef.current?.focus();
|
|
2682
2752
|
}, [showRecoveryAction, surfaceKey]);
|
|
2683
2753
|
const resetSurface = useCallback3(() => {
|
|
@@ -2696,7 +2766,7 @@ function WalletButtonInner({
|
|
|
2696
2766
|
(target ?? focusTargetRef.current)?.focus();
|
|
2697
2767
|
}, 0);
|
|
2698
2768
|
}, []);
|
|
2699
|
-
|
|
2769
|
+
useEffect4(() => {
|
|
2700
2770
|
if (!pendingProviderFocusRef.current) return;
|
|
2701
2771
|
pendingProviderFocusRef.current = false;
|
|
2702
2772
|
focusProviderSurface();
|
|
@@ -2753,30 +2823,21 @@ function WalletButtonInner({
|
|
|
2753
2823
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
2754
2824
|
throw new Error("Missing sessionId or email for wallet payment");
|
|
2755
2825
|
}
|
|
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;
|
|
2826
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
2827
|
+
effectiveSessionId,
|
|
2828
|
+
effectiveNonce ?? "",
|
|
2829
|
+
{
|
|
2830
|
+
provider: "stripe",
|
|
2831
|
+
paymentMethodCategory: "wallet",
|
|
2832
|
+
paymentMethodType: walletType ?? buttonMethod,
|
|
2833
|
+
paymentMethodId: paymentMethod.id,
|
|
2834
|
+
intentKind
|
|
2835
|
+
}
|
|
2836
|
+
);
|
|
2837
|
+
if (intent.provider !== "stripe") {
|
|
2838
|
+
throw new Error("Invalid provider returned for wallet intent");
|
|
2776
2839
|
}
|
|
2777
|
-
const
|
|
2778
|
-
const intentClientSecret = intentJson.data?.id;
|
|
2779
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2840
|
+
const intentClientSecret = intent.clientSecret;
|
|
2780
2841
|
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
2842
|
if (confirmError) {
|
|
2782
2843
|
if (isProviderDecline(confirmError)) {
|
|
@@ -2786,6 +2847,17 @@ function WalletButtonInner({
|
|
|
2786
2847
|
code: getProviderErrorCode(confirmError),
|
|
2787
2848
|
declineCode: getProviderDeclineCode(confirmError)
|
|
2788
2849
|
}));
|
|
2850
|
+
await reportNonCardDecline({
|
|
2851
|
+
billingApiUrl,
|
|
2852
|
+
sessionId: effectiveSessionId,
|
|
2853
|
+
nonce: effectiveNonce,
|
|
2854
|
+
request: {
|
|
2855
|
+
provider: "stripe",
|
|
2856
|
+
paymentMethodCategory: "wallet",
|
|
2857
|
+
paymentMethodType: walletType ?? buttonMethod,
|
|
2858
|
+
providerDeclineReason: getProviderErrorCode(confirmError) ?? "provider_declined"
|
|
2859
|
+
}
|
|
2860
|
+
});
|
|
2789
2861
|
} else {
|
|
2790
2862
|
recoverTechnicalFailure(walletType, confirmError, "stripe_wallet_confirm_failed", attemptContext?.generation);
|
|
2791
2863
|
}
|
|
@@ -2806,7 +2878,7 @@ function WalletButtonInner({
|
|
|
2806
2878
|
setSubmitting(false);
|
|
2807
2879
|
}
|
|
2808
2880
|
},
|
|
2809
|
-
[stripe, elements, sessionId, nonce, email,
|
|
2881
|
+
[stripe, elements, sessionId, nonce, email, billingApiUrl, intentKind, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick, recoverTechnicalFailure, finishAttempt, isAttemptCurrent, isAttemptInvalidated, surfaceKey]
|
|
2810
2882
|
);
|
|
2811
2883
|
const expressMethodMap = useMemo3(() => {
|
|
2812
2884
|
const allKeys = ["applePay", "googlePay", "paypal", "link", "amazonPay", "klarna"];
|
|
@@ -2827,7 +2899,7 @@ function WalletButtonInner({
|
|
|
2827
2899
|
[expressMethods]
|
|
2828
2900
|
);
|
|
2829
2901
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2830
|
-
/* @__PURE__ */
|
|
2902
|
+
/* @__PURE__ */ jsx7(
|
|
2831
2903
|
ExpressCheckoutReadySwap,
|
|
2832
2904
|
{
|
|
2833
2905
|
state: loadState,
|
|
@@ -2857,7 +2929,7 @@ function WalletButtonInner({
|
|
|
2857
2929
|
]
|
|
2858
2930
|
}
|
|
2859
2931
|
),
|
|
2860
|
-
/* @__PURE__ */
|
|
2932
|
+
/* @__PURE__ */ jsx7(
|
|
2861
2933
|
ExpressCheckoutElement,
|
|
2862
2934
|
{
|
|
2863
2935
|
onReady: (event) => {
|
|
@@ -2921,7 +2993,7 @@ function WalletButtonInner({
|
|
|
2921
2993
|
)
|
|
2922
2994
|
}
|
|
2923
2995
|
),
|
|
2924
|
-
submitting && /* @__PURE__ */
|
|
2996
|
+
submitting && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: "processing" })
|
|
2925
2997
|
] });
|
|
2926
2998
|
}
|
|
2927
2999
|
function StripeMethodButton({
|
|
@@ -2943,7 +3015,7 @@ function StripeMethodButton({
|
|
|
2943
3015
|
const resolvedBackground = brand?.backgroundColor ?? backgroundColor ?? "#ffffff";
|
|
2944
3016
|
const resolvedBorder = brand?.borderColor ?? borderColor ?? "#d1d5db";
|
|
2945
3017
|
const resolvedTextColor = brand?.textColor ?? textColor ?? "#262833";
|
|
2946
|
-
return /* @__PURE__ */
|
|
3018
|
+
return /* @__PURE__ */ jsx7(
|
|
2947
3019
|
"button",
|
|
2948
3020
|
{
|
|
2949
3021
|
type: "button",
|
|
@@ -2990,7 +3062,7 @@ function StripeMethodButton({
|
|
|
2990
3062
|
// Pulse-skeleton parity with the wallet ECE: no spinner, just the
|
|
2991
3063
|
// status text on top of the pulsing background. Keeps the loading
|
|
2992
3064
|
// affordance shape-equivalent across both kinds of tile.
|
|
2993
|
-
/* @__PURE__ */
|
|
3065
|
+
/* @__PURE__ */ jsx7("span", { style: { margin: "0 auto" }, children: `Connecting to ${getStripeMethodDisplayName(method)}\u2026` })
|
|
2994
3066
|
) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2995
3067
|
/* @__PURE__ */ jsxs5(
|
|
2996
3068
|
"span",
|
|
@@ -3010,7 +3082,7 @@ function StripeMethodButton({
|
|
|
3010
3082
|
// bytes ship as a sibling file, out of the JS bundle. 3:2 box
|
|
3011
3083
|
// matching the datatrans logos' 120×80 viewBox; each ships its own
|
|
3012
3084
|
// white rounded-rect background so it stays legible on any tile.
|
|
3013
|
-
/* @__PURE__ */
|
|
3085
|
+
/* @__PURE__ */ jsx7(
|
|
3014
3086
|
"img",
|
|
3015
3087
|
{
|
|
3016
3088
|
src: vendoredLogoUrl,
|
|
@@ -3030,7 +3102,7 @@ function StripeMethodButton({
|
|
|
3030
3102
|
}
|
|
3031
3103
|
}
|
|
3032
3104
|
)
|
|
3033
|
-
) : brand?.logoSvg ? /* @__PURE__ */
|
|
3105
|
+
) : brand?.logoSvg ? /* @__PURE__ */ jsx7(
|
|
3034
3106
|
"span",
|
|
3035
3107
|
{
|
|
3036
3108
|
"aria-hidden": "true",
|
|
@@ -3045,11 +3117,11 @@ function StripeMethodButton({
|
|
|
3045
3117
|
dangerouslySetInnerHTML: { __html: brand.logoSvg }
|
|
3046
3118
|
}
|
|
3047
3119
|
) : null,
|
|
3048
|
-
/* @__PURE__ */
|
|
3120
|
+
/* @__PURE__ */ jsx7("span", { children: getStripeMethodDisplayName(method) })
|
|
3049
3121
|
]
|
|
3050
3122
|
}
|
|
3051
3123
|
),
|
|
3052
|
-
hasNextStep && /* @__PURE__ */
|
|
3124
|
+
hasNextStep && /* @__PURE__ */ jsx7(
|
|
3053
3125
|
"svg",
|
|
3054
3126
|
{
|
|
3055
3127
|
width: "14",
|
|
@@ -3069,7 +3141,7 @@ function StripeMethodButton({
|
|
|
3069
3141
|
opacity: 0.7
|
|
3070
3142
|
},
|
|
3071
3143
|
"aria-hidden": "true",
|
|
3072
|
-
children: /* @__PURE__ */
|
|
3144
|
+
children: /* @__PURE__ */ jsx7("path", { d: "M9 18l6-6-6-6" })
|
|
3073
3145
|
}
|
|
3074
3146
|
)
|
|
3075
3147
|
] })
|
|
@@ -3099,10 +3171,9 @@ function StripeMethodInlineForm({
|
|
|
3099
3171
|
const stripe = useStripeRaw();
|
|
3100
3172
|
const elements = useStripeElements();
|
|
3101
3173
|
const [submitting, setSubmitting] = useState3(false);
|
|
3102
|
-
const submittingRef =
|
|
3174
|
+
const submittingRef = useRef4(false);
|
|
3103
3175
|
const [isMethodComplete, setIsMethodComplete] = useState3(false);
|
|
3104
3176
|
const [loadState, setLoadState] = useState3("loading");
|
|
3105
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
3106
3177
|
const handlePay = useCallback3(async () => {
|
|
3107
3178
|
if (!stripe || !elements || isProcessing || submittingRef.current || !isMethodComplete) return;
|
|
3108
3179
|
submittingRef.current = true;
|
|
@@ -3133,26 +3204,22 @@ function StripeMethodInlineForm({
|
|
|
3133
3204
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
3134
3205
|
throw new Error("Missing sessionId or email for payment.");
|
|
3135
3206
|
}
|
|
3136
|
-
const
|
|
3137
|
-
const
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
paymentMethodType
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
onDecline?.(buildDeclineEvent("card", intentError));
|
|
3151
|
-
return;
|
|
3207
|
+
const paymentMethodType = paymentMethod.type || method;
|
|
3208
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
3209
|
+
effectiveSessionId,
|
|
3210
|
+
effectiveNonce ?? "",
|
|
3211
|
+
{
|
|
3212
|
+
provider: "stripe",
|
|
3213
|
+
paymentMethodCategory: "apm",
|
|
3214
|
+
paymentMethodType,
|
|
3215
|
+
paymentMethodId: null,
|
|
3216
|
+
intentKind: "payment"
|
|
3217
|
+
}
|
|
3218
|
+
);
|
|
3219
|
+
if (intent.provider !== "stripe") {
|
|
3220
|
+
throw new Error("Invalid provider returned for APM intent");
|
|
3152
3221
|
}
|
|
3153
|
-
const
|
|
3154
|
-
const intentClientSecret = intentJson.data?.id;
|
|
3155
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
3222
|
+
const intentClientSecret = intent.clientSecret;
|
|
3156
3223
|
if (typeof window !== "undefined") {
|
|
3157
3224
|
try {
|
|
3158
3225
|
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
@@ -3185,6 +3252,17 @@ function StripeMethodInlineForm({
|
|
|
3185
3252
|
const message = confirmError.message ?? "Payment failed.";
|
|
3186
3253
|
onErrorChange?.(message);
|
|
3187
3254
|
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
3255
|
+
await reportNonCardDecline({
|
|
3256
|
+
billingApiUrl,
|
|
3257
|
+
sessionId: effectiveSessionId,
|
|
3258
|
+
nonce: effectiveNonce,
|
|
3259
|
+
request: {
|
|
3260
|
+
provider: "stripe",
|
|
3261
|
+
paymentMethodCategory: "apm",
|
|
3262
|
+
paymentMethodType: method,
|
|
3263
|
+
providerDeclineReason: confirmError.code ?? "provider_declined"
|
|
3264
|
+
}
|
|
3265
|
+
});
|
|
3188
3266
|
return;
|
|
3189
3267
|
}
|
|
3190
3268
|
const piStatus = paymentIntent?.status;
|
|
@@ -3234,7 +3312,7 @@ function StripeMethodInlineForm({
|
|
|
3234
3312
|
sessionId,
|
|
3235
3313
|
nonce,
|
|
3236
3314
|
email,
|
|
3237
|
-
|
|
3315
|
+
billingApiUrl,
|
|
3238
3316
|
method,
|
|
3239
3317
|
onTokenizedBody,
|
|
3240
3318
|
onErrorChange,
|
|
@@ -3242,8 +3320,8 @@ function StripeMethodInlineForm({
|
|
|
3242
3320
|
]);
|
|
3243
3321
|
void onCancel;
|
|
3244
3322
|
return /* @__PURE__ */ jsxs5("div", { "data-testid": `flopay-stripe-method-form-${method}`, style: { display: "flex", flexDirection: "column" }, children: [
|
|
3245
|
-
/* @__PURE__ */
|
|
3246
|
-
|
|
3323
|
+
/* @__PURE__ */ jsx7(
|
|
3324
|
+
PaymentElement,
|
|
3247
3325
|
{
|
|
3248
3326
|
onReady: () => setLoadState("ready"),
|
|
3249
3327
|
onLoadError: () => {
|
|
@@ -3271,7 +3349,7 @@ function StripeMethodInlineForm({
|
|
|
3271
3349
|
}
|
|
3272
3350
|
}
|
|
3273
3351
|
),
|
|
3274
|
-
/* @__PURE__ */
|
|
3352
|
+
/* @__PURE__ */ jsx7(
|
|
3275
3353
|
"button",
|
|
3276
3354
|
{
|
|
3277
3355
|
type: "button",
|
|
@@ -3298,7 +3376,7 @@ function StripeMethodInlineForm({
|
|
|
3298
3376
|
children: submitting ? "Processing\u2026" : `Pay with ${getStripeMethodDisplayName(method)}`
|
|
3299
3377
|
}
|
|
3300
3378
|
),
|
|
3301
|
-
errorText && /* @__PURE__ */
|
|
3379
|
+
errorText && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.75rem 0 0", children: errorText })
|
|
3302
3380
|
] });
|
|
3303
3381
|
}
|
|
3304
3382
|
function StripePaymentElementInner({
|
|
@@ -3325,11 +3403,10 @@ function StripePaymentElementInner({
|
|
|
3325
3403
|
onExpandApm,
|
|
3326
3404
|
expandedApmMethod
|
|
3327
3405
|
}) {
|
|
3328
|
-
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
3329
3406
|
const [expandedMethod, setExpandedMethod] = useState3(null);
|
|
3330
3407
|
const [submittingMethod, setSubmittingMethod] = useState3(null);
|
|
3331
|
-
const submittingRef =
|
|
3332
|
-
|
|
3408
|
+
const submittingRef = useRef4(false);
|
|
3409
|
+
useEffect4(() => {
|
|
3333
3410
|
if (paymentElementMethods.length > 0 && stripeInstance) {
|
|
3334
3411
|
onLoadStateChange?.("ready");
|
|
3335
3412
|
} else if (!stripeInstance) {
|
|
@@ -3356,30 +3433,21 @@ function StripePaymentElementInner({
|
|
|
3356
3433
|
if (!effectiveSessionId || !effectiveEmail) {
|
|
3357
3434
|
throw new Error("Missing sessionId or email for payment.");
|
|
3358
3435
|
}
|
|
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.
|
|
3436
|
+
const intent = await new PaymentAPI2(billingApiUrl).createSessionIntent(
|
|
3437
|
+
effectiveSessionId,
|
|
3438
|
+
effectiveNonce ?? "",
|
|
3439
|
+
{
|
|
3440
|
+
provider: "stripe",
|
|
3441
|
+
paymentMethodCategory: "apm",
|
|
3370
3442
|
paymentMethodType: method,
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
onDecline?.(buildDeclineEvent("card", intentError));
|
|
3378
|
-
return;
|
|
3443
|
+
paymentMethodId: null,
|
|
3444
|
+
intentKind: "payment"
|
|
3445
|
+
}
|
|
3446
|
+
);
|
|
3447
|
+
if (intent.provider !== "stripe") {
|
|
3448
|
+
throw new Error("Invalid provider returned for APM intent");
|
|
3379
3449
|
}
|
|
3380
|
-
const
|
|
3381
|
-
const intentClientSecret = intentJson.data?.id;
|
|
3382
|
-
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
3450
|
+
const intentClientSecret = intent.clientSecret;
|
|
3383
3451
|
if (typeof window !== "undefined") {
|
|
3384
3452
|
try {
|
|
3385
3453
|
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
@@ -3420,6 +3488,17 @@ function StripePaymentElementInner({
|
|
|
3420
3488
|
const message = confirmError.message ?? "Payment failed.";
|
|
3421
3489
|
onErrorChange?.(message);
|
|
3422
3490
|
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
3491
|
+
await reportNonCardDecline({
|
|
3492
|
+
billingApiUrl,
|
|
3493
|
+
sessionId: effectiveSessionId,
|
|
3494
|
+
nonce: effectiveNonce,
|
|
3495
|
+
request: {
|
|
3496
|
+
provider: "stripe",
|
|
3497
|
+
paymentMethodCategory: "apm",
|
|
3498
|
+
paymentMethodType: method,
|
|
3499
|
+
providerDeclineReason: confirmError.code ?? "provider_declined"
|
|
3500
|
+
}
|
|
3501
|
+
});
|
|
3423
3502
|
return;
|
|
3424
3503
|
}
|
|
3425
3504
|
const piStatus = paymentIntent?.status;
|
|
@@ -3467,7 +3546,7 @@ function StripePaymentElementInner({
|
|
|
3467
3546
|
sessionId,
|
|
3468
3547
|
nonce,
|
|
3469
3548
|
email,
|
|
3470
|
-
|
|
3549
|
+
billingApiUrl,
|
|
3471
3550
|
billingName,
|
|
3472
3551
|
onTokenizedBody,
|
|
3473
3552
|
onErrorChange,
|
|
@@ -3495,7 +3574,7 @@ function StripePaymentElementInner({
|
|
|
3495
3574
|
paymentMethodTypes: [localExpandedMethod]
|
|
3496
3575
|
};
|
|
3497
3576
|
}, [localExpandedMethod, paymentElementBaseOptions]);
|
|
3498
|
-
return /* @__PURE__ */
|
|
3577
|
+
return /* @__PURE__ */ jsx7(
|
|
3499
3578
|
"div",
|
|
3500
3579
|
{
|
|
3501
3580
|
"data-testid": "flopay-stripe-payment-element-region",
|
|
@@ -3504,8 +3583,8 @@ function StripePaymentElementInner({
|
|
|
3504
3583
|
const isExpanded = expandedApmMethod === method;
|
|
3505
3584
|
const isSubmittingThis = submittingMethod === method;
|
|
3506
3585
|
const otherInProgress = submittingMethod !== null && submittingMethod !== method || expandedApmMethod !== null && expandedApmMethod !== void 0 && expandedApmMethod !== method;
|
|
3507
|
-
return /* @__PURE__ */ jsxs5(
|
|
3508
|
-
/* @__PURE__ */
|
|
3586
|
+
return /* @__PURE__ */ jsxs5(React7.Fragment, { children: [
|
|
3587
|
+
/* @__PURE__ */ jsx7(
|
|
3509
3588
|
StripeMethodButton,
|
|
3510
3589
|
{
|
|
3511
3590
|
method,
|
|
@@ -3522,12 +3601,12 @@ function StripePaymentElementInner({
|
|
|
3522
3601
|
fontFamily: buttonAppearance?.fontFamily
|
|
3523
3602
|
}
|
|
3524
3603
|
),
|
|
3525
|
-
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */
|
|
3604
|
+
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */ jsx7(
|
|
3526
3605
|
StripeElements,
|
|
3527
3606
|
{
|
|
3528
3607
|
stripe: stripeInstance,
|
|
3529
3608
|
options: localInlineElementsOptions,
|
|
3530
|
-
children: /* @__PURE__ */
|
|
3609
|
+
children: /* @__PURE__ */ jsx7(
|
|
3531
3610
|
StripeMethodInlineForm,
|
|
3532
3611
|
{
|
|
3533
3612
|
method,
|
|
@@ -3568,15 +3647,10 @@ function SplitCardFormInner({
|
|
|
3568
3647
|
firstName,
|
|
3569
3648
|
lastName,
|
|
3570
3649
|
chv,
|
|
3571
|
-
submitLabel = "CONFIRM PAYMENT",
|
|
3572
3650
|
className,
|
|
3573
|
-
children,
|
|
3574
3651
|
isProcessing: externalProcessing,
|
|
3575
3652
|
error: externalError,
|
|
3576
3653
|
onErrorChange,
|
|
3577
|
-
onFullNameChange,
|
|
3578
|
-
onFirstNameChange,
|
|
3579
|
-
onLastNameChange,
|
|
3580
3654
|
showPayPal = true,
|
|
3581
3655
|
showStripe = true,
|
|
3582
3656
|
enabledPaymentMethods,
|
|
@@ -3615,17 +3689,14 @@ function SplitCardFormInner({
|
|
|
3615
3689
|
directPaypal,
|
|
3616
3690
|
isSubscription = false,
|
|
3617
3691
|
session,
|
|
3618
|
-
debug = false
|
|
3619
|
-
innerRef
|
|
3692
|
+
debug = false
|
|
3620
3693
|
}) {
|
|
3621
3694
|
const flopay = useFloPay();
|
|
3622
3695
|
const paypalFlopay = usePayPalFloPay();
|
|
3623
|
-
const
|
|
3624
|
-
const checkout = useContext3(CheckoutContext);
|
|
3696
|
+
const checkout = useContext2(CheckoutContext);
|
|
3625
3697
|
const contextBillingUrl = useBillingApiUrl();
|
|
3626
3698
|
const [processing, setProcessing] = useState3(false);
|
|
3627
3699
|
const [error, setError] = useState3(null);
|
|
3628
|
-
const [is3DSActive, setIs3DSActive] = useState3(false);
|
|
3629
3700
|
const [selectedCountry, setSelectedCountry] = useState3(countryProp ?? "US");
|
|
3630
3701
|
const [zipCode, setZipCode] = useState3(zipProp ?? "");
|
|
3631
3702
|
const [addressLine1, setAddressLine1] = useState3(addressLine1Prop ?? "");
|
|
@@ -3633,18 +3704,19 @@ function SplitCardFormInner({
|
|
|
3633
3704
|
const [city, setCity] = useState3(cityProp ?? "");
|
|
3634
3705
|
const [stateValue, setStateValue] = useState3(stateProp ?? "");
|
|
3635
3706
|
const [accountPatch, setAccountPatch] = useState3({});
|
|
3636
|
-
const zipCodeRef =
|
|
3637
|
-
const selectedCountryRef =
|
|
3638
|
-
const addressLine1Ref =
|
|
3639
|
-
const addressLine2Ref =
|
|
3640
|
-
const cityRef =
|
|
3641
|
-
const stateRef =
|
|
3707
|
+
const zipCodeRef = useRef4(zipProp ?? "");
|
|
3708
|
+
const selectedCountryRef = useRef4(countryProp ?? "US");
|
|
3709
|
+
const addressLine1Ref = useRef4(addressLine1Prop ?? "");
|
|
3710
|
+
const addressLine2Ref = useRef4(addressLine2Prop ?? "");
|
|
3711
|
+
const cityRef = useRef4(cityProp ?? "");
|
|
3712
|
+
const stateRef = useRef4(stateProp ?? "");
|
|
3642
3713
|
const avsConfig = useMemo3(() => resolveAVSConfig(enableAVSProp), [enableAVSProp]);
|
|
3643
3714
|
const enableAVS = avsConfig !== null;
|
|
3644
3715
|
const vaultBlockReady = Boolean(session?.vault?.html);
|
|
3645
3716
|
const vaultGatewayAdvertised = Boolean(session?.gateways?.pcivault);
|
|
3717
|
+
const vaultCapabilityAvailable = vaultBlockReady || vaultGatewayAdvertised;
|
|
3646
3718
|
const vaultActive = Boolean(
|
|
3647
|
-
showStripe &&
|
|
3719
|
+
showStripe && vaultCapabilityAvailable && flopay && sessionId
|
|
3648
3720
|
);
|
|
3649
3721
|
const cardCapture = useMemo3(() => {
|
|
3650
3722
|
if (!flopay || !vaultActive || !sessionId) return null;
|
|
@@ -3676,7 +3748,9 @@ function SplitCardFormInner({
|
|
|
3676
3748
|
const [vaultMount, setVaultMount] = useState3(
|
|
3677
3749
|
() => toVaultMount(session?.vault)
|
|
3678
3750
|
);
|
|
3679
|
-
const [viewState, setViewState] = useState3(
|
|
3751
|
+
const [viewState, setViewState] = useState3(
|
|
3752
|
+
initialCardOpen && vaultCapabilityAvailable ? "card" : "buttons"
|
|
3753
|
+
);
|
|
3680
3754
|
const [expandedApmMethod, setExpandedApmMethod] = useState3(null);
|
|
3681
3755
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
3682
3756
|
const TRANSITION_MS = 280;
|
|
@@ -3700,18 +3774,16 @@ function SplitCardFormInner({
|
|
|
3700
3774
|
setExpandedApmMethod(null);
|
|
3701
3775
|
}, TRANSITION_MS);
|
|
3702
3776
|
}, []);
|
|
3703
|
-
|
|
3704
|
-
if (layout === "buttons" && initialCardOpen) {
|
|
3777
|
+
useEffect4(() => {
|
|
3778
|
+
if (layout === "buttons" && initialCardOpen && vaultCapabilityAvailable) {
|
|
3705
3779
|
setViewState("card");
|
|
3706
3780
|
}
|
|
3707
|
-
}, [layout, initialCardOpen]);
|
|
3708
|
-
const [fullName, setFullName] = useState3("");
|
|
3709
|
-
const [formReady, setFormReady] = useState3(false);
|
|
3781
|
+
}, [layout, initialCardOpen, vaultCapabilityAvailable]);
|
|
3710
3782
|
const [overlayStatus, setOverlayStatus] = useState3(null);
|
|
3711
|
-
const processingRef =
|
|
3783
|
+
const processingRef = useRef4(false);
|
|
3712
3784
|
const [paypalDirectRetry, setPaypalDirectRetry] = useState3(null);
|
|
3713
|
-
const paypalDirectRetryRef =
|
|
3714
|
-
|
|
3785
|
+
const paypalDirectRetryRef = useRef4(paypalDirectRetry);
|
|
3786
|
+
useEffect4(() => {
|
|
3715
3787
|
paypalDirectRetryRef.current = paypalDirectRetry;
|
|
3716
3788
|
}, [paypalDirectRetry]);
|
|
3717
3789
|
const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
|
|
@@ -3759,7 +3831,6 @@ function SplitCardFormInner({
|
|
|
3759
3831
|
}, [appearance, bStyles, layout]);
|
|
3760
3832
|
const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
|
|
3761
3833
|
const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
|
|
3762
|
-
const isSelfContained = !onTokenizedBody;
|
|
3763
3834
|
const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
|
|
3764
3835
|
const resolvedAccount = useMemo3(() => mergeAccountPatch({
|
|
3765
3836
|
userId,
|
|
@@ -3769,6 +3840,7 @@ function SplitCardFormInner({
|
|
|
3769
3840
|
country: countryProp,
|
|
3770
3841
|
zip: zipProp
|
|
3771
3842
|
}, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
|
|
3843
|
+
const resolvedBillingName = [resolvedAccount.firstName, resolvedAccount.lastName].filter((part) => Boolean(part?.trim())).join(" ");
|
|
3772
3844
|
const stripeInstance = useMemo3(() => {
|
|
3773
3845
|
if (!flopay) return null;
|
|
3774
3846
|
return flopay.getRawProvider();
|
|
@@ -3825,11 +3897,11 @@ function SplitCardFormInner({
|
|
|
3825
3897
|
},
|
|
3826
3898
|
[onErrorChange]
|
|
3827
3899
|
);
|
|
3828
|
-
|
|
3900
|
+
useEffect4(() => {
|
|
3829
3901
|
if (!vaultActive || !cardCapture) return;
|
|
3830
3902
|
cardCapture.setCardFieldOrder?.(cardFieldOrder ?? null, avsConfig == null);
|
|
3831
3903
|
}, [vaultActive, cardCapture, cardFieldOrder, avsConfig]);
|
|
3832
|
-
|
|
3904
|
+
useEffect4(() => {
|
|
3833
3905
|
if (viewState === "expanding" || viewState === "collapsing" || viewState === "apm-expanding" || viewState === "apm-collapsing") {
|
|
3834
3906
|
updateError(null);
|
|
3835
3907
|
}
|
|
@@ -3864,7 +3936,7 @@ function SplitCardFormInner({
|
|
|
3864
3936
|
},
|
|
3865
3937
|
[layout, onError, updateError]
|
|
3866
3938
|
);
|
|
3867
|
-
|
|
3939
|
+
useEffect4(() => {
|
|
3868
3940
|
if (!vaultActive || !sessionId) {
|
|
3869
3941
|
setVaultMount(null);
|
|
3870
3942
|
return;
|
|
@@ -3902,13 +3974,12 @@ function SplitCardFormInner({
|
|
|
3902
3974
|
nonce,
|
|
3903
3975
|
updateError
|
|
3904
3976
|
]);
|
|
3905
|
-
const vaultOutcomeRef =
|
|
3977
|
+
const vaultOutcomeRef = useRef4({
|
|
3906
3978
|
onComplete,
|
|
3907
3979
|
onError,
|
|
3908
3980
|
updateError,
|
|
3909
3981
|
emitDecline,
|
|
3910
3982
|
resolvedAccount,
|
|
3911
|
-
fullName,
|
|
3912
3983
|
avsConfig,
|
|
3913
3984
|
avsCheckProp,
|
|
3914
3985
|
sessionId,
|
|
@@ -3921,16 +3992,15 @@ function SplitCardFormInner({
|
|
|
3921
3992
|
updateError,
|
|
3922
3993
|
emitDecline,
|
|
3923
3994
|
resolvedAccount,
|
|
3924
|
-
fullName,
|
|
3925
3995
|
avsConfig,
|
|
3926
3996
|
avsCheckProp,
|
|
3927
3997
|
sessionId,
|
|
3928
3998
|
nonce,
|
|
3929
3999
|
baseUrl
|
|
3930
4000
|
};
|
|
3931
|
-
const vaultCompletedRef =
|
|
4001
|
+
const vaultCompletedRef = useRef4(false);
|
|
3932
4002
|
const buildVaultAccountSnapshot = useCallback3(() => {
|
|
3933
|
-
const { resolvedAccount: resolvedAccount2, avsConfig: avsConfig2,
|
|
4003
|
+
const { resolvedAccount: resolvedAccount2, avsConfig: avsConfig2, avsCheckProp: avsCheckProp2 } = vaultOutcomeRef.current;
|
|
3934
4004
|
const cc = selectedCountryRef.current || resolvedAccount2.country || "US";
|
|
3935
4005
|
const stateVisible = avsConfig2 ? isAVSFieldVisible(avsConfig2.state, cc) : false;
|
|
3936
4006
|
const line1Visible = avsConfig2 ? isAVSFieldVisible(avsConfig2.address_line_1, cc) : false;
|
|
@@ -3943,8 +4013,8 @@ function SplitCardFormInner({
|
|
|
3943
4013
|
accountData: {
|
|
3944
4014
|
userId: resolvedAccount2.userId ?? "",
|
|
3945
4015
|
email: resolvedAccount2.email ?? "",
|
|
3946
|
-
firstName: resolvedAccount2.firstName ??
|
|
3947
|
-
lastName: resolvedAccount2.lastName ??
|
|
4016
|
+
firstName: resolvedAccount2.firstName ?? "",
|
|
4017
|
+
lastName: resolvedAccount2.lastName ?? "",
|
|
3948
4018
|
...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
|
|
3949
4019
|
...cityVisible && cityRef.current ? { city: cityRef.current } : {},
|
|
3950
4020
|
...stateValue2 ? { state: stateValue2 } : {},
|
|
@@ -3965,11 +4035,11 @@ function SplitCardFormInner({
|
|
|
3965
4035
|
} : {}
|
|
3966
4036
|
};
|
|
3967
4037
|
}, []);
|
|
3968
|
-
|
|
4038
|
+
useEffect4(() => {
|
|
3969
4039
|
if (!vaultActive || !cardCapture) return;
|
|
3970
4040
|
cardCapture.setSubmitGate?.(avsInvalid);
|
|
3971
4041
|
}, [vaultActive, cardCapture, avsInvalid]);
|
|
3972
|
-
|
|
4042
|
+
useEffect4(() => {
|
|
3973
4043
|
if (!vaultActive || !cardCapture) return;
|
|
3974
4044
|
vaultCompletedRef.current = false;
|
|
3975
4045
|
let cancelled = false;
|
|
@@ -4072,21 +4142,25 @@ function SplitCardFormInner({
|
|
|
4072
4142
|
const [walletLoadState, setWalletLoadState] = useState3("loading");
|
|
4073
4143
|
const [paymentElementLoadState, setPaymentElementLoadState] = useState3("loading");
|
|
4074
4144
|
const [directPaypalReady, setDirectPaypalReady] = useState3(false);
|
|
4145
|
+
const [directPaypalInitializationState, setDirectPaypalInitializationState] = useState3("loading");
|
|
4075
4146
|
const [inAppBrowserDetected, setInAppBrowserDetected] = useState3();
|
|
4076
|
-
|
|
4147
|
+
useEffect4(() => {
|
|
4077
4148
|
setInAppBrowserDetected(isInAppBrowser());
|
|
4078
4149
|
}, []);
|
|
4079
4150
|
const shouldShowPayPal = showPayPal && (directPaypalConfigured || (hasEnabledMethodsPayload ? paypalEnabled : inAppBrowserDetected === false));
|
|
4080
4151
|
const shouldShowWallets = showStripe && showWallets;
|
|
4081
4152
|
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
4082
|
-
const
|
|
4153
|
+
const directPaypalUnavailable = directPaypalInitializationState === "retrying" || directPaypalInitializationState === "exhausted";
|
|
4154
|
+
const shouldRenderStripePayPal = shouldShowPayPal && !!paypalStripeInstance && (!directPaypalConfigured || directPaypalUnavailable);
|
|
4083
4155
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
4084
4156
|
const shouldRenderPaymentElement = showStripe && hasEnabledMethods && paymentElementMethodsForCurrency.length > 0 && !!stripeInstance;
|
|
4085
|
-
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
4157
|
+
const shouldDisplayPayPalRow = shouldRenderDirectPayPal && !directPaypalUnavailable ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
4086
4158
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
4087
4159
|
const shouldDisplayPaymentElementRow = shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
4088
|
-
const
|
|
4089
|
-
|
|
4160
|
+
const expressSurfaceUsable = (state) => state === "loading" || state === "ready";
|
|
4161
|
+
const hasUsableNonCardCapability = shouldRenderDirectPayPal || shouldRenderStripePayPal && expressSurfaceUsable(paypalLoadState) || shouldRenderWallets && expressSurfaceUsable(walletLoadState) || shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
4162
|
+
const validationFiredRef = useRef4(false);
|
|
4163
|
+
useEffect4(() => {
|
|
4090
4164
|
if (validationFiredRef.current) return;
|
|
4091
4165
|
if (!showStripe && !showPayPal) {
|
|
4092
4166
|
validationFiredRef.current = true;
|
|
@@ -4104,10 +4178,29 @@ function SplitCardFormInner({
|
|
|
4104
4178
|
);
|
|
4105
4179
|
onError?.(err);
|
|
4106
4180
|
updateError(err.message);
|
|
4181
|
+
} else if (inAppBrowserDetected !== void 0 && !vaultCapabilityAvailable && !hasUsableNonCardCapability) {
|
|
4182
|
+
validationFiredRef.current = true;
|
|
4183
|
+
const err = new FloPayError3(
|
|
4184
|
+
"FloPay: this checkout session has no vault card capability and no usable supported non-card payment methods. Upgrade the billing backend integration.",
|
|
4185
|
+
"api_error",
|
|
4186
|
+
{ code: "UnsupportedBackendVaultCapability" }
|
|
4187
|
+
);
|
|
4188
|
+
onError?.(err);
|
|
4189
|
+
updateError(err.message);
|
|
4107
4190
|
}
|
|
4108
|
-
}, [
|
|
4109
|
-
|
|
4110
|
-
|
|
4191
|
+
}, [
|
|
4192
|
+
showStripe,
|
|
4193
|
+
showPayPal,
|
|
4194
|
+
directPaypalConfigured,
|
|
4195
|
+
paypalStripeInstance,
|
|
4196
|
+
inAppBrowserDetected,
|
|
4197
|
+
vaultCapabilityAvailable,
|
|
4198
|
+
hasUsableNonCardCapability,
|
|
4199
|
+
onError,
|
|
4200
|
+
updateError
|
|
4201
|
+
]);
|
|
4202
|
+
const deprecationLoggedRef = useRef4(false);
|
|
4203
|
+
useEffect4(() => {
|
|
4111
4204
|
if (deprecationLoggedRef.current) return;
|
|
4112
4205
|
if (!hasEnabledMethods) return;
|
|
4113
4206
|
const stale = [];
|
|
@@ -4119,13 +4212,6 @@ function SplitCardFormInner({
|
|
|
4119
4212
|
`[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
4213
|
);
|
|
4121
4214
|
}, [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
4215
|
const applyInlineSessionPatch = useCallback3(
|
|
4130
4216
|
(patch, method) => {
|
|
4131
4217
|
if (!checkout.applyInlineSessionPatch) {
|
|
@@ -4206,8 +4292,8 @@ function SplitCardFormInner({
|
|
|
4206
4292
|
accountData: {
|
|
4207
4293
|
userId: effectiveAccount.userId ?? "",
|
|
4208
4294
|
email: effectiveAccount.email ?? "",
|
|
4209
|
-
firstName: effectiveAccount.firstName ??
|
|
4210
|
-
lastName: effectiveAccount.lastName ??
|
|
4295
|
+
firstName: effectiveAccount.firstName ?? "",
|
|
4296
|
+
lastName: effectiveAccount.lastName ?? "",
|
|
4211
4297
|
...avsConfig ? (() => {
|
|
4212
4298
|
const c = selectedCountryRef.current;
|
|
4213
4299
|
const stateVisible = isAVSFieldVisible(avsConfig.state, c);
|
|
@@ -4255,70 +4341,6 @@ function SplitCardFormInner({
|
|
|
4255
4341
|
return;
|
|
4256
4342
|
}
|
|
4257
4343
|
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
4344
|
if (json?.type === "paypal_redirect_required") {
|
|
4323
4345
|
const secret = json["threeDSecureToken"];
|
|
4324
4346
|
const savedPmId = json["paymentMethodId"] || tokenizedBody.id || "";
|
|
@@ -4372,6 +4394,8 @@ function SplitCardFormInner({
|
|
|
4372
4394
|
emitDecline("paypal", "paypal_direct_required retry limit exceeded");
|
|
4373
4395
|
return;
|
|
4374
4396
|
}
|
|
4397
|
+
setDirectPaypalReady(false);
|
|
4398
|
+
setDirectPaypalInitializationState("loading");
|
|
4375
4399
|
setPaypalDirectRetry({ orderId, attempts: prevAttempts + 1 });
|
|
4376
4400
|
setOverlayStatus(null);
|
|
4377
4401
|
return;
|
|
@@ -4394,7 +4418,7 @@ function SplitCardFormInner({
|
|
|
4394
4418
|
processingRef.current = false;
|
|
4395
4419
|
}
|
|
4396
4420
|
},
|
|
4397
|
-
[baseUrl, sessionId, nonce, resolvedAccount,
|
|
4421
|
+
[baseUrl, sessionId, nonce, resolvedAccount, resolvedBillingName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
|
|
4398
4422
|
);
|
|
4399
4423
|
const dispatchTokenizedBody = useCallback3(
|
|
4400
4424
|
(tokenizedBody, overrides) => {
|
|
@@ -4406,35 +4430,8 @@ function SplitCardFormInner({
|
|
|
4406
4430
|
},
|
|
4407
4431
|
[onTokenizedBody, processPaymentInternal]
|
|
4408
4432
|
);
|
|
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(() => {
|
|
4433
|
+
const stripeResumeAttemptedRef = useRef4(false);
|
|
4434
|
+
useEffect4(() => {
|
|
4438
4435
|
if (typeof window === "undefined" || stripeResumeAttemptedRef.current) return;
|
|
4439
4436
|
const params = new URLSearchParams(window.location.search);
|
|
4440
4437
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -4512,166 +4509,12 @@ function SplitCardFormInner({
|
|
|
4512
4509
|
}, persistedOverrides);
|
|
4513
4510
|
})();
|
|
4514
4511
|
}, [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);
|
|
4512
|
+
const handleSubmit = useCallback3((event) => {
|
|
4513
|
+
event.preventDefault();
|
|
4514
|
+
}, []);
|
|
4515
|
+
const isReady = flopay !== null;
|
|
4673
4516
|
if (!isReady) {
|
|
4674
|
-
return /* @__PURE__ */
|
|
4517
|
+
return /* @__PURE__ */ jsx7("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
|
|
4675
4518
|
}
|
|
4676
4519
|
const isButtons = layout === "buttons";
|
|
4677
4520
|
const appearanceVars = appearance?.variables;
|
|
@@ -4712,25 +4555,10 @@ function SplitCardFormInner({
|
|
|
4712
4555
|
"--flopay-input-font-family": resolvedInputFontFamily,
|
|
4713
4556
|
"--flopay-input-font-weight": String(resolvedInputFontWeight)
|
|
4714
4557
|
};
|
|
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
4558
|
const containerOverrides = bStyles.cardFormContainer ?? {};
|
|
4731
4559
|
const containerPadding = containerOverrides.padding ?? (isButtons ? "0" : "1rem");
|
|
4732
4560
|
const containerRadius = containerOverrides.borderRadius ?? resolvedBorderRadius;
|
|
4733
|
-
const vaultCardFieldsNode = cardCapture && vaultMount ? /* @__PURE__ */
|
|
4561
|
+
const vaultCardFieldsNode = cardCapture && vaultMount ? /* @__PURE__ */ jsx7(
|
|
4734
4562
|
VaultCardFields,
|
|
4735
4563
|
{
|
|
4736
4564
|
capture: cardCapture,
|
|
@@ -4739,7 +4567,6 @@ function SplitCardFormInner({
|
|
|
4739
4567
|
expectedOrigin: vaultMount.expectedOrigin,
|
|
4740
4568
|
theme: vaultThemeColors,
|
|
4741
4569
|
onReady: () => {
|
|
4742
|
-
setFormReady(true);
|
|
4743
4570
|
if (!avsConfig || typeof document === "undefined") return;
|
|
4744
4571
|
const focusFirstAvs = () => {
|
|
4745
4572
|
const block = document.querySelector('[data-testid="flopay-avs-fields"]');
|
|
@@ -4768,7 +4595,7 @@ function SplitCardFormInner({
|
|
|
4768
4595
|
if (message) setOverlayStatus(null);
|
|
4769
4596
|
}
|
|
4770
4597
|
}
|
|
4771
|
-
) : /* @__PURE__ */
|
|
4598
|
+
) : /* @__PURE__ */ jsx7(
|
|
4772
4599
|
"div",
|
|
4773
4600
|
{
|
|
4774
4601
|
"data-testid": "flopay-vault-loading",
|
|
@@ -4796,7 +4623,7 @@ function SplitCardFormInner({
|
|
|
4796
4623
|
display: "flex",
|
|
4797
4624
|
flexDirection: "column"
|
|
4798
4625
|
}, children: [
|
|
4799
|
-
/* @__PURE__ */
|
|
4626
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
4800
4627
|
.flopay-shared-input::placeholder {
|
|
4801
4628
|
color: var(--flopay-input-placeholder-color);
|
|
4802
4629
|
opacity: 1;
|
|
@@ -4834,7 +4661,7 @@ function SplitCardFormInner({
|
|
|
4834
4661
|
},
|
|
4835
4662
|
"aria-label": "Back to payment methods",
|
|
4836
4663
|
children: [
|
|
4837
|
-
/* @__PURE__ */
|
|
4664
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
4838
4665
|
display: "inline-flex",
|
|
4839
4666
|
alignItems: "center",
|
|
4840
4667
|
justifyContent: "center",
|
|
@@ -4844,12 +4671,12 @@ function SplitCardFormInner({
|
|
|
4844
4671
|
backgroundColor: "#f3f4f6",
|
|
4845
4672
|
transition: "background-color 0.15s",
|
|
4846
4673
|
...bStyles.backButtonIcon
|
|
4847
|
-
}, children: /* @__PURE__ */
|
|
4848
|
-
/* @__PURE__ */
|
|
4674
|
+
}, 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" }) }) }),
|
|
4675
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
4849
4676
|
]
|
|
4850
4677
|
}
|
|
4851
4678
|
),
|
|
4852
|
-
hideTitle ? /* @__PURE__ */
|
|
4679
|
+
hideTitle ? /* @__PURE__ */ jsx7("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx7("div", { style: {
|
|
4853
4680
|
flex: 1,
|
|
4854
4681
|
textAlign: "center",
|
|
4855
4682
|
fontWeight: 600,
|
|
@@ -4857,9 +4684,9 @@ function SplitCardFormInner({
|
|
|
4857
4684
|
color: "#262833",
|
|
4858
4685
|
paddingRight: 80,
|
|
4859
4686
|
...bStyles.title
|
|
4860
|
-
}, children: /* @__PURE__ */
|
|
4687
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) })
|
|
4861
4688
|
] }),
|
|
4862
|
-
!isButtons && !hideTitle && /* @__PURE__ */
|
|
4689
|
+
!isButtons && !hideTitle && /* @__PURE__ */ jsx7("div", { style: {
|
|
4863
4690
|
textAlign: "center",
|
|
4864
4691
|
fontWeight: 600,
|
|
4865
4692
|
fontSize: "1.1rem",
|
|
@@ -4869,70 +4696,8 @@ function SplitCardFormInner({
|
|
|
4869
4696
|
// (-2) and AVS block (-1) are ordered below it but above the card form.
|
|
4870
4697
|
order: vaultActive ? -3 : 0,
|
|
4871
4698
|
...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: (() => {
|
|
4699
|
+
}, children: /* @__PURE__ */ jsx7(TitleContentSlot, { content: cardTitleContent }) }),
|
|
4700
|
+
avsConfig && /* @__PURE__ */ jsx7("div", { style: { order: vaultActive ? -1 : 0 }, "data-testid": "flopay-avs-fields", children: (() => {
|
|
4936
4701
|
const cc = selectedCountry;
|
|
4937
4702
|
const inputWrapStyle = (invalid = false) => ({
|
|
4938
4703
|
backgroundColor: cardInputBg,
|
|
@@ -4950,7 +4715,7 @@ function SplitCardFormInner({
|
|
|
4950
4715
|
});
|
|
4951
4716
|
const stateOpts = getStateOptions(cc);
|
|
4952
4717
|
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
4953
|
-
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */
|
|
4718
|
+
isAVSFieldVisible(avsConfig.address_line_1, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(invalidAvsFields.line1), children: /* @__PURE__ */ jsx7(
|
|
4954
4719
|
"input",
|
|
4955
4720
|
{
|
|
4956
4721
|
className: "flopay-shared-input",
|
|
@@ -4969,7 +4734,7 @@ function SplitCardFormInner({
|
|
|
4969
4734
|
style: inputFieldStyle()
|
|
4970
4735
|
}
|
|
4971
4736
|
) }),
|
|
4972
|
-
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */
|
|
4737
|
+
isAVSFieldVisible(avsConfig.address_line_2, cc) && /* @__PURE__ */ jsx7("div", { style: inputWrapStyle(), children: /* @__PURE__ */ jsx7(
|
|
4973
4738
|
"input",
|
|
4974
4739
|
{
|
|
4975
4740
|
className: "flopay-shared-input",
|
|
@@ -4992,7 +4757,7 @@ function SplitCardFormInner({
|
|
|
4992
4757
|
gap: "0",
|
|
4993
4758
|
marginTop: "0.5rem"
|
|
4994
4759
|
}, children: [
|
|
4995
|
-
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */
|
|
4760
|
+
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
4996
4761
|
flex: 1,
|
|
4997
4762
|
backgroundColor: cardInputBg,
|
|
4998
4763
|
borderTop: `1px solid ${avsBorderColor(invalidAvsFields.city)}`,
|
|
@@ -5003,7 +4768,7 @@ function SplitCardFormInner({
|
|
|
5003
4768
|
borderTopLeftRadius: resolvedBorderRadius,
|
|
5004
4769
|
borderBottomLeftRadius: resolvedBorderRadius,
|
|
5005
4770
|
...isAVSFieldVisible(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: resolvedBorderRadius }
|
|
5006
|
-
}, children: /* @__PURE__ */
|
|
4771
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5007
4772
|
"input",
|
|
5008
4773
|
{
|
|
5009
4774
|
className: "flopay-shared-input",
|
|
@@ -5022,7 +4787,7 @@ function SplitCardFormInner({
|
|
|
5022
4787
|
style: inputFieldStyle()
|
|
5023
4788
|
}
|
|
5024
4789
|
) }),
|
|
5025
|
-
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */
|
|
4790
|
+
isAVSFieldVisible(avsConfig.state, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5026
4791
|
flex: 1,
|
|
5027
4792
|
backgroundColor: cardInputBg,
|
|
5028
4793
|
border: `1px solid ${avsBorderColor(invalidAvsFields.state)}`,
|
|
@@ -5046,11 +4811,11 @@ function SplitCardFormInner({
|
|
|
5046
4811
|
"data-testid": "flopay-state",
|
|
5047
4812
|
style: { ...inputFieldStyle(), cursor: "pointer" },
|
|
5048
4813
|
children: [
|
|
5049
|
-
/* @__PURE__ */
|
|
5050
|
-
stateOpts.map((s) => /* @__PURE__ */
|
|
4814
|
+
/* @__PURE__ */ jsx7("option", { value: "", children: getStateLabel(cc) }),
|
|
4815
|
+
stateOpts.map((s) => /* @__PURE__ */ jsx7("option", { value: s.code, children: s.name }, s.code))
|
|
5051
4816
|
]
|
|
5052
4817
|
}
|
|
5053
|
-
) : /* @__PURE__ */
|
|
4818
|
+
) : /* @__PURE__ */ jsx7(
|
|
5054
4819
|
"input",
|
|
5055
4820
|
{
|
|
5056
4821
|
className: "flopay-shared-input",
|
|
@@ -5076,7 +4841,7 @@ function SplitCardFormInner({
|
|
|
5076
4841
|
gap: avsLayoutProp === "column" ? "0.5rem" : "0",
|
|
5077
4842
|
marginTop: "0.5rem"
|
|
5078
4843
|
}, children: [
|
|
5079
|
-
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */
|
|
4844
|
+
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5080
4845
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
5081
4846
|
backgroundColor: cardInputBg,
|
|
5082
4847
|
borderTop: `1px solid ${resolvedBorder}`,
|
|
@@ -5085,7 +4850,7 @@ function SplitCardFormInner({
|
|
|
5085
4850
|
borderLeft: `1px solid ${resolvedBorder}`,
|
|
5086
4851
|
padding: "10px",
|
|
5087
4852
|
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: resolvedBorderRadius, borderBottomLeftRadius: resolvedBorderRadius, borderRight: "none" } : { borderRadius: resolvedBorderRadius }
|
|
5088
|
-
}, children: /* @__PURE__ */
|
|
4853
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5089
4854
|
"select",
|
|
5090
4855
|
{
|
|
5091
4856
|
id: "flopay-billing-country",
|
|
@@ -5109,13 +4874,13 @@ function SplitCardFormInner({
|
|
|
5109
4874
|
] }, c.code))
|
|
5110
4875
|
}
|
|
5111
4876
|
) }),
|
|
5112
|
-
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */
|
|
4877
|
+
isAVSFieldVisible(avsConfig.postal_code, cc) && /* @__PURE__ */ jsx7("div", { style: {
|
|
5113
4878
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
5114
4879
|
backgroundColor: cardInputBg,
|
|
5115
4880
|
border: `1px solid ${zipBorderColor}`,
|
|
5116
4881
|
padding: "10px",
|
|
5117
4882
|
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: resolvedBorderRadius, borderBottomRightRadius: resolvedBorderRadius } : { borderRadius: resolvedBorderRadius }
|
|
5118
|
-
}, children: /* @__PURE__ */
|
|
4883
|
+
}, children: /* @__PURE__ */ jsx7(
|
|
5119
4884
|
"input",
|
|
5120
4885
|
{
|
|
5121
4886
|
className: "flopay-shared-input",
|
|
@@ -5139,7 +4904,7 @@ function SplitCardFormInner({
|
|
|
5139
4904
|
}
|
|
5140
4905
|
) })
|
|
5141
4906
|
] }),
|
|
5142
|
-
showPostcodeError && /* @__PURE__ */
|
|
4907
|
+
showPostcodeError && /* @__PURE__ */ jsx7(
|
|
5143
4908
|
"div",
|
|
5144
4909
|
{
|
|
5145
4910
|
id: "flopay-billing-postal-code-error",
|
|
@@ -5156,39 +4921,9 @@ function SplitCardFormInner({
|
|
|
5156
4921
|
)
|
|
5157
4922
|
] });
|
|
5158
4923
|
})() }),
|
|
5159
|
-
vaultActive && cardPreFormSlot && /* @__PURE__ */
|
|
4924
|
+
vaultActive && cardPreFormSlot && /* @__PURE__ */ jsx7("div", { style: { order: -2, width: "100%" }, children: cardPreFormSlot }),
|
|
5160
4925
|
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
|
-
))
|
|
4926
|
+
displayError && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.75rem 0", styleOverride: bStyles.errorBanner, children: displayError })
|
|
5192
4927
|
] });
|
|
5193
4928
|
const gateDebugStyle = {
|
|
5194
4929
|
margin: 0,
|
|
@@ -5204,9 +4939,9 @@ function SplitCardFormInner({
|
|
|
5204
4939
|
const renderDirectPaypalGateDebug = (testId) => {
|
|
5205
4940
|
if (!debug) return null;
|
|
5206
4941
|
if (!showPayPal || !directPaypalConfigured) {
|
|
5207
|
-
return /* @__PURE__ */
|
|
4942
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/DirectPayPal-debug - not enabled" });
|
|
5208
4943
|
}
|
|
5209
|
-
return /* @__PURE__ */
|
|
4944
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
5210
4945
|
"FloPay/DirectPayPal-debug (parent gate)",
|
|
5211
4946
|
` showPayPal=${showPayPal}`,
|
|
5212
4947
|
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
@@ -5219,9 +4954,9 @@ function SplitCardFormInner({
|
|
|
5219
4954
|
const renderStripeGateDebug = (testId) => {
|
|
5220
4955
|
if (!debug) return null;
|
|
5221
4956
|
if (!showStripe || !stripeInstance) {
|
|
5222
|
-
return /* @__PURE__ */
|
|
4957
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/Stripe-debug - not enabled" });
|
|
5223
4958
|
}
|
|
5224
|
-
return /* @__PURE__ */
|
|
4959
|
+
return /* @__PURE__ */ jsx7("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
5225
4960
|
"FloPay/Stripe-debug (parent gate)",
|
|
5226
4961
|
` showStripe=${showStripe}`,
|
|
5227
4962
|
` currency=${currency}`,
|
|
@@ -5251,8 +4986,8 @@ function SplitCardFormInner({
|
|
|
5251
4986
|
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
4987
|
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
4988
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5254
|
-
/* @__PURE__ */
|
|
5255
|
-
overlayStatus && /* @__PURE__ */
|
|
4989
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
4990
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5256
4991
|
/* @__PURE__ */ jsxs5("div", { style: { display: "grid" }, children: [
|
|
5257
4992
|
/* @__PURE__ */ jsxs5(
|
|
5258
4993
|
"div",
|
|
@@ -5272,7 +5007,7 @@ function SplitCardFormInner({
|
|
|
5272
5007
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug"),
|
|
5273
5008
|
renderStripeGateDebug("flopay-stripe-gate-debug"),
|
|
5274
5009
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
5275
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
5010
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
5276
5011
|
"div",
|
|
5277
5012
|
{
|
|
5278
5013
|
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
@@ -5288,7 +5023,7 @@ function SplitCardFormInner({
|
|
|
5288
5023
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
5289
5024
|
}
|
|
5290
5025
|
),
|
|
5291
|
-
/* @__PURE__ */
|
|
5026
|
+
/* @__PURE__ */ jsx7(
|
|
5292
5027
|
DirectPayPalButton,
|
|
5293
5028
|
{
|
|
5294
5029
|
sessionId,
|
|
@@ -5308,6 +5043,7 @@ function SplitCardFormInner({
|
|
|
5308
5043
|
runBeforeButtonClick,
|
|
5309
5044
|
isProcessing: isSubmitting,
|
|
5310
5045
|
onLoadStateChange: setDirectPaypalReady,
|
|
5046
|
+
onInitializationStateChange: setDirectPaypalInitializationState,
|
|
5311
5047
|
session: session ?? null,
|
|
5312
5048
|
existingOrderId: paypalDirectRetry?.orderId,
|
|
5313
5049
|
debug
|
|
@@ -5315,7 +5051,7 @@ function SplitCardFormInner({
|
|
|
5315
5051
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
5316
5052
|
)
|
|
5317
5053
|
] }),
|
|
5318
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
5054
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
5319
5055
|
PayPalButtonInner,
|
|
5320
5056
|
{
|
|
5321
5057
|
sessionId,
|
|
@@ -5333,13 +5069,14 @@ function SplitCardFormInner({
|
|
|
5333
5069
|
placeholderBorderRadius: buttonBorderRadius
|
|
5334
5070
|
}
|
|
5335
5071
|
) }),
|
|
5336
|
-
shouldRenderWallets ? /* @__PURE__ */
|
|
5072
|
+
shouldRenderWallets ? /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
5337
5073
|
WalletButtonInner,
|
|
5338
5074
|
{
|
|
5339
5075
|
sessionId,
|
|
5340
5076
|
nonce,
|
|
5341
5077
|
email: resolvedAccount.email,
|
|
5342
5078
|
billingApiUrl: resolvedBillingApiUrl,
|
|
5079
|
+
intentKind: totalAmount > 0 ? "payment" : "setup",
|
|
5343
5080
|
expressMethods: walletExpressMethods,
|
|
5344
5081
|
onTokenizedBody: dispatchTokenizedBody,
|
|
5345
5082
|
onErrorChange: updateError,
|
|
@@ -5350,8 +5087,8 @@ function SplitCardFormInner({
|
|
|
5350
5087
|
onLoadStateChange: setWalletLoadState,
|
|
5351
5088
|
placeholderBorderRadius: buttonBorderRadius
|
|
5352
5089
|
}
|
|
5353
|
-
) }) : shouldShowWallets ? /* @__PURE__ */
|
|
5354
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
5090
|
+
) }) : 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,
|
|
5091
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
5355
5092
|
StripePaymentElementInner,
|
|
5356
5093
|
{
|
|
5357
5094
|
sessionId,
|
|
@@ -5383,7 +5120,7 @@ function SplitCardFormInner({
|
|
|
5383
5120
|
}
|
|
5384
5121
|
}
|
|
5385
5122
|
),
|
|
5386
|
-
|
|
5123
|
+
vaultActive && /* @__PURE__ */ jsx7(
|
|
5387
5124
|
"button",
|
|
5388
5125
|
{
|
|
5389
5126
|
type: "button",
|
|
@@ -5439,19 +5176,19 @@ function SplitCardFormInner({
|
|
|
5439
5176
|
onMouseUp: (e) => {
|
|
5440
5177
|
e.currentTarget.style.transform = "scale(1)";
|
|
5441
5178
|
},
|
|
5442
|
-
children: /* @__PURE__ */
|
|
5179
|
+
children: /* @__PURE__ */ jsx7(CardButtonContentSlot, { content: cardButtonContent })
|
|
5443
5180
|
}
|
|
5444
5181
|
),
|
|
5445
|
-
displayError && viewState === "buttons" && /* @__PURE__ */
|
|
5182
|
+
displayError && viewState === "buttons" && /* @__PURE__ */ jsx7(ErrorBanner, { margin: "0.25rem 0", styleOverride: bStyles.errorBanner, children: displayError })
|
|
5446
5183
|
]
|
|
5447
5184
|
}
|
|
5448
5185
|
),
|
|
5449
|
-
|
|
5186
|
+
vaultActive && isCardView && /* @__PURE__ */ jsx7("div", { style: {
|
|
5450
5187
|
gridArea: "1 / 1",
|
|
5451
5188
|
...cardAnim ? { animation: cardAnim } : {},
|
|
5452
5189
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
5453
5190
|
}, children: cardFormBlock }),
|
|
5454
|
-
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */
|
|
5191
|
+
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */ jsx7("div", { style: {
|
|
5455
5192
|
gridArea: "1 / 1",
|
|
5456
5193
|
...apmAnim ? { animation: apmAnim } : {},
|
|
5457
5194
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
@@ -5489,7 +5226,7 @@ function SplitCardFormInner({
|
|
|
5489
5226
|
},
|
|
5490
5227
|
"aria-label": "Back to payment methods",
|
|
5491
5228
|
children: [
|
|
5492
|
-
/* @__PURE__ */
|
|
5229
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
5493
5230
|
display: "inline-flex",
|
|
5494
5231
|
alignItems: "center",
|
|
5495
5232
|
justifyContent: "center",
|
|
@@ -5499,12 +5236,12 @@ function SplitCardFormInner({
|
|
|
5499
5236
|
backgroundColor: "#f3f4f6",
|
|
5500
5237
|
transition: "background-color 0.15s",
|
|
5501
5238
|
...bStyles.backButtonIcon
|
|
5502
|
-
}, children: /* @__PURE__ */
|
|
5503
|
-
/* @__PURE__ */
|
|
5239
|
+
}, 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" }) }) }),
|
|
5240
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
5504
5241
|
]
|
|
5505
5242
|
}
|
|
5506
5243
|
),
|
|
5507
|
-
/* @__PURE__ */
|
|
5244
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5508
5245
|
flex: 1,
|
|
5509
5246
|
textAlign: "center",
|
|
5510
5247
|
fontWeight: 600,
|
|
@@ -5514,12 +5251,12 @@ function SplitCardFormInner({
|
|
|
5514
5251
|
...bStyles.title
|
|
5515
5252
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
5516
5253
|
] }),
|
|
5517
|
-
/* @__PURE__ */
|
|
5254
|
+
/* @__PURE__ */ jsx7(
|
|
5518
5255
|
StripeElements,
|
|
5519
5256
|
{
|
|
5520
5257
|
stripe: stripeInstance,
|
|
5521
5258
|
options: apmInlineOptions,
|
|
5522
|
-
children: /* @__PURE__ */
|
|
5259
|
+
children: /* @__PURE__ */ jsx7(
|
|
5523
5260
|
StripeMethodInlineForm,
|
|
5524
5261
|
{
|
|
5525
5262
|
method: expandedApmMethod,
|
|
@@ -5550,9 +5287,9 @@ function SplitCardFormInner({
|
|
|
5550
5287
|
}
|
|
5551
5288
|
if (isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && showStripe) {
|
|
5552
5289
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5553
|
-
/* @__PURE__ */
|
|
5554
|
-
overlayStatus && /* @__PURE__ */
|
|
5555
|
-
/* @__PURE__ */
|
|
5290
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
5291
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5292
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5556
5293
|
...apmAnim ? { animation: apmAnim } : {},
|
|
5557
5294
|
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
5558
5295
|
}, children: /* @__PURE__ */ jsxs5("div", { style: {
|
|
@@ -5589,7 +5326,7 @@ function SplitCardFormInner({
|
|
|
5589
5326
|
},
|
|
5590
5327
|
"aria-label": "Back to payment methods",
|
|
5591
5328
|
children: [
|
|
5592
|
-
/* @__PURE__ */
|
|
5329
|
+
/* @__PURE__ */ jsx7("span", { style: {
|
|
5593
5330
|
display: "inline-flex",
|
|
5594
5331
|
alignItems: "center",
|
|
5595
5332
|
justifyContent: "center",
|
|
@@ -5599,12 +5336,12 @@ function SplitCardFormInner({
|
|
|
5599
5336
|
backgroundColor: "#f3f4f6",
|
|
5600
5337
|
transition: "background-color 0.15s",
|
|
5601
5338
|
...bStyles.backButtonIcon
|
|
5602
|
-
}, children: /* @__PURE__ */
|
|
5603
|
-
/* @__PURE__ */
|
|
5339
|
+
}, 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" }) }) }),
|
|
5340
|
+
/* @__PURE__ */ jsx7(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
5604
5341
|
]
|
|
5605
5342
|
}
|
|
5606
5343
|
),
|
|
5607
|
-
/* @__PURE__ */
|
|
5344
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5608
5345
|
flex: 1,
|
|
5609
5346
|
textAlign: "center",
|
|
5610
5347
|
fontWeight: 600,
|
|
@@ -5614,12 +5351,12 @@ function SplitCardFormInner({
|
|
|
5614
5351
|
...bStyles.title
|
|
5615
5352
|
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
5616
5353
|
] }),
|
|
5617
|
-
/* @__PURE__ */
|
|
5354
|
+
/* @__PURE__ */ jsx7(
|
|
5618
5355
|
StripeElements,
|
|
5619
5356
|
{
|
|
5620
5357
|
stripe: stripeInstance,
|
|
5621
5358
|
options: apmInlineOptions,
|
|
5622
|
-
children: /* @__PURE__ */
|
|
5359
|
+
children: /* @__PURE__ */ jsx7(
|
|
5623
5360
|
StripeMethodInlineForm,
|
|
5624
5361
|
{
|
|
5625
5362
|
method: expandedApmMethod,
|
|
@@ -5648,13 +5385,13 @@ function SplitCardFormInner({
|
|
|
5648
5385
|
] });
|
|
5649
5386
|
}
|
|
5650
5387
|
return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
5651
|
-
/* @__PURE__ */
|
|
5652
|
-
overlayStatus && /* @__PURE__ */
|
|
5388
|
+
/* @__PURE__ */ jsx7(FloPayKeyframes, {}),
|
|
5389
|
+
overlayStatus && /* @__PURE__ */ jsx7(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
5653
5390
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
5654
5391
|
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug-default"),
|
|
5655
5392
|
renderStripeGateDebug("flopay-stripe-gate-debug-default"),
|
|
5656
5393
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
5657
|
-
paypalDirectRetry && /* @__PURE__ */
|
|
5394
|
+
paypalDirectRetry && /* @__PURE__ */ jsx7(
|
|
5658
5395
|
"div",
|
|
5659
5396
|
{
|
|
5660
5397
|
"data-testid": "flopay-paypal-direct-retry-notice-default",
|
|
@@ -5670,7 +5407,7 @@ function SplitCardFormInner({
|
|
|
5670
5407
|
children: "Please confirm your PayPal payment to complete checkout."
|
|
5671
5408
|
}
|
|
5672
5409
|
),
|
|
5673
|
-
/* @__PURE__ */
|
|
5410
|
+
/* @__PURE__ */ jsx7(
|
|
5674
5411
|
DirectPayPalButton,
|
|
5675
5412
|
{
|
|
5676
5413
|
sessionId,
|
|
@@ -5690,6 +5427,7 @@ function SplitCardFormInner({
|
|
|
5690
5427
|
runBeforeButtonClick,
|
|
5691
5428
|
isProcessing: isSubmitting,
|
|
5692
5429
|
onLoadStateChange: setDirectPaypalReady,
|
|
5430
|
+
onInitializationStateChange: setDirectPaypalInitializationState,
|
|
5693
5431
|
session: session ?? null,
|
|
5694
5432
|
existingOrderId: paypalDirectRetry?.orderId,
|
|
5695
5433
|
debug
|
|
@@ -5697,7 +5435,7 @@ function SplitCardFormInner({
|
|
|
5697
5435
|
paypalDirectRetry?.orderId ?? "fresh"
|
|
5698
5436
|
)
|
|
5699
5437
|
] }),
|
|
5700
|
-
shouldRenderStripePayPal && /* @__PURE__ */
|
|
5438
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx7(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx7(
|
|
5701
5439
|
PayPalButtonInner,
|
|
5702
5440
|
{
|
|
5703
5441
|
sessionId,
|
|
@@ -5715,13 +5453,14 @@ function SplitCardFormInner({
|
|
|
5715
5453
|
placeholderBorderRadius: buttonBorderRadius
|
|
5716
5454
|
}
|
|
5717
5455
|
) }),
|
|
5718
|
-
shouldRenderWallets && /* @__PURE__ */
|
|
5456
|
+
shouldRenderWallets && /* @__PURE__ */ jsx7(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx7(
|
|
5719
5457
|
WalletButtonInner,
|
|
5720
5458
|
{
|
|
5721
5459
|
sessionId,
|
|
5722
5460
|
nonce,
|
|
5723
5461
|
email: resolvedAccount.email,
|
|
5724
5462
|
billingApiUrl: resolvedBillingApiUrl,
|
|
5463
|
+
intentKind: totalAmount > 0 ? "payment" : "setup",
|
|
5725
5464
|
expressMethods: walletExpressMethods,
|
|
5726
5465
|
onTokenizedBody: dispatchTokenizedBody,
|
|
5727
5466
|
onErrorChange: updateError,
|
|
@@ -5733,7 +5472,7 @@ function SplitCardFormInner({
|
|
|
5733
5472
|
placeholderBorderRadius: buttonBorderRadius
|
|
5734
5473
|
}
|
|
5735
5474
|
) }),
|
|
5736
|
-
shouldRenderPaymentElement && /* @__PURE__ */
|
|
5475
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx7(
|
|
5737
5476
|
StripePaymentElementInner,
|
|
5738
5477
|
{
|
|
5739
5478
|
sessionId,
|
|
@@ -5766,7 +5505,7 @@ function SplitCardFormInner({
|
|
|
5766
5505
|
}
|
|
5767
5506
|
)
|
|
5768
5507
|
] }),
|
|
5769
|
-
|
|
5508
|
+
vaultActive && (shouldDisplayWalletRow || shouldDisplayPayPalRow || shouldDisplayPaymentElementRow) && /* @__PURE__ */ jsxs5("div", { style: {
|
|
5770
5509
|
display: "flex",
|
|
5771
5510
|
alignItems: "center",
|
|
5772
5511
|
gap: "0.75rem",
|
|
@@ -5774,11 +5513,11 @@ function SplitCardFormInner({
|
|
|
5774
5513
|
color: "#999",
|
|
5775
5514
|
fontSize: "0.85rem"
|
|
5776
5515
|
}, children: [
|
|
5777
|
-
/* @__PURE__ */
|
|
5778
|
-
/* @__PURE__ */
|
|
5779
|
-
/* @__PURE__ */
|
|
5516
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
|
|
5517
|
+
/* @__PURE__ */ jsx7("span", { children: "or pay with card" }),
|
|
5518
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
5780
5519
|
] }),
|
|
5781
|
-
|
|
5520
|
+
vaultActive && cardFormBlock
|
|
5782
5521
|
] });
|
|
5783
5522
|
}
|
|
5784
5523
|
|
|
@@ -6477,7 +6216,7 @@ async function loadSavedPaymentProviders({
|
|
|
6477
6216
|
}
|
|
6478
6217
|
|
|
6479
6218
|
// src/flopay-checkout.tsx
|
|
6480
|
-
import { Fragment as Fragment3, jsx as
|
|
6219
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6481
6220
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
6482
6221
|
var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
|
|
6483
6222
|
var sessionInflightMap = /* @__PURE__ */ new Map();
|
|
@@ -6623,7 +6362,6 @@ function FloPayCheckout({
|
|
|
6623
6362
|
onComplete,
|
|
6624
6363
|
onError,
|
|
6625
6364
|
onDecline,
|
|
6626
|
-
onFullNameChange,
|
|
6627
6365
|
onCountryChange,
|
|
6628
6366
|
onZipChange,
|
|
6629
6367
|
showPayPal = true,
|
|
@@ -6645,7 +6383,6 @@ function FloPayCheckout({
|
|
|
6645
6383
|
cardFieldOrder,
|
|
6646
6384
|
cardPreFormSlot,
|
|
6647
6385
|
avsLayout,
|
|
6648
|
-
submitLabel,
|
|
6649
6386
|
className,
|
|
6650
6387
|
initialErrorMessage = null,
|
|
6651
6388
|
children,
|
|
@@ -6661,9 +6398,9 @@ function FloPayCheckout({
|
|
|
6661
6398
|
const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
|
|
6662
6399
|
const [unified, setUnified] = useState4(null);
|
|
6663
6400
|
const [flopay, setFloPay] = useState4(null);
|
|
6664
|
-
const flopayRef =
|
|
6401
|
+
const flopayRef = useRef5(null);
|
|
6665
6402
|
const [paypalFlopay, setPaypalFloPay] = useState4(null);
|
|
6666
|
-
const paypalFlopayRef =
|
|
6403
|
+
const paypalFlopayRef = useRef5(null);
|
|
6667
6404
|
const [session, setSession] = useState4(null);
|
|
6668
6405
|
const [resolvedSessionId, setResolvedSessionId] = useState4(sessionIdProp ?? "");
|
|
6669
6406
|
const activeSessionId = sessionIdProp ?? resolvedSessionId;
|
|
@@ -6678,28 +6415,53 @@ function FloPayCheckout({
|
|
|
6678
6415
|
const [createSessionPatch, setCreateSessionPatch] = useState4(void 0);
|
|
6679
6416
|
const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = useState4("");
|
|
6680
6417
|
const [cardBootstrapPending, setCardBootstrapPending] = useState4(false);
|
|
6681
|
-
const
|
|
6682
|
-
const
|
|
6683
|
-
const
|
|
6418
|
+
const [paypalInitializationState, setPaypalInitializationState] = useState4("loading");
|
|
6419
|
+
const [paypalManualRetryGeneration, setPaypalManualRetryGeneration] = useState4(0);
|
|
6420
|
+
const autoCheckoutAttempted = useRef5(false);
|
|
6421
|
+
const paypalResumeAttempted = useRef5(false);
|
|
6422
|
+
const paypalInitializationErrorEmittedRef = useRef5(false);
|
|
6423
|
+
const savedPaymentKeysRef = useRef5(null);
|
|
6684
6424
|
const telemetryCheckoutContext = useMemo4(() => ({
|
|
6685
6425
|
checkoutMode: checkoutModeProp ?? currentMode,
|
|
6686
6426
|
layout: children ? "unknown" : layout === "buttons" ? "buttons" : "embedded"
|
|
6687
6427
|
}), [checkoutModeProp, children, currentMode, layout]);
|
|
6688
|
-
const onCompleteRef =
|
|
6428
|
+
const onCompleteRef = useRef5(onComplete);
|
|
6689
6429
|
onCompleteRef.current = onComplete;
|
|
6690
|
-
const onErrorRef =
|
|
6430
|
+
const onErrorRef = useRef5(onError);
|
|
6691
6431
|
onErrorRef.current = onError;
|
|
6692
|
-
const onDeclineRef =
|
|
6432
|
+
const onDeclineRef = useRef5(onDecline);
|
|
6693
6433
|
onDeclineRef.current = onDecline;
|
|
6694
|
-
|
|
6434
|
+
useEffect5(() => {
|
|
6695
6435
|
getFloPayTelemetryBridge(flopay)?.setCheckoutContext(telemetryCheckoutContext);
|
|
6696
6436
|
if (paypalFlopay && paypalFlopay !== flopay) {
|
|
6697
6437
|
getFloPayTelemetryBridge(paypalFlopay)?.setCheckoutContext(telemetryCheckoutContext);
|
|
6698
6438
|
}
|
|
6699
6439
|
}, [flopay, paypalFlopay, telemetryCheckoutContext]);
|
|
6700
|
-
const onSessionCompletedRef =
|
|
6440
|
+
const onSessionCompletedRef = useRef5(onSessionCompleted);
|
|
6701
6441
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
6702
|
-
|
|
6442
|
+
const handlePayPalInitializationStateChange = useCallback4(
|
|
6443
|
+
(state) => {
|
|
6444
|
+
setPaypalInitializationState(state);
|
|
6445
|
+
if (state !== "exhausted" || paypalInitializationErrorEmittedRef.current) return;
|
|
6446
|
+
paypalInitializationErrorEmittedRef.current = true;
|
|
6447
|
+
onErrorRef.current?.(new FloPayError5(
|
|
6448
|
+
"PayPal is temporarily unavailable. Please try again.",
|
|
6449
|
+
"api_error",
|
|
6450
|
+
{ code: "paypal_init_timeout" }
|
|
6451
|
+
));
|
|
6452
|
+
},
|
|
6453
|
+
[]
|
|
6454
|
+
);
|
|
6455
|
+
const retryPayPalInitialization = useCallback4(() => {
|
|
6456
|
+
setPaypalInitializationState("retrying");
|
|
6457
|
+
setPaypalManualRetryGeneration((generation) => generation + 1);
|
|
6458
|
+
}, []);
|
|
6459
|
+
useEffect5(() => {
|
|
6460
|
+
setPaypalInitializationState("loading");
|
|
6461
|
+
setPaypalManualRetryGeneration(0);
|
|
6462
|
+
paypalInitializationErrorEmittedRef.current = false;
|
|
6463
|
+
}, [activeSessionId]);
|
|
6464
|
+
useEffect5(() => {
|
|
6703
6465
|
console.info("[FloPay] Checkout initialized", {
|
|
6704
6466
|
sdk_version: SDK_VERSION2,
|
|
6705
6467
|
checkout_type: checkoutType,
|
|
@@ -6727,11 +6489,11 @@ function FloPayCheckout({
|
|
|
6727
6489
|
} : void 0,
|
|
6728
6490
|
[effectiveCreateSessionBase, effectiveCreateSessionMode]
|
|
6729
6491
|
);
|
|
6730
|
-
|
|
6492
|
+
useEffect5(() => {
|
|
6731
6493
|
setCreateSessionPatch(void 0);
|
|
6732
6494
|
setCreateSessionPatchBaseHash(baseCreateSessionHash);
|
|
6733
6495
|
}, [baseCreateSessionHash]);
|
|
6734
|
-
|
|
6496
|
+
useEffect5(() => {
|
|
6735
6497
|
setModeError(initialErrorMessage);
|
|
6736
6498
|
}, [initialErrorMessage]);
|
|
6737
6499
|
const emitDecline = useCallback4(
|
|
@@ -7008,7 +6770,7 @@ function FloPayCheckout({
|
|
|
7008
6770
|
telemetryCheckoutContext
|
|
7009
6771
|
]
|
|
7010
6772
|
);
|
|
7011
|
-
|
|
6773
|
+
useEffect5(() => {
|
|
7012
6774
|
if (typeof window === "undefined" || paypalResumeAttempted.current) {
|
|
7013
6775
|
return;
|
|
7014
6776
|
}
|
|
@@ -7211,7 +6973,7 @@ function FloPayCheckout({
|
|
|
7211
6973
|
}
|
|
7212
6974
|
})();
|
|
7213
6975
|
}, [emitDecline, invokeMerchantCallback, locale, normalizeSavedPaymentError, resolvedBillingUrl, telemetry]);
|
|
7214
|
-
const initializedHashRef =
|
|
6976
|
+
const initializedHashRef = useRef5(null);
|
|
7215
6977
|
function hashCreateParams(params) {
|
|
7216
6978
|
const key = JSON.stringify({
|
|
7217
6979
|
c: params?.clientId,
|
|
@@ -7248,12 +7010,12 @@ function FloPayCheckout({
|
|
|
7248
7010
|
() => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
|
|
7249
7011
|
[effectiveCreateSession]
|
|
7250
7012
|
);
|
|
7251
|
-
const createSessionParamsRef =
|
|
7013
|
+
const createSessionParamsRef = useRef5(effectiveCreateSession);
|
|
7252
7014
|
createSessionParamsRef.current = effectiveCreateSession;
|
|
7253
|
-
|
|
7015
|
+
useEffect5(() => {
|
|
7254
7016
|
setResolvedSessionId(sessionIdProp ?? "");
|
|
7255
7017
|
}, [sessionIdProp]);
|
|
7256
|
-
|
|
7018
|
+
useEffect5(() => {
|
|
7257
7019
|
autoCheckoutAttempted.current = false;
|
|
7258
7020
|
setModeError(initialErrorMessage);
|
|
7259
7021
|
setModeOverlayError(null);
|
|
@@ -7445,12 +7207,11 @@ function FloPayCheckout({
|
|
|
7445
7207
|
resolvedSessionId,
|
|
7446
7208
|
session
|
|
7447
7209
|
]);
|
|
7448
|
-
|
|
7210
|
+
useEffect5(() => {
|
|
7449
7211
|
let cancelled = false;
|
|
7450
7212
|
setLoadError(null);
|
|
7451
7213
|
if (createSessionHash) {
|
|
7452
7214
|
const params = createSessionParamsRef.current;
|
|
7453
|
-
setSession(buildSyntheticSession(params, checkoutModeProp));
|
|
7454
7215
|
setCurrentMode(effectiveCreateSessionMode);
|
|
7455
7216
|
setIsLoading(false);
|
|
7456
7217
|
if (initializedHashRef.current === createSessionHash) {
|
|
@@ -7458,6 +7219,7 @@ function FloPayCheckout({
|
|
|
7458
7219
|
cancelled = true;
|
|
7459
7220
|
};
|
|
7460
7221
|
}
|
|
7222
|
+
setSession(buildSyntheticSession(params, checkoutModeProp));
|
|
7461
7223
|
(async () => {
|
|
7462
7224
|
const hasPayPalRedirectParams = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent");
|
|
7463
7225
|
const shouldAutoProcessInlineSession = effectiveCreateSessionMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams;
|
|
@@ -7692,7 +7454,7 @@ function FloPayCheckout({
|
|
|
7692
7454
|
]
|
|
7693
7455
|
);
|
|
7694
7456
|
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
|
|
7695
|
-
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */
|
|
7457
|
+
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ jsx8(
|
|
7696
7458
|
ProcessingOverlay,
|
|
7697
7459
|
{
|
|
7698
7460
|
status: modeOverlayStatus,
|
|
@@ -7708,7 +7470,7 @@ function FloPayCheckout({
|
|
|
7708
7470
|
}
|
|
7709
7471
|
if (layout === "buttons") {
|
|
7710
7472
|
const bundleRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
7711
|
-
const skeletonBar = (h) => /* @__PURE__ */
|
|
7473
|
+
const skeletonBar = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
7712
7474
|
height: h,
|
|
7713
7475
|
borderRadius: bundleRadius,
|
|
7714
7476
|
background: "#e5e7eb",
|
|
@@ -7719,14 +7481,14 @@ function FloPayCheckout({
|
|
|
7719
7481
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7720
7482
|
showStripe && (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7721
7483
|
showStripe && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
7722
|
-
/* @__PURE__ */
|
|
7484
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
7723
7485
|
] }),
|
|
7724
7486
|
modeOverlay
|
|
7725
7487
|
] });
|
|
7726
7488
|
}
|
|
7727
7489
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7728
7490
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
|
|
7729
|
-
/* @__PURE__ */
|
|
7491
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
7730
7492
|
width: 24,
|
|
7731
7493
|
height: 24,
|
|
7732
7494
|
border: "2px solid #e5e7eb",
|
|
@@ -7734,16 +7496,16 @@ function FloPayCheckout({
|
|
|
7734
7496
|
borderRadius: "50%",
|
|
7735
7497
|
animation: "spin 0.6s linear infinite"
|
|
7736
7498
|
} }),
|
|
7737
|
-
/* @__PURE__ */
|
|
7499
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
7738
7500
|
] }),
|
|
7739
7501
|
modeOverlay
|
|
7740
7502
|
] });
|
|
7741
7503
|
}
|
|
7742
7504
|
if (loadError) {
|
|
7743
7505
|
if (errorNode) {
|
|
7744
|
-
return /* @__PURE__ */
|
|
7506
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
|
|
7745
7507
|
}
|
|
7746
|
-
return /* @__PURE__ */
|
|
7508
|
+
return /* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
7747
7509
|
"div",
|
|
7748
7510
|
{
|
|
7749
7511
|
role: "alert",
|
|
@@ -7760,7 +7522,7 @@ function FloPayCheckout({
|
|
|
7760
7522
|
}
|
|
7761
7523
|
if (shouldShowInterimButtons) {
|
|
7762
7524
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7763
|
-
/* @__PURE__ */
|
|
7525
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(
|
|
7764
7526
|
InterimButtonsView,
|
|
7765
7527
|
{
|
|
7766
7528
|
onButtonClick,
|
|
@@ -7781,27 +7543,42 @@ function FloPayCheckout({
|
|
|
7781
7543
|
}
|
|
7782
7544
|
if (isPaypalOnlySession && session && directPaypalConfig) {
|
|
7783
7545
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7784
|
-
/* @__PURE__ */
|
|
7785
|
-
modeError && /* @__PURE__ */
|
|
7786
|
-
/* @__PURE__ */
|
|
7787
|
-
|
|
7546
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsxs6("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
7547
|
+
modeError && /* @__PURE__ */ jsx8(ErrorBanner, { icon: false, children: modeError }),
|
|
7548
|
+
paypalInitializationState === "retrying" && /* @__PURE__ */ jsx8("div", { role: "status", "aria-live": "polite", children: "PayPal is temporarily unavailable. Retrying\u2026" }),
|
|
7549
|
+
paypalInitializationState === "exhausted" && /* @__PURE__ */ jsxs6("div", { role: "alert", children: [
|
|
7550
|
+
/* @__PURE__ */ jsx8("div", { children: "PayPal is temporarily unavailable. Please try again." }),
|
|
7551
|
+
/* @__PURE__ */ jsx8("button", { type: "button", onClick: retryPayPalInitialization, children: "Retry PayPal" })
|
|
7552
|
+
] }),
|
|
7553
|
+
paypalInitializationState !== "exhausted" && /* @__PURE__ */ jsx8(
|
|
7554
|
+
"div",
|
|
7788
7555
|
{
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7556
|
+
"aria-hidden": paypalInitializationState === "retrying" ? true : void 0,
|
|
7557
|
+
style: paypalInitializationState === "retrying" ? { position: "relative", height: 0, opacity: 0, pointerEvents: "none" } : void 0,
|
|
7558
|
+
children: /* @__PURE__ */ jsx8(
|
|
7559
|
+
InstrumentedDirectPayPalButton,
|
|
7560
|
+
{
|
|
7561
|
+
sessionId: activeSessionId,
|
|
7562
|
+
nonce: session.clientSecret || void 0,
|
|
7563
|
+
billingApiUrl: resolvedBillingUrl,
|
|
7564
|
+
email: session.customer?.email,
|
|
7565
|
+
clientId: directPaypalConfig.clientId,
|
|
7566
|
+
environment: directPaypalConfig.environment,
|
|
7567
|
+
currency: (session.currency ?? "usd").toUpperCase(),
|
|
7568
|
+
isSubscription: session.mode === "subscription",
|
|
7569
|
+
onComplete,
|
|
7570
|
+
onErrorChange: setModeError,
|
|
7571
|
+
onDecline,
|
|
7572
|
+
onButtonClick,
|
|
7573
|
+
onInitializationStateChange: handlePayPalInitializationStateChange,
|
|
7574
|
+
allowAutomaticRetry: paypalManualRetryGeneration === 0,
|
|
7575
|
+
session,
|
|
7576
|
+
telemetry,
|
|
7577
|
+
telemetryContext: telemetryCheckoutContext,
|
|
7578
|
+
debug
|
|
7579
|
+
},
|
|
7580
|
+
`paypal-init-${paypalManualRetryGeneration}`
|
|
7581
|
+
)
|
|
7805
7582
|
}
|
|
7806
7583
|
)
|
|
7807
7584
|
] }) }),
|
|
@@ -7809,12 +7586,12 @@ function FloPayCheckout({
|
|
|
7809
7586
|
] });
|
|
7810
7587
|
}
|
|
7811
7588
|
if (!flopay || !providerOptions) {
|
|
7812
|
-
return /* @__PURE__ */
|
|
7589
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: modeOverlay });
|
|
7813
7590
|
}
|
|
7814
7591
|
if (currentMode === "confirm") {
|
|
7815
7592
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7816
|
-
/* @__PURE__ */
|
|
7817
|
-
modeError && /* @__PURE__ */
|
|
7593
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ jsxs6("div", { className, children: [
|
|
7594
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
7818
7595
|
"div",
|
|
7819
7596
|
{
|
|
7820
7597
|
style: {
|
|
@@ -7829,7 +7606,7 @@ function FloPayCheckout({
|
|
|
7829
7606
|
renderConfirmButton ? renderConfirmButton({
|
|
7830
7607
|
onConfirm: handleConfirmCheckout,
|
|
7831
7608
|
isProcessing: confirmProcessing
|
|
7832
|
-
}) : /* @__PURE__ */
|
|
7609
|
+
}) : /* @__PURE__ */ jsx8(
|
|
7833
7610
|
"button",
|
|
7834
7611
|
{
|
|
7835
7612
|
type: "button",
|
|
@@ -7855,8 +7632,8 @@ function FloPayCheckout({
|
|
|
7855
7632
|
] });
|
|
7856
7633
|
}
|
|
7857
7634
|
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7858
|
-
/* @__PURE__ */
|
|
7859
|
-
modeError && /* @__PURE__ */
|
|
7635
|
+
/* @__PURE__ */ jsx8(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx8(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
7636
|
+
modeError && /* @__PURE__ */ jsx8(
|
|
7860
7637
|
"div",
|
|
7861
7638
|
{
|
|
7862
7639
|
style: {
|
|
@@ -7871,7 +7648,7 @@ function FloPayCheckout({
|
|
|
7871
7648
|
children: modeError
|
|
7872
7649
|
}
|
|
7873
7650
|
),
|
|
7874
|
-
/* @__PURE__ */
|
|
7651
|
+
/* @__PURE__ */ jsx8(
|
|
7875
7652
|
SessionInjector,
|
|
7876
7653
|
{
|
|
7877
7654
|
sessionId: activeSessionId,
|
|
@@ -7881,7 +7658,7 @@ function FloPayCheckout({
|
|
|
7881
7658
|
children
|
|
7882
7659
|
}
|
|
7883
7660
|
)
|
|
7884
|
-
] }) : /* @__PURE__ */
|
|
7661
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
7885
7662
|
SplitCardForm,
|
|
7886
7663
|
{
|
|
7887
7664
|
sessionId: activeSessionId,
|
|
@@ -7897,7 +7674,6 @@ function FloPayCheckout({
|
|
|
7897
7674
|
onDecline,
|
|
7898
7675
|
error: modeError,
|
|
7899
7676
|
onErrorChange: setModeError,
|
|
7900
|
-
onFullNameChange,
|
|
7901
7677
|
showPayPal,
|
|
7902
7678
|
showStripe,
|
|
7903
7679
|
enabledPaymentMethods: unified?.data.stripe?.enabledPaymentMethods,
|
|
@@ -7926,7 +7702,6 @@ function FloPayCheckout({
|
|
|
7926
7702
|
avsCheck: !!enableAVS,
|
|
7927
7703
|
checkoutType: createSessionParams ? "embedded_checkout" : "standard_checkout",
|
|
7928
7704
|
checkoutLayout: children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout",
|
|
7929
|
-
submitLabel,
|
|
7930
7705
|
className,
|
|
7931
7706
|
directPaypal: resolveDirectPaypalConfig(unified),
|
|
7932
7707
|
isSubscription: session?.mode === "subscription",
|
|
@@ -7944,8 +7719,8 @@ function SessionInjector({
|
|
|
7944
7719
|
session,
|
|
7945
7720
|
children
|
|
7946
7721
|
}) {
|
|
7947
|
-
return /* @__PURE__ */
|
|
7948
|
-
if (!
|
|
7722
|
+
return /* @__PURE__ */ jsx8(Fragment3, { children: React8.Children.map(children, (child) => {
|
|
7723
|
+
if (!React8.isValidElement(child)) return child;
|
|
7949
7724
|
const existing = child.props;
|
|
7950
7725
|
const injected = {};
|
|
7951
7726
|
if (!existing.sessionId) injected.sessionId = sessionId;
|
|
@@ -7960,7 +7735,7 @@ function SessionInjector({
|
|
|
7960
7735
|
injected.lastName = session.customer.lastName;
|
|
7961
7736
|
}
|
|
7962
7737
|
if (Object.keys(injected).length === 0) return child;
|
|
7963
|
-
return
|
|
7738
|
+
return React8.cloneElement(child, injected);
|
|
7964
7739
|
}) });
|
|
7965
7740
|
}
|
|
7966
7741
|
function InterimButtonsView({
|
|
@@ -7993,7 +7768,7 @@ function InterimButtonsView({
|
|
|
7993
7768
|
};
|
|
7994
7769
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
7995
7770
|
const skeletonRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
7996
|
-
const skeleton = (h) => /* @__PURE__ */
|
|
7771
|
+
const skeleton = (h) => /* @__PURE__ */ jsx8("div", { style: {
|
|
7997
7772
|
height: h,
|
|
7998
7773
|
borderRadius: skeletonRadius,
|
|
7999
7774
|
background: "#e5e7eb",
|
|
@@ -8035,7 +7810,7 @@ function InterimButtonsView({
|
|
|
8035
7810
|
...bStyles.backButton
|
|
8036
7811
|
},
|
|
8037
7812
|
children: [
|
|
8038
|
-
/* @__PURE__ */
|
|
7813
|
+
/* @__PURE__ */ jsx8("span", { style: {
|
|
8039
7814
|
display: "inline-flex",
|
|
8040
7815
|
alignItems: "center",
|
|
8041
7816
|
justifyContent: "center",
|
|
@@ -8044,12 +7819,12 @@ function InterimButtonsView({
|
|
|
8044
7819
|
borderRadius: "50%",
|
|
8045
7820
|
backgroundColor: "#f3f4f6",
|
|
8046
7821
|
...bStyles.backButtonIcon
|
|
8047
|
-
}, children: /* @__PURE__ */
|
|
8048
|
-
/* @__PURE__ */
|
|
7822
|
+
}, 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" }) }) }),
|
|
7823
|
+
/* @__PURE__ */ jsx8(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
8049
7824
|
]
|
|
8050
7825
|
}
|
|
8051
7826
|
),
|
|
8052
|
-
hideTitle ? /* @__PURE__ */
|
|
7827
|
+
hideTitle ? /* @__PURE__ */ jsx8("div", { style: { flex: 1 } }) : /* @__PURE__ */ jsx8("div", { style: {
|
|
8053
7828
|
flex: 1,
|
|
8054
7829
|
textAlign: "center",
|
|
8055
7830
|
fontWeight: 600,
|
|
@@ -8057,11 +7832,11 @@ function InterimButtonsView({
|
|
|
8057
7832
|
color: "#262833",
|
|
8058
7833
|
paddingRight: 80,
|
|
8059
7834
|
...bStyles.title
|
|
8060
|
-
}, children: /* @__PURE__ */
|
|
7835
|
+
}, children: /* @__PURE__ */ jsx8(TitleContentSlot, { content: cardTitleContent }) })
|
|
8061
7836
|
] }),
|
|
8062
|
-
/* @__PURE__ */
|
|
7837
|
+
/* @__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
7838
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex" }, children: [
|
|
8064
|
-
/* @__PURE__ */
|
|
7839
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8065
7840
|
flex: 1,
|
|
8066
7841
|
backgroundColor: inputBg,
|
|
8067
7842
|
borderTop: "none",
|
|
@@ -8071,8 +7846,8 @@ function InterimButtonsView({
|
|
|
8071
7846
|
borderBottomLeftRadius: 8,
|
|
8072
7847
|
padding: 12,
|
|
8073
7848
|
height: 45
|
|
8074
|
-
}, children: /* @__PURE__ */
|
|
8075
|
-
/* @__PURE__ */
|
|
7849
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
7850
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8076
7851
|
flex: 1,
|
|
8077
7852
|
backgroundColor: inputBg,
|
|
8078
7853
|
borderTop: "none",
|
|
@@ -8082,10 +7857,10 @@ function InterimButtonsView({
|
|
|
8082
7857
|
borderBottomRightRadius: 8,
|
|
8083
7858
|
padding: 12,
|
|
8084
7859
|
height: 45
|
|
8085
|
-
}, children: /* @__PURE__ */
|
|
7860
|
+
}, children: /* @__PURE__ */ jsx8("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
8086
7861
|
] }),
|
|
8087
|
-
/* @__PURE__ */
|
|
8088
|
-
/* @__PURE__ */
|
|
7862
|
+
/* @__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" } }) }),
|
|
7863
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
8089
7864
|
height: 50,
|
|
8090
7865
|
borderRadius: 8,
|
|
8091
7866
|
marginTop: 16,
|
|
@@ -8094,7 +7869,7 @@ function InterimButtonsView({
|
|
|
8094
7869
|
...bStyles.submitButton,
|
|
8095
7870
|
opacity: 0.5
|
|
8096
7871
|
} }),
|
|
8097
|
-
/* @__PURE__ */
|
|
7872
|
+
/* @__PURE__ */ jsx8("style", { children: `
|
|
8098
7873
|
@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
8099
7874
|
@keyframes flopay-interim-expand {
|
|
8100
7875
|
0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
|
|
@@ -8107,7 +7882,7 @@ function InterimButtonsView({
|
|
|
8107
7882
|
return /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
8108
7883
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
8109
7884
|
showStripe && (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
8110
|
-
showStripe && /* @__PURE__ */
|
|
7885
|
+
showStripe && /* @__PURE__ */ jsx8(
|
|
8111
7886
|
"button",
|
|
8112
7887
|
{
|
|
8113
7888
|
type: "button",
|
|
@@ -8141,362 +7916,80 @@ function InterimButtonsView({
|
|
|
8141
7916
|
onMouseUp: (e) => {
|
|
8142
7917
|
e.currentTarget.style.transform = "scale(1)";
|
|
8143
7918
|
},
|
|
8144
|
-
children: /* @__PURE__ */
|
|
7919
|
+
children: /* @__PURE__ */ jsx8(CardButtonContentSlot, { content: cardButtonContent })
|
|
8145
7920
|
}
|
|
8146
7921
|
),
|
|
8147
|
-
/* @__PURE__ */
|
|
7922
|
+
/* @__PURE__ */ jsx8("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
8148
7923
|
] });
|
|
8149
7924
|
}
|
|
8150
7925
|
|
|
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;
|
|
7926
|
+
// src/elements.tsx
|
|
7927
|
+
import { useEffect as useEffect6, useRef as useRef6, useContext as useContext3 } from "react";
|
|
7928
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
7929
|
+
function createElementComponent(elementType, displayName) {
|
|
7930
|
+
function ElementComponent({
|
|
7931
|
+
className,
|
|
7932
|
+
id,
|
|
7933
|
+
style,
|
|
7934
|
+
options,
|
|
7935
|
+
onChange,
|
|
7936
|
+
onReady,
|
|
7937
|
+
onFocus,
|
|
7938
|
+
onBlur,
|
|
7939
|
+
onEscape
|
|
7940
|
+
}) {
|
|
7941
|
+
const containerRef = useRef6(null);
|
|
7942
|
+
const elementRef = useRef6(null);
|
|
7943
|
+
const { elements, reportInteractive } = useContext3(FloPayContext);
|
|
7944
|
+
useEffect6(() => {
|
|
7945
|
+
if (!elements || !containerRef.current) return;
|
|
7946
|
+
let mounted = true;
|
|
7947
|
+
(async () => {
|
|
7948
|
+
let element = elements.getElement(elementType);
|
|
7949
|
+
if (!element) {
|
|
7950
|
+
element = await elements.create(elementType, options);
|
|
8435
7951
|
}
|
|
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);
|
|
7952
|
+
if (!mounted || !containerRef.current) {
|
|
8447
7953
|
return;
|
|
8448
7954
|
}
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
7955
|
+
element.mount(containerRef.current);
|
|
7956
|
+
elementRef.current = element;
|
|
7957
|
+
if (onChange) element.on("change", onChange);
|
|
7958
|
+
element.on("ready", () => {
|
|
7959
|
+
reportInteractive?.();
|
|
7960
|
+
onReady?.();
|
|
8455
7961
|
});
|
|
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
|
|
7962
|
+
if (onFocus) element.on("focus", onFocus);
|
|
7963
|
+
if (onBlur) element.on("blur", onBlur);
|
|
7964
|
+
if (onEscape) element.on("escape", onEscape);
|
|
7965
|
+
})();
|
|
7966
|
+
return () => {
|
|
7967
|
+
mounted = false;
|
|
7968
|
+
if (elementRef.current) {
|
|
7969
|
+
try {
|
|
7970
|
+
elementRef.current.unmount();
|
|
7971
|
+
} catch {
|
|
7972
|
+
}
|
|
7973
|
+
elementRef.current = null;
|
|
8489
7974
|
}
|
|
8490
|
-
|
|
8491
|
-
]
|
|
8492
|
-
|
|
7975
|
+
};
|
|
7976
|
+
}, [elements, reportInteractive]);
|
|
7977
|
+
return /* @__PURE__ */ jsx9("div", { ref: containerRef, className, id, style });
|
|
7978
|
+
}
|
|
7979
|
+
ElementComponent.displayName = displayName;
|
|
7980
|
+
return ElementComponent;
|
|
8493
7981
|
}
|
|
7982
|
+
var PaymentElement2 = createElementComponent(
|
|
7983
|
+
"payment",
|
|
7984
|
+
"PaymentElement"
|
|
7985
|
+
);
|
|
7986
|
+
var AddressElement = createElementComponent("address", "AddressElement");
|
|
8494
7987
|
|
|
8495
7988
|
// src/paypal-button.tsx
|
|
8496
|
-
import { PaymentAPI as
|
|
8497
|
-
import { FloPayError as
|
|
8498
|
-
import { useCallback as
|
|
8499
|
-
import { Fragment as
|
|
7989
|
+
import { PaymentAPI as PaymentAPI5 } from "@flopay/js";
|
|
7990
|
+
import { FloPayError as FloPayError6 } from "@flopay/shared";
|
|
7991
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef7, useState as useState5 } from "react";
|
|
7992
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8500
7993
|
function PayPalButton({
|
|
8501
7994
|
sessionId,
|
|
8502
7995
|
nonce,
|
|
@@ -8514,14 +8007,14 @@ function PayPalButton({
|
|
|
8514
8007
|
const flopay = useFloPay();
|
|
8515
8008
|
const elements = useElements();
|
|
8516
8009
|
const contextBillingUrl = useBillingApiUrl();
|
|
8517
|
-
const [ready, setReady] =
|
|
8518
|
-
const [submitting, setSubmitting] =
|
|
8010
|
+
const [ready, setReady] = useState5(false);
|
|
8011
|
+
const [submitting, setSubmitting] = useState5(false);
|
|
8519
8012
|
const paypalResumeAttempted = useRef7(false);
|
|
8520
8013
|
const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
|
|
8521
|
-
const processPaymentInternal =
|
|
8014
|
+
const processPaymentInternal = useCallback5(
|
|
8522
8015
|
async (tokenizedBody) => {
|
|
8523
8016
|
try {
|
|
8524
|
-
const api = new
|
|
8017
|
+
const api = new PaymentAPI5(baseUrl);
|
|
8525
8018
|
const response = await api.processPayment(userId ?? "", {
|
|
8526
8019
|
sessionId,
|
|
8527
8020
|
nonce,
|
|
@@ -8546,7 +8039,7 @@ function PayPalButton({
|
|
|
8546
8039
|
},
|
|
8547
8040
|
[baseUrl, sessionId, nonce, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
|
|
8548
8041
|
);
|
|
8549
|
-
const dispatchTokenizedBody =
|
|
8042
|
+
const dispatchTokenizedBody = useCallback5(
|
|
8550
8043
|
(body) => {
|
|
8551
8044
|
if (onTokenizedBody) {
|
|
8552
8045
|
onTokenizedBody(body);
|
|
@@ -8556,7 +8049,7 @@ function PayPalButton({
|
|
|
8556
8049
|
},
|
|
8557
8050
|
[onTokenizedBody, processPaymentInternal]
|
|
8558
8051
|
);
|
|
8559
|
-
|
|
8052
|
+
useEffect7(() => {
|
|
8560
8053
|
if (!flopay || paypalResumeAttempted.current) return;
|
|
8561
8054
|
const params = new URLSearchParams(window.location.search);
|
|
8562
8055
|
const paymentIntentId = params.get("payment_intent");
|
|
@@ -8604,13 +8097,13 @@ function PayPalButton({
|
|
|
8604
8097
|
}
|
|
8605
8098
|
})();
|
|
8606
8099
|
}, [flopay, dispatchTokenizedBody, onErrorChange]);
|
|
8607
|
-
const handlePayPalConfirm =
|
|
8100
|
+
const handlePayPalConfirm = useCallback5(async () => {
|
|
8608
8101
|
if (!flopay || !elements) return;
|
|
8609
8102
|
try {
|
|
8610
8103
|
setSubmitting(true);
|
|
8611
8104
|
onErrorChange?.(null);
|
|
8612
8105
|
if (!sessionId || !email) {
|
|
8613
|
-
throw new
|
|
8106
|
+
throw new FloPayError6("Missing sessionId or email for PayPal payment", "validation_error");
|
|
8614
8107
|
}
|
|
8615
8108
|
const result = await flopay.confirmPayPalPayment({
|
|
8616
8109
|
billingApiUrl: baseUrl,
|
|
@@ -8638,11 +8131,11 @@ function PayPalButton({
|
|
|
8638
8131
|
}
|
|
8639
8132
|
}, [flopay, elements, sessionId, nonce, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
|
|
8640
8133
|
if (!flopay || !elements) {
|
|
8641
|
-
return /* @__PURE__ */
|
|
8134
|
+
return /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
|
|
8642
8135
|
}
|
|
8643
|
-
return /* @__PURE__ */
|
|
8644
|
-
!ready && /* @__PURE__ */
|
|
8645
|
-
/* @__PURE__ */
|
|
8136
|
+
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
8137
|
+
!ready && /* @__PURE__ */ jsx10("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
|
|
8138
|
+
/* @__PURE__ */ jsx10("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ jsx10(
|
|
8646
8139
|
"button",
|
|
8647
8140
|
{
|
|
8648
8141
|
type: "button",
|
|
@@ -8664,7 +8157,7 @@ function PayPalButton({
|
|
|
8664
8157
|
children: submitting ? "Processing..." : "PayPal"
|
|
8665
8158
|
}
|
|
8666
8159
|
) }),
|
|
8667
|
-
(submitting || isProcessing) && /* @__PURE__ */
|
|
8160
|
+
(submitting || isProcessing) && /* @__PURE__ */ jsx10("div", { style: {
|
|
8668
8161
|
position: "fixed",
|
|
8669
8162
|
inset: 0,
|
|
8670
8163
|
background: "rgba(0,0,0,0.4)",
|
|
@@ -8672,7 +8165,7 @@ function PayPalButton({
|
|
|
8672
8165
|
alignItems: "center",
|
|
8673
8166
|
justifyContent: "center",
|
|
8674
8167
|
zIndex: 1e3
|
|
8675
|
-
}, children: /* @__PURE__ */
|
|
8168
|
+
}, children: /* @__PURE__ */ jsx10("div", { style: {
|
|
8676
8169
|
background: "white",
|
|
8677
8170
|
borderRadius: 8,
|
|
8678
8171
|
padding: "1.5rem",
|
|
@@ -8684,19 +8177,19 @@ function PayPalButton({
|
|
|
8684
8177
|
}
|
|
8685
8178
|
|
|
8686
8179
|
// src/automatic-payment-button.tsx
|
|
8687
|
-
import { useCallback as
|
|
8688
|
-
import { PaymentAPI as
|
|
8689
|
-
import { FloPayError as
|
|
8690
|
-
import { Fragment as
|
|
8180
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef8, useState as useState6 } from "react";
|
|
8181
|
+
import { PaymentAPI as PaymentAPI6 } from "@flopay/js";
|
|
8182
|
+
import { FloPayError as FloPayError7, resolveBillingApiUrl as resolveBillingApiUrl4, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme3, resolveTheme as resolveTheme3 } from "@flopay/shared";
|
|
8183
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
8691
8184
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
|
|
8692
8185
|
function sleep2(ms) {
|
|
8693
8186
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8694
8187
|
}
|
|
8695
8188
|
function coerceError(err, fallbackMessage) {
|
|
8696
|
-
if (err instanceof
|
|
8189
|
+
if (err instanceof FloPayError7) {
|
|
8697
8190
|
return err;
|
|
8698
8191
|
}
|
|
8699
|
-
return new
|
|
8192
|
+
return new FloPayError7(
|
|
8700
8193
|
err instanceof Error ? err.message : fallbackMessage,
|
|
8701
8194
|
"api_error"
|
|
8702
8195
|
);
|
|
@@ -8799,36 +8292,36 @@ function FloPayAutomaticPaymentButton({
|
|
|
8799
8292
|
utmMetadata
|
|
8800
8293
|
]
|
|
8801
8294
|
);
|
|
8802
|
-
const [isProcessing, setIsProcessing] =
|
|
8803
|
-
const [overlayStatus, setOverlayStatus] =
|
|
8804
|
-
const [overlayError, setOverlayError] =
|
|
8805
|
-
const [fallbackSession, setFallbackSession] =
|
|
8295
|
+
const [isProcessing, setIsProcessing] = useState6(false);
|
|
8296
|
+
const [overlayStatus, setOverlayStatus] = useState6(null);
|
|
8297
|
+
const [overlayError, setOverlayError] = useState6(null);
|
|
8298
|
+
const [fallbackSession, setFallbackSession] = useState6(null);
|
|
8806
8299
|
const isMountedRef = useRef8(true);
|
|
8807
8300
|
const threeDsAbortRef = useRef8(null);
|
|
8808
8301
|
const fallbackSessionRef = useRef8(fallbackSession);
|
|
8809
8302
|
const onSuccessRef = useRef8(onSuccess);
|
|
8810
8303
|
const onErrorRef = useRef8(onError);
|
|
8811
8304
|
const onDeclineRef = useRef8(onDecline);
|
|
8812
|
-
|
|
8305
|
+
useEffect8(() => {
|
|
8813
8306
|
fallbackSessionRef.current = fallbackSession;
|
|
8814
8307
|
}, [fallbackSession]);
|
|
8815
|
-
|
|
8308
|
+
useEffect8(() => {
|
|
8816
8309
|
onSuccessRef.current = onSuccess;
|
|
8817
8310
|
}, [onSuccess]);
|
|
8818
|
-
|
|
8311
|
+
useEffect8(() => {
|
|
8819
8312
|
onErrorRef.current = onError;
|
|
8820
8313
|
}, [onError]);
|
|
8821
|
-
|
|
8314
|
+
useEffect8(() => {
|
|
8822
8315
|
onDeclineRef.current = onDecline;
|
|
8823
8316
|
}, [onDecline]);
|
|
8824
|
-
|
|
8317
|
+
useEffect8(() => {
|
|
8825
8318
|
isMountedRef.current = true;
|
|
8826
8319
|
return () => {
|
|
8827
8320
|
isMountedRef.current = false;
|
|
8828
8321
|
threeDsAbortRef.current?.abort();
|
|
8829
8322
|
};
|
|
8830
8323
|
}, []);
|
|
8831
|
-
|
|
8324
|
+
useEffect8(() => {
|
|
8832
8325
|
if (typeof window === "undefined") {
|
|
8833
8326
|
return;
|
|
8834
8327
|
}
|
|
@@ -8842,13 +8335,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
8842
8335
|
window.removeEventListener("keydown", handleKeyDown);
|
|
8843
8336
|
};
|
|
8844
8337
|
}, []);
|
|
8845
|
-
const emitDecline =
|
|
8338
|
+
const emitDecline = useCallback6((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
|
|
8846
8339
|
onDeclineRef.current?.(buildDeclineEvent(method, error, {
|
|
8847
8340
|
code: error.code,
|
|
8848
8341
|
declineCode: error.declineCode
|
|
8849
8342
|
}));
|
|
8850
8343
|
}, []);
|
|
8851
|
-
const showSuccess =
|
|
8344
|
+
const showSuccess = useCallback6(async (event) => {
|
|
8852
8345
|
if (!isMountedRef.current) return;
|
|
8853
8346
|
setOverlayError(null);
|
|
8854
8347
|
setOverlayStatus("success");
|
|
@@ -8856,7 +8349,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
8856
8349
|
if (!isMountedRef.current) return;
|
|
8857
8350
|
onSuccessRef.current?.(event);
|
|
8858
8351
|
}, []);
|
|
8859
|
-
const showError =
|
|
8352
|
+
const showError = useCallback6(async (error, options) => {
|
|
8860
8353
|
if (!isMountedRef.current) return;
|
|
8861
8354
|
onErrorRef.current?.(error);
|
|
8862
8355
|
if (options?.emitDecline) {
|
|
@@ -8866,10 +8359,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
8866
8359
|
setOverlayStatus("error");
|
|
8867
8360
|
await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
|
|
8868
8361
|
}, [emitDecline]);
|
|
8869
|
-
const processResolvedSession =
|
|
8362
|
+
const processResolvedSession = useCallback6(async (apiResult, resolvedSessionId, options) => {
|
|
8870
8363
|
const session = apiResult.data.session ?? null;
|
|
8871
8364
|
if (!session) {
|
|
8872
|
-
throw new
|
|
8365
|
+
throw new FloPayError7("No session data returned", "api_error");
|
|
8873
8366
|
}
|
|
8874
8367
|
const effectiveNonce = session.clientSecret || nonce;
|
|
8875
8368
|
if (session.status === "complete") {
|
|
@@ -8882,19 +8375,19 @@ function FloPayAutomaticPaymentButton({
|
|
|
8882
8375
|
return;
|
|
8883
8376
|
}
|
|
8884
8377
|
if (session.status === "expired") {
|
|
8885
|
-
throw new
|
|
8378
|
+
throw new FloPayError7("Checkout session has expired.", "api_error", {
|
|
8886
8379
|
code: "checkout_session_expired"
|
|
8887
8380
|
});
|
|
8888
8381
|
}
|
|
8889
8382
|
try {
|
|
8890
8383
|
if (apiResult.autoProcessingPending) {
|
|
8891
|
-
const api = new
|
|
8384
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
8892
8385
|
const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
|
|
8893
8386
|
initialDelayMs: apiResult.autoProcessingPending.retryAfterMs
|
|
8894
8387
|
});
|
|
8895
8388
|
const completedSession = completed.data.session;
|
|
8896
8389
|
if (!completedSession || completedSession.status !== "complete") {
|
|
8897
|
-
throw new
|
|
8390
|
+
throw new FloPayError7("Automatic payment failed. Please try again.", "api_error", {
|
|
8898
8391
|
code: completedSession?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
|
|
8899
8392
|
});
|
|
8900
8393
|
}
|
|
@@ -8937,7 +8430,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
8937
8430
|
}
|
|
8938
8431
|
);
|
|
8939
8432
|
}
|
|
8940
|
-
const api = new
|
|
8433
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
8941
8434
|
const completed = await api.waitForCheckoutSessionCompletion(resolvedSessionId, {
|
|
8942
8435
|
initialDelayMs: 0,
|
|
8943
8436
|
nonce: effectiveNonce
|
|
@@ -9022,14 +8515,14 @@ function FloPayAutomaticPaymentButton({
|
|
|
9022
8515
|
showError,
|
|
9023
8516
|
showSuccess
|
|
9024
8517
|
]);
|
|
9025
|
-
const handleButtonClick =
|
|
8518
|
+
const handleButtonClick = useCallback6(async (event) => {
|
|
9026
8519
|
buttonProps.onClick?.(event);
|
|
9027
8520
|
if (event.defaultPrevented || disabled || isProcessing) {
|
|
9028
8521
|
return;
|
|
9029
8522
|
}
|
|
9030
8523
|
setFallbackSession(null);
|
|
9031
8524
|
if (sessionId && createSessionDraft) {
|
|
9032
|
-
const error = new
|
|
8525
|
+
const error = new FloPayError7(
|
|
9033
8526
|
"Provide either sessionId or create-session props, not both.",
|
|
9034
8527
|
"validation_error"
|
|
9035
8528
|
);
|
|
@@ -9041,7 +8534,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9041
8534
|
return;
|
|
9042
8535
|
}
|
|
9043
8536
|
if (!sessionId && !createSessionDraft) {
|
|
9044
|
-
const error = new
|
|
8537
|
+
const error = new FloPayError7(
|
|
9045
8538
|
"Provide a sessionId or the props required to create an automatic payment session.",
|
|
9046
8539
|
"validation_error"
|
|
9047
8540
|
);
|
|
@@ -9056,7 +8549,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9056
8549
|
setOverlayError(null);
|
|
9057
8550
|
setOverlayStatus("processing");
|
|
9058
8551
|
try {
|
|
9059
|
-
const api = new
|
|
8552
|
+
const api = new PaymentAPI6(resolvedBillingUrl);
|
|
9060
8553
|
if (sessionId) {
|
|
9061
8554
|
const result = await api.getUnifiedCheckoutSession(sessionId, nonce);
|
|
9062
8555
|
await processResolvedSession(result, sessionId);
|
|
@@ -9070,7 +8563,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9070
8563
|
fromCreateSession: true
|
|
9071
8564
|
});
|
|
9072
8565
|
} catch (err) {
|
|
9073
|
-
if (err instanceof
|
|
8566
|
+
if (err instanceof FloPayError7 && err.code === "session_auto_completed") {
|
|
9074
8567
|
await showSuccess({
|
|
9075
8568
|
result: { status: "succeeded" },
|
|
9076
8569
|
session: null,
|
|
@@ -9104,7 +8597,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9104
8597
|
showError,
|
|
9105
8598
|
showSuccess
|
|
9106
8599
|
]);
|
|
9107
|
-
const handleFallbackComplete =
|
|
8600
|
+
const handleFallbackComplete = useCallback6((result) => {
|
|
9108
8601
|
const activeFallback = fallbackSessionRef.current;
|
|
9109
8602
|
setFallbackSession(null);
|
|
9110
8603
|
onSuccessRef.current?.({
|
|
@@ -9114,10 +8607,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
9114
8607
|
autoCompleted: false
|
|
9115
8608
|
});
|
|
9116
8609
|
}, []);
|
|
9117
|
-
const handleFallbackError =
|
|
8610
|
+
const handleFallbackError = useCallback6((error) => {
|
|
9118
8611
|
onErrorRef.current?.(error);
|
|
9119
8612
|
}, []);
|
|
9120
|
-
const handleFallbackDecline =
|
|
8613
|
+
const handleFallbackDecline = useCallback6((decline) => {
|
|
9121
8614
|
onDeclineRef.current?.(decline);
|
|
9122
8615
|
}, []);
|
|
9123
8616
|
const themeBundle = useMemo5(() => resolveTheme3(theme), [theme]);
|
|
@@ -9148,8 +8641,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
9148
8641
|
const resolvedPrimaryHoverColor = resolvedAppearanceVars?.colorPrimaryHover ?? darkenHex(resolvedPrimaryColor, 0.12);
|
|
9149
8642
|
const resolvedButtonBorderRadius = resolvedAppearanceVars?.borderRadius ?? "8px";
|
|
9150
8643
|
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__ */
|
|
8644
|
+
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
8645
|
+
/* @__PURE__ */ jsx11(
|
|
9153
8646
|
"button",
|
|
9154
8647
|
{
|
|
9155
8648
|
...buttonProps,
|
|
@@ -9213,17 +8706,17 @@ function FloPayAutomaticPaymentButton({
|
|
|
9213
8706
|
e.currentTarget.style.transform = "scale(1)";
|
|
9214
8707
|
}
|
|
9215
8708
|
},
|
|
9216
|
-
children: /* @__PURE__ */
|
|
8709
|
+
children: /* @__PURE__ */ jsx11(CardButtonContentSlot, { content: children })
|
|
9217
8710
|
}
|
|
9218
8711
|
),
|
|
9219
|
-
overlayStatus && /* @__PURE__ */
|
|
8712
|
+
overlayStatus && /* @__PURE__ */ jsx11(
|
|
9220
8713
|
ProcessingOverlay,
|
|
9221
8714
|
{
|
|
9222
8715
|
status: overlayStatus,
|
|
9223
8716
|
errorMessage: overlayError
|
|
9224
8717
|
}
|
|
9225
8718
|
),
|
|
9226
|
-
fallbackSession && /* @__PURE__ */
|
|
8719
|
+
fallbackSession && /* @__PURE__ */ jsx11(
|
|
9227
8720
|
"div",
|
|
9228
8721
|
{
|
|
9229
8722
|
"data-testid": "flopay-automatic-payment-fallback",
|
|
@@ -9244,7 +8737,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9244
8737
|
padding: "1.5rem",
|
|
9245
8738
|
zIndex: 1100
|
|
9246
8739
|
},
|
|
9247
|
-
children: /* @__PURE__ */
|
|
8740
|
+
children: /* @__PURE__ */ jsx11(
|
|
9248
8741
|
"div",
|
|
9249
8742
|
{
|
|
9250
8743
|
style: {
|
|
@@ -9260,7 +8753,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
9260
8753
|
flexDirection: "column",
|
|
9261
8754
|
gap: "1rem"
|
|
9262
8755
|
},
|
|
9263
|
-
children: /* @__PURE__ */
|
|
8756
|
+
children: /* @__PURE__ */ jsx11(
|
|
9264
8757
|
FloPayCheckout,
|
|
9265
8758
|
{
|
|
9266
8759
|
sessionId: fallbackSession.sessionId,
|
|
@@ -9287,17 +8780,12 @@ function FloPayAutomaticPaymentButton({
|
|
|
9287
8780
|
}
|
|
9288
8781
|
export {
|
|
9289
8782
|
AddressElement,
|
|
9290
|
-
CardCvcElement,
|
|
9291
|
-
CardElement,
|
|
9292
|
-
CardExpiryElement,
|
|
9293
|
-
CardNumberElement,
|
|
9294
|
-
CheckoutForm,
|
|
9295
8783
|
DirectPayPalButton,
|
|
9296
8784
|
FloPayAutomaticPaymentButton,
|
|
9297
8785
|
FloPayCheckout,
|
|
9298
8786
|
FloPayProvider,
|
|
9299
8787
|
PayPalButton,
|
|
9300
|
-
PaymentElement,
|
|
8788
|
+
PaymentElement2 as PaymentElement,
|
|
9301
8789
|
SplitCardForm,
|
|
9302
8790
|
VaultCardFields,
|
|
9303
8791
|
useCheckout,
|