@flopay/react 0.3.15 → 0.3.19
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 +14 -8
- package/dist/index.cjs +271 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.mjs +271 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -350,6 +350,25 @@ var FLOPAY_KEYFRAMES = `
|
|
|
350
350
|
100% { opacity: 0; transform: translateX(16px) scale(0.97); }
|
|
351
351
|
}
|
|
352
352
|
`;
|
|
353
|
+
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
|
|
354
|
+
function getButtonMethodLabel(method) {
|
|
355
|
+
switch (method) {
|
|
356
|
+
case "paypal":
|
|
357
|
+
return "PayPal";
|
|
358
|
+
case "apple_pay":
|
|
359
|
+
return "Apple Pay";
|
|
360
|
+
case "google_pay":
|
|
361
|
+
return "Google Pay";
|
|
362
|
+
default:
|
|
363
|
+
return "Card";
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function normalizeBeforeButtonClickError(method, err) {
|
|
367
|
+
return err instanceof FloPayError2 ? err : new FloPayError2(
|
|
368
|
+
err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
|
|
369
|
+
"validation_error"
|
|
370
|
+
);
|
|
371
|
+
}
|
|
353
372
|
function FloPayKeyframes() {
|
|
354
373
|
return /* @__PURE__ */ jsx4("style", { children: FLOPAY_KEYFRAMES });
|
|
355
374
|
}
|
|
@@ -361,6 +380,52 @@ function toCssWeight(value) {
|
|
|
361
380
|
if (typeof value === "number" || typeof value === "string") return value;
|
|
362
381
|
return void 0;
|
|
363
382
|
}
|
|
383
|
+
function resolveExpressCheckoutLoadState(event, methods) {
|
|
384
|
+
const available = event.availablePaymentMethods;
|
|
385
|
+
if (!available) return "unavailable";
|
|
386
|
+
return methods.some((method) => available[method]) ? "ready" : "unavailable";
|
|
387
|
+
}
|
|
388
|
+
function ExpressCheckoutReadySwap({
|
|
389
|
+
state,
|
|
390
|
+
placeholderTestId,
|
|
391
|
+
children
|
|
392
|
+
}) {
|
|
393
|
+
if (state === "unavailable") return null;
|
|
394
|
+
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative", minHeight: 44 }, children: [
|
|
395
|
+
/* @__PURE__ */ jsx4(
|
|
396
|
+
"div",
|
|
397
|
+
{
|
|
398
|
+
"data-testid": placeholderTestId,
|
|
399
|
+
"aria-hidden": state === "ready",
|
|
400
|
+
style: {
|
|
401
|
+
position: "absolute",
|
|
402
|
+
inset: 0,
|
|
403
|
+
height: 44,
|
|
404
|
+
borderRadius: 8,
|
|
405
|
+
background: "#e5e7eb",
|
|
406
|
+
animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
|
|
407
|
+
opacity: state === "ready" ? 0 : 1,
|
|
408
|
+
transform: state === "ready" ? "scale(0.985)" : "scale(1)",
|
|
409
|
+
transition: "opacity 140ms ease-out, transform 140ms ease-out",
|
|
410
|
+
pointerEvents: "none"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
),
|
|
414
|
+
/* @__PURE__ */ jsx4(
|
|
415
|
+
"div",
|
|
416
|
+
{
|
|
417
|
+
style: {
|
|
418
|
+
minHeight: 44,
|
|
419
|
+
opacity: state === "ready" ? 1 : 0,
|
|
420
|
+
transform: state === "ready" ? "translateY(0)" : "translateY(2px)",
|
|
421
|
+
transition: "opacity 140ms ease-out, transform 140ms ease-out",
|
|
422
|
+
pointerEvents: state === "ready" ? "auto" : "none"
|
|
423
|
+
},
|
|
424
|
+
children
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
] });
|
|
428
|
+
}
|
|
364
429
|
function ProcessingOverlay({ status, errorMessage }) {
|
|
365
430
|
return /* @__PURE__ */ jsx4("div", { style: {
|
|
366
431
|
position: "fixed",
|
|
@@ -474,13 +539,15 @@ function PayPalButtonInner({
|
|
|
474
539
|
onErrorChange,
|
|
475
540
|
isProcessing = false,
|
|
476
541
|
onButtonClick,
|
|
477
|
-
onDecline
|
|
542
|
+
onDecline,
|
|
543
|
+
runBeforeButtonClick
|
|
478
544
|
}) {
|
|
479
545
|
const stripe = useStripeRaw();
|
|
480
546
|
const elements = useStripeElements();
|
|
481
|
-
const [
|
|
547
|
+
const [loadState, setLoadState] = useState2("loading");
|
|
482
548
|
const [submitting, setSubmitting] = useState2(false);
|
|
483
549
|
const paypalResumeAttempted = useRef2(false);
|
|
550
|
+
const beforeClickRef = useRef2(null);
|
|
484
551
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
485
552
|
useEffect3(() => {
|
|
486
553
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
@@ -529,13 +596,50 @@ function PayPalButtonInner({
|
|
|
529
596
|
}
|
|
530
597
|
})();
|
|
531
598
|
}, [stripe, onTokenizedBody, onErrorChange, onDecline]);
|
|
532
|
-
const
|
|
599
|
+
const handlePayPalClick = useCallback(async (event) => {
|
|
600
|
+
if (isProcessing || submitting) {
|
|
601
|
+
event.reject();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("paypal", { deferInlineSessionPatch: true }) : { proceed: true };
|
|
605
|
+
if (!beforeClick.proceed) {
|
|
606
|
+
beforeClickRef.current = null;
|
|
607
|
+
event.reject();
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
beforeClickRef.current = {
|
|
611
|
+
accountPatch: beforeClick.accountPatch,
|
|
612
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch
|
|
613
|
+
};
|
|
614
|
+
event.resolve();
|
|
615
|
+
}, [isProcessing, runBeforeButtonClick, submitting]);
|
|
616
|
+
const handlePayPalConfirm = useCallback(async (event) => {
|
|
533
617
|
if (!stripe || !elements) return;
|
|
618
|
+
let prepared = beforeClickRef.current;
|
|
619
|
+
beforeClickRef.current = null;
|
|
620
|
+
if (!prepared && runBeforeButtonClick) {
|
|
621
|
+
const beforeClick = await runBeforeButtonClick("paypal");
|
|
622
|
+
if (!beforeClick.proceed) {
|
|
623
|
+
event.paymentFailed({ reason: "fail", message: "PayPal checkout was cancelled." });
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
prepared = {
|
|
627
|
+
accountPatch: beforeClick.accountPatch,
|
|
628
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
|
|
632
|
+
if (patchResult.error) {
|
|
633
|
+
event.paymentFailed({ reason: "fail", message: patchResult.error.message });
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const effectiveSessionId = patchResult.sessionId ?? sessionId;
|
|
637
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
534
638
|
onButtonClick?.("paypal");
|
|
535
639
|
try {
|
|
536
640
|
setSubmitting(true);
|
|
537
641
|
onErrorChange?.(null);
|
|
538
|
-
if (!
|
|
642
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
539
643
|
throw new Error("Missing sessionId or email for PayPal payment");
|
|
540
644
|
}
|
|
541
645
|
const createPM = stripe.createPaymentMethod;
|
|
@@ -547,8 +651,8 @@ function PayPalButtonInner({
|
|
|
547
651
|
method: "POST",
|
|
548
652
|
headers: { "Content-Type": "application/json" },
|
|
549
653
|
body: JSON.stringify({
|
|
550
|
-
sessionId,
|
|
551
|
-
email,
|
|
654
|
+
sessionId: effectiveSessionId,
|
|
655
|
+
email: effectiveEmail,
|
|
552
656
|
paymentMethodType: paymentMethod?.id ?? "paypal",
|
|
553
657
|
isPaypal: "true"
|
|
554
658
|
})
|
|
@@ -582,22 +686,26 @@ function PayPalButtonInner({
|
|
|
582
686
|
type: "card",
|
|
583
687
|
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
584
688
|
isPaypal: true
|
|
689
|
+
}, {
|
|
690
|
+
accountPatch: prepared?.accountPatch,
|
|
691
|
+
sessionId: effectiveSessionId
|
|
585
692
|
});
|
|
586
693
|
} catch (err) {
|
|
587
694
|
onErrorChange?.(err instanceof Error ? err.message : "PayPal payment failed. Please try again.");
|
|
588
695
|
} finally {
|
|
589
696
|
setSubmitting(false);
|
|
590
697
|
}
|
|
591
|
-
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
|
|
698
|
+
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
|
|
592
699
|
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
593
|
-
/* @__PURE__ */ jsx4("
|
|
700
|
+
/* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ jsx4(
|
|
594
701
|
ExpressCheckoutElement,
|
|
595
702
|
{
|
|
596
|
-
onReady: () =>
|
|
597
|
-
onLoadError: () =>
|
|
598
|
-
|
|
703
|
+
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
704
|
+
onLoadError: () => setLoadState("unavailable"),
|
|
705
|
+
onClick: handlePayPalClick,
|
|
599
706
|
onConfirm: handlePayPalConfirm,
|
|
600
707
|
onCancel: () => {
|
|
708
|
+
beforeClickRef.current = null;
|
|
601
709
|
onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
602
710
|
},
|
|
603
711
|
options: {
|
|
@@ -623,18 +731,43 @@ function WalletButtonInner({
|
|
|
623
731
|
onTokenizedBody,
|
|
624
732
|
onErrorChange,
|
|
625
733
|
onButtonClick,
|
|
626
|
-
onDecline
|
|
734
|
+
onDecline,
|
|
735
|
+
runBeforeButtonClick
|
|
627
736
|
}) {
|
|
628
737
|
const stripe = useStripeRaw();
|
|
629
738
|
const elements = useStripeElements();
|
|
630
|
-
const [
|
|
739
|
+
const [loadState, setLoadState] = useState2("loading");
|
|
631
740
|
const [submitting, setSubmitting] = useState2(false);
|
|
632
741
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
633
742
|
const lastWalletMethodRef = useRef2("card");
|
|
743
|
+
const beforeClickRef = useRef2(null);
|
|
634
744
|
const handleWalletConfirm = useCallback(
|
|
635
|
-
async (
|
|
745
|
+
async (event) => {
|
|
636
746
|
if (!stripe || !elements) return;
|
|
637
|
-
const walletType =
|
|
747
|
+
const walletType = event.expressPaymentType;
|
|
748
|
+
let prepared = beforeClickRef.current;
|
|
749
|
+
beforeClickRef.current = null;
|
|
750
|
+
if (!prepared && runBeforeButtonClick) {
|
|
751
|
+
const beforeClick = await runBeforeButtonClick(
|
|
752
|
+
walletType === "apple_pay" ? "apple_pay" : "google_pay"
|
|
753
|
+
);
|
|
754
|
+
if (!beforeClick.proceed) {
|
|
755
|
+
event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
prepared = {
|
|
759
|
+
accountPatch: beforeClick.accountPatch,
|
|
760
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
|
|
764
|
+
if (patchResult.error) {
|
|
765
|
+
event.paymentFailed({ reason: "fail", message: patchResult.error.message });
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
769
|
+
const effectiveSessionId = patchResult.sessionId ?? sessionId;
|
|
770
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
638
771
|
onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
|
|
639
772
|
try {
|
|
640
773
|
setSubmitting(true);
|
|
@@ -649,15 +782,15 @@ function WalletButtonInner({
|
|
|
649
782
|
onErrorChange?.(pmError?.message ?? "Failed to create payment method.");
|
|
650
783
|
return;
|
|
651
784
|
}
|
|
652
|
-
if (!
|
|
785
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
653
786
|
throw new Error("Missing sessionId or email for wallet payment");
|
|
654
787
|
}
|
|
655
788
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
656
789
|
method: "POST",
|
|
657
790
|
headers: { "Content-Type": "application/json" },
|
|
658
791
|
body: JSON.stringify({
|
|
659
|
-
sessionId,
|
|
660
|
-
email,
|
|
792
|
+
sessionId: effectiveSessionId,
|
|
793
|
+
email: effectiveEmail,
|
|
661
794
|
paymentMethodType: paymentMethod.id,
|
|
662
795
|
isPaypal: false
|
|
663
796
|
})
|
|
@@ -671,7 +804,6 @@ function WalletButtonInner({
|
|
|
671
804
|
{ payment_method: paymentMethod.id }
|
|
672
805
|
);
|
|
673
806
|
if (confirmError) {
|
|
674
|
-
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
675
807
|
const message = confirmError.message ?? "Wallet payment failed.";
|
|
676
808
|
onErrorChange?.(message);
|
|
677
809
|
onDecline?.(buildDeclineEvent(method, message, {
|
|
@@ -683,6 +815,9 @@ function WalletButtonInner({
|
|
|
683
815
|
id: paymentMethod.id,
|
|
684
816
|
type: "card",
|
|
685
817
|
threeDSecureActionResultTokenId: paymentIntent?.id
|
|
818
|
+
}, {
|
|
819
|
+
accountPatch: prepared?.accountPatch,
|
|
820
|
+
sessionId: effectiveSessionId
|
|
686
821
|
});
|
|
687
822
|
} catch (err) {
|
|
688
823
|
onErrorChange?.(err instanceof Error ? err.message : "Wallet payment failed. Please try again.");
|
|
@@ -690,21 +825,31 @@ function WalletButtonInner({
|
|
|
690
825
|
setSubmitting(false);
|
|
691
826
|
}
|
|
692
827
|
},
|
|
693
|
-
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
|
|
828
|
+
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
|
|
694
829
|
);
|
|
695
830
|
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
696
|
-
/* @__PURE__ */ jsx4("
|
|
831
|
+
/* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ jsx4(
|
|
697
832
|
ExpressCheckoutElement,
|
|
698
833
|
{
|
|
699
|
-
onReady: () =>
|
|
700
|
-
onLoadError: () =>
|
|
701
|
-
|
|
702
|
-
onClick: (event) => {
|
|
834
|
+
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
|
|
835
|
+
onLoadError: () => setLoadState("unavailable"),
|
|
836
|
+
onClick: async (event) => {
|
|
703
837
|
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
838
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current, { deferInlineSessionPatch: true }) : { proceed: true };
|
|
839
|
+
if (!beforeClick.proceed) {
|
|
840
|
+
beforeClickRef.current = null;
|
|
841
|
+
event.reject();
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
beforeClickRef.current = {
|
|
845
|
+
accountPatch: beforeClick.accountPatch,
|
|
846
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch
|
|
847
|
+
};
|
|
704
848
|
event.resolve();
|
|
705
849
|
},
|
|
706
850
|
onConfirm: handleWalletConfirm,
|
|
707
851
|
onCancel: () => {
|
|
852
|
+
beforeClickRef.current = null;
|
|
708
853
|
onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
|
|
709
854
|
},
|
|
710
855
|
options: {
|
|
@@ -742,6 +887,7 @@ function SplitCardFormInner({
|
|
|
742
887
|
isProcessing: externalProcessing,
|
|
743
888
|
error: externalError,
|
|
744
889
|
onErrorChange,
|
|
890
|
+
onFullNameChange,
|
|
745
891
|
onFirstNameChange,
|
|
746
892
|
onLastNameChange,
|
|
747
893
|
showPayPal = true,
|
|
@@ -860,59 +1006,96 @@ function SplitCardFormInner({
|
|
|
860
1006
|
const showWallets = showApplePay || showGooglePay;
|
|
861
1007
|
const handleNameChange = useCallback((value) => {
|
|
862
1008
|
setFullName(value);
|
|
1009
|
+
onFullNameChange?.(value);
|
|
863
1010
|
const parts = value.trim().split(/\s+/);
|
|
864
1011
|
onFirstNameChange?.(parts[0] ?? "");
|
|
865
1012
|
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
866
|
-
}, [onFirstNameChange, onLastNameChange]);
|
|
867
|
-
const
|
|
868
|
-
|
|
1013
|
+
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
1014
|
+
const applyInlineSessionPatch = useCallback(
|
|
1015
|
+
(patch, method) => {
|
|
1016
|
+
if (!checkout.applyInlineSessionPatch) {
|
|
1017
|
+
return Promise.resolve({ error: null, sessionId });
|
|
1018
|
+
}
|
|
1019
|
+
return checkout.applyInlineSessionPatch(patch).then((result) => ({
|
|
1020
|
+
error: null,
|
|
1021
|
+
sessionId: result.sessionId || sessionId
|
|
1022
|
+
})).catch((err) => {
|
|
1023
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
1024
|
+
updateError(floPayErr.message);
|
|
1025
|
+
onError?.(floPayErr);
|
|
1026
|
+
return { error: floPayErr, sessionId };
|
|
1027
|
+
});
|
|
1028
|
+
},
|
|
1029
|
+
[checkout.applyInlineSessionPatch, onError, sessionId, updateError]
|
|
1030
|
+
);
|
|
1031
|
+
const runBeforeButtonClick = useCallback(async (method, options) => {
|
|
1032
|
+
if (!onBeforeButtonClick) return { proceed: true };
|
|
869
1033
|
try {
|
|
870
1034
|
const result = await onBeforeButtonClick({
|
|
871
|
-
method
|
|
872
|
-
sessionId: sessionId || void 0
|
|
1035
|
+
method,
|
|
1036
|
+
sessionId: sessionId || void 0,
|
|
1037
|
+
createSession: checkout.inlineSessionDraft
|
|
873
1038
|
});
|
|
874
1039
|
if (result === false) {
|
|
875
|
-
return false;
|
|
1040
|
+
return { proceed: false };
|
|
876
1041
|
}
|
|
877
1042
|
if (result && typeof result === "object") {
|
|
878
|
-
await checkout.applyInlineSessionPatch?.(result);
|
|
879
1043
|
if (result.account) {
|
|
880
1044
|
setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
|
|
881
1045
|
}
|
|
1046
|
+
const pendingInlinePatch = applyInlineSessionPatch(result, method);
|
|
1047
|
+
if (options?.deferInlineSessionPatch) {
|
|
1048
|
+
return {
|
|
1049
|
+
proceed: true,
|
|
1050
|
+
accountPatch: result.account,
|
|
1051
|
+
pendingInlinePatch
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
const patchResult = await pendingInlinePatch;
|
|
1055
|
+
if (patchResult.error) {
|
|
1056
|
+
return {
|
|
1057
|
+
proceed: false,
|
|
1058
|
+
accountPatch: result.account
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
proceed: true,
|
|
1063
|
+
accountPatch: result.account,
|
|
1064
|
+
sessionId: patchResult.sessionId
|
|
1065
|
+
};
|
|
882
1066
|
}
|
|
883
|
-
return true;
|
|
1067
|
+
return { proceed: true };
|
|
884
1068
|
} catch (err) {
|
|
885
|
-
const floPayErr =
|
|
886
|
-
err instanceof Error ? err.message : "Card before-click hook failed.",
|
|
887
|
-
"validation_error"
|
|
888
|
-
);
|
|
1069
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
889
1070
|
updateError(floPayErr.message);
|
|
890
1071
|
onError?.(floPayErr);
|
|
891
|
-
return false;
|
|
1072
|
+
return { proceed: false };
|
|
892
1073
|
}
|
|
893
|
-
}, [checkout.
|
|
1074
|
+
}, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
|
|
894
1075
|
const processPaymentInternal = useCallback(
|
|
895
|
-
async (tokenizedBody) => {
|
|
1076
|
+
async (tokenizedBody, overrides) => {
|
|
896
1077
|
if (processingRef.current) return;
|
|
897
1078
|
processingRef.current = true;
|
|
898
1079
|
setProcessing(true);
|
|
899
1080
|
setOverlayStatus("processing");
|
|
900
1081
|
updateError(null);
|
|
1082
|
+
const effectiveSessionId = overrides?.sessionId ?? sessionId;
|
|
1083
|
+
const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
|
|
901
1084
|
try {
|
|
902
1085
|
const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
|
|
903
1086
|
method: "POST",
|
|
904
1087
|
headers: {
|
|
905
1088
|
"Content-Type": "application/json",
|
|
906
|
-
"x-user-id":
|
|
1089
|
+
"x-user-id": effectiveAccount.userId ?? ""
|
|
907
1090
|
},
|
|
908
1091
|
body: JSON.stringify({
|
|
909
|
-
sessionId,
|
|
1092
|
+
sessionId: effectiveSessionId,
|
|
910
1093
|
tokenizedData: tokenizedBody,
|
|
911
1094
|
accountData: {
|
|
912
|
-
userId:
|
|
913
|
-
email:
|
|
914
|
-
firstName:
|
|
915
|
-
lastName:
|
|
1095
|
+
userId: effectiveAccount.userId ?? "",
|
|
1096
|
+
email: effectiveAccount.email ?? "",
|
|
1097
|
+
firstName: effectiveAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
|
|
1098
|
+
lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
916
1099
|
...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
|
|
917
1100
|
},
|
|
918
1101
|
chv
|
|
@@ -1021,11 +1204,11 @@ function SplitCardFormInner({
|
|
|
1021
1204
|
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
|
|
1022
1205
|
);
|
|
1023
1206
|
const dispatchTokenizedBody = useCallback(
|
|
1024
|
-
(tokenizedBody) => {
|
|
1207
|
+
(tokenizedBody, overrides) => {
|
|
1025
1208
|
if (onTokenizedBody) {
|
|
1026
1209
|
onTokenizedBody(tokenizedBody);
|
|
1027
1210
|
} else {
|
|
1028
|
-
processPaymentInternal(tokenizedBody);
|
|
1211
|
+
processPaymentInternal(tokenizedBody, overrides);
|
|
1029
1212
|
}
|
|
1030
1213
|
},
|
|
1031
1214
|
[onTokenizedBody, processPaymentInternal]
|
|
@@ -1452,6 +1635,7 @@ function SplitCardFormInner({
|
|
|
1452
1635
|
if (layout === "buttons") {
|
|
1453
1636
|
const isButtonsView = viewState === "buttons" || viewState === "expanding";
|
|
1454
1637
|
const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
|
|
1638
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
1455
1639
|
const buttonsAnim = viewState === "expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
|
|
1456
1640
|
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;
|
|
1457
1641
|
return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
@@ -1477,9 +1661,10 @@ function SplitCardFormInner({
|
|
|
1477
1661
|
onErrorChange: updateError,
|
|
1478
1662
|
isProcessing: isSubmitting,
|
|
1479
1663
|
onButtonClick,
|
|
1480
|
-
onDecline
|
|
1664
|
+
onDecline,
|
|
1665
|
+
runBeforeButtonClick
|
|
1481
1666
|
}
|
|
1482
|
-
) }) : showPayPal ? /* @__PURE__ */ jsx4("div", { style: { height:
|
|
1667
|
+
) }) : showPayPal ? /* @__PURE__ */ jsx4("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
1483
1668
|
showWallets && stripeInstance ? /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx4(
|
|
1484
1669
|
WalletButtonInner,
|
|
1485
1670
|
{
|
|
@@ -1491,24 +1676,25 @@ function SplitCardFormInner({
|
|
|
1491
1676
|
onTokenizedBody: dispatchTokenizedBody,
|
|
1492
1677
|
onErrorChange: updateError,
|
|
1493
1678
|
onButtonClick,
|
|
1494
|
-
onDecline
|
|
1679
|
+
onDecline,
|
|
1680
|
+
runBeforeButtonClick
|
|
1495
1681
|
}
|
|
1496
|
-
) }) : showWallets ? /* @__PURE__ */ jsx4("div", { style: { height:
|
|
1682
|
+
) }) : showWallets ? /* @__PURE__ */ jsx4("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
1497
1683
|
/* @__PURE__ */ jsx4(
|
|
1498
1684
|
"button",
|
|
1499
1685
|
{
|
|
1500
1686
|
type: "button",
|
|
1501
1687
|
onClick: async () => {
|
|
1502
1688
|
if (isSubmitting) return;
|
|
1503
|
-
const
|
|
1504
|
-
if (!
|
|
1689
|
+
const beforeClick = await runBeforeButtonClick("card");
|
|
1690
|
+
if (!beforeClick.proceed) return;
|
|
1505
1691
|
onButtonClick?.("card");
|
|
1506
1692
|
expandToCard();
|
|
1507
1693
|
},
|
|
1508
1694
|
disabled: isSubmitting,
|
|
1509
1695
|
style: {
|
|
1510
1696
|
width: "100%",
|
|
1511
|
-
|
|
1697
|
+
...cardButtonSizing,
|
|
1512
1698
|
backgroundColor: "white",
|
|
1513
1699
|
color: "#262833",
|
|
1514
1700
|
border: "1px solid #d1d5db",
|
|
@@ -1607,6 +1793,7 @@ function SplitCardFormInner({
|
|
|
1607
1793
|
|
|
1608
1794
|
// src/flopay-checkout.tsx
|
|
1609
1795
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1796
|
+
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
1610
1797
|
function hasInlineSessionPatchData(patch) {
|
|
1611
1798
|
if (!patch) return false;
|
|
1612
1799
|
return Boolean(
|
|
@@ -1625,6 +1812,9 @@ function FloPayCheckout({
|
|
|
1625
1812
|
onComplete,
|
|
1626
1813
|
onError,
|
|
1627
1814
|
onDecline,
|
|
1815
|
+
onFullNameChange,
|
|
1816
|
+
onCountryChange,
|
|
1817
|
+
onZipChange,
|
|
1628
1818
|
showPayPal = true,
|
|
1629
1819
|
showApplePay = true,
|
|
1630
1820
|
showGooglePay = true,
|
|
@@ -1910,16 +2100,27 @@ function FloPayCheckout({
|
|
|
1910
2100
|
[fallbackPublishableKey, locale, resolvedBillingUrl]
|
|
1911
2101
|
);
|
|
1912
2102
|
const handleInlineSessionPatch = useCallback2(async (patch) => {
|
|
1913
|
-
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending)
|
|
2103
|
+
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
|
|
2104
|
+
return {
|
|
2105
|
+
sessionId: resolvedSessionId,
|
|
2106
|
+
session
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
1914
2109
|
setCardBootstrapPending(true);
|
|
1915
2110
|
try {
|
|
1916
|
-
await bootstrapInlineSession(patch);
|
|
2111
|
+
const resolved = await bootstrapInlineSession(patch);
|
|
2112
|
+
return {
|
|
2113
|
+
sessionId: resolved.sid,
|
|
2114
|
+
session: resolved.result.data.session ?? null
|
|
2115
|
+
};
|
|
1917
2116
|
} finally {
|
|
1918
2117
|
setCardBootstrapPending(false);
|
|
1919
2118
|
}
|
|
1920
2119
|
}, [
|
|
1921
2120
|
bootstrapInlineSession,
|
|
1922
|
-
cardBootstrapPending
|
|
2121
|
+
cardBootstrapPending,
|
|
2122
|
+
resolvedSessionId,
|
|
2123
|
+
session
|
|
1923
2124
|
]);
|
|
1924
2125
|
useEffect4(() => {
|
|
1925
2126
|
let cancelled = false;
|
|
@@ -2072,6 +2273,7 @@ function FloPayCheckout({
|
|
|
2072
2273
|
loading: isLoading,
|
|
2073
2274
|
error: loadError,
|
|
2074
2275
|
checkoutMode: currentMode,
|
|
2276
|
+
inlineSessionDraft: effectiveCreateSession,
|
|
2075
2277
|
applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
|
|
2076
2278
|
inlineSessionPatchProcessing: cardBootstrapPending
|
|
2077
2279
|
}),
|
|
@@ -2080,6 +2282,7 @@ function FloPayCheckout({
|
|
|
2080
2282
|
isLoading,
|
|
2081
2283
|
loadError,
|
|
2082
2284
|
currentMode,
|
|
2285
|
+
effectiveCreateSession,
|
|
2083
2286
|
shouldHandleInlineSessionPatch,
|
|
2084
2287
|
handleInlineSessionPatch,
|
|
2085
2288
|
cardBootstrapPending
|
|
@@ -2096,9 +2299,9 @@ function FloPayCheckout({
|
|
|
2096
2299
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
2097
2300
|
} });
|
|
2098
2301
|
return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2099
|
-
showPayPal && skeletonBar(
|
|
2100
|
-
(showApplePay || showGooglePay) && skeletonBar(
|
|
2101
|
-
skeletonBar(
|
|
2302
|
+
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2303
|
+
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2304
|
+
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2102
2305
|
/* @__PURE__ */ jsx5("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
2103
2306
|
] });
|
|
2104
2307
|
}
|
|
@@ -2223,6 +2426,7 @@ function FloPayCheckout({
|
|
|
2223
2426
|
onComplete,
|
|
2224
2427
|
onError,
|
|
2225
2428
|
onDecline,
|
|
2429
|
+
onFullNameChange,
|
|
2226
2430
|
showPayPal,
|
|
2227
2431
|
showApplePay,
|
|
2228
2432
|
showGooglePay,
|
|
@@ -2237,6 +2441,8 @@ function FloPayCheckout({
|
|
|
2237
2441
|
enableAVS,
|
|
2238
2442
|
avsLayout,
|
|
2239
2443
|
country: session?.customer?.country,
|
|
2444
|
+
onCountryChange,
|
|
2445
|
+
onZipChange,
|
|
2240
2446
|
submitLabel,
|
|
2241
2447
|
className
|
|
2242
2448
|
}
|
|
@@ -2309,6 +2515,7 @@ function InterimButtonsView({
|
|
|
2309
2515
|
background: "#e5e7eb",
|
|
2310
2516
|
animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
|
|
2311
2517
|
} });
|
|
2518
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2312
2519
|
if (showCardForm) {
|
|
2313
2520
|
const inputBorder = bStyles.cardInputBorder ?? "#e5e7eb";
|
|
2314
2521
|
const inputBg = bStyles.cardInputBackground ?? "white";
|
|
@@ -2399,8 +2606,8 @@ function InterimButtonsView({
|
|
|
2399
2606
|
] });
|
|
2400
2607
|
}
|
|
2401
2608
|
return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2402
|
-
showPayPal && skeleton(
|
|
2403
|
-
(showApplePay || showGooglePay) && skeleton(
|
|
2609
|
+
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2610
|
+
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2404
2611
|
/* @__PURE__ */ jsx5(
|
|
2405
2612
|
"button",
|
|
2406
2613
|
{
|
|
@@ -2417,7 +2624,7 @@ function InterimButtonsView({
|
|
|
2417
2624
|
disabled: cardLoading,
|
|
2418
2625
|
style: {
|
|
2419
2626
|
width: "100%",
|
|
2420
|
-
|
|
2627
|
+
...cardButtonSizing,
|
|
2421
2628
|
backgroundColor: "white",
|
|
2422
2629
|
color: "#262833",
|
|
2423
2630
|
border: "1px solid #d1d5db",
|