@flopay/react 0.3.17 → 0.3.20
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 +8 -4
- package/dist/index.cjs +190 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +190 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ Theme presets: `'default'`, `'minimal'`, `'rounded'`, `'dark'`. Custom styles vi
|
|
|
123
123
|
|
|
124
124
|
#### Button Hooks
|
|
125
125
|
|
|
126
|
-
Use `onButtonClick` to track button interactions, `onDecline` to track declines/cancellations, and `onBeforeButtonClick` to enrich
|
|
126
|
+
Use `onButtonClick` to track button interactions, `onDecline` to track declines/cancellations, and `onBeforeButtonClick` to enrich any buttons-layout payment method before it continues:
|
|
127
127
|
|
|
128
128
|
```tsx
|
|
129
129
|
<FloPayCheckout
|
|
@@ -136,7 +136,11 @@ Use `onButtonClick` to track button interactions, `onDecline` to track declines/
|
|
|
136
136
|
cancelUrl: '/cancel',
|
|
137
137
|
}}
|
|
138
138
|
onBeforeButtonClick={async ({ method, createSession }) => {
|
|
139
|
-
if (method !== 'card')
|
|
139
|
+
if (method !== 'card') {
|
|
140
|
+
return {
|
|
141
|
+
tagsData: { sessionId: `checkout_${method}_clicked` },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
140
144
|
|
|
141
145
|
const email = await openEmailCaptureModal({
|
|
142
146
|
initialEmail: createSession?.account.email ?? '',
|
|
@@ -158,7 +162,7 @@ Use `onButtonClick` to track button interactions, `onDecline` to track declines/
|
|
|
158
162
|
/>
|
|
159
163
|
```
|
|
160
164
|
|
|
161
|
-
`onBeforeButtonClick`
|
|
165
|
+
`onBeforeButtonClick` runs for every payment button in `layout="buttons"`. Branch on `method` if only some flows need extra work. For PayPal, Apple Pay, and Google Pay, keep the hook fast because it runs during the provider button handshake before the wallet sheet or PayPal window opens.
|
|
162
166
|
|
|
163
167
|
#### Inline Session Creation
|
|
164
168
|
|
|
@@ -180,7 +184,7 @@ Skip the backend API route — create the session directly in the component:
|
|
|
180
184
|
|
|
181
185
|
The component POSTs to the billing API, gets the full session back, and renders the form — zero backend code needed.
|
|
182
186
|
|
|
183
|
-
When you use `onBeforeButtonClick
|
|
187
|
+
When you use `onBeforeButtonClick` with `createSession`, any returned `InlineSessionPatch` is merged into the draft session params before the selected buttons-layout flow continues. That lets you add tracking data or update account fields just in time without pre-creating a separate backend session.
|
|
184
188
|
|
|
185
189
|
### Advanced: Manual Provider Setup
|
|
186
190
|
|
package/dist/index.cjs
CHANGED
|
@@ -394,6 +394,25 @@ var FLOPAY_KEYFRAMES = `
|
|
|
394
394
|
100% { opacity: 0; transform: translateX(16px) scale(0.97); }
|
|
395
395
|
}
|
|
396
396
|
`;
|
|
397
|
+
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
|
|
398
|
+
function getButtonMethodLabel(method) {
|
|
399
|
+
switch (method) {
|
|
400
|
+
case "paypal":
|
|
401
|
+
return "PayPal";
|
|
402
|
+
case "apple_pay":
|
|
403
|
+
return "Apple Pay";
|
|
404
|
+
case "google_pay":
|
|
405
|
+
return "Google Pay";
|
|
406
|
+
default:
|
|
407
|
+
return "Card";
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function normalizeBeforeButtonClickError(method, err) {
|
|
411
|
+
return err instanceof import_shared5.FloPayError ? err : new import_shared5.FloPayError(
|
|
412
|
+
err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
|
|
413
|
+
"validation_error"
|
|
414
|
+
);
|
|
415
|
+
}
|
|
397
416
|
function FloPayKeyframes() {
|
|
398
417
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: FLOPAY_KEYFRAMES });
|
|
399
418
|
}
|
|
@@ -564,13 +583,15 @@ function PayPalButtonInner({
|
|
|
564
583
|
onErrorChange,
|
|
565
584
|
isProcessing = false,
|
|
566
585
|
onButtonClick,
|
|
567
|
-
onDecline
|
|
586
|
+
onDecline,
|
|
587
|
+
runBeforeButtonClick
|
|
568
588
|
}) {
|
|
569
589
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
570
590
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
571
591
|
const [loadState, setLoadState] = (0, import_react6.useState)("loading");
|
|
572
592
|
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
573
593
|
const paypalResumeAttempted = (0, import_react6.useRef)(false);
|
|
594
|
+
const beforeClickRef = (0, import_react6.useRef)(null);
|
|
574
595
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
575
596
|
(0, import_react6.useEffect)(() => {
|
|
576
597
|
if (!stripe || paypalResumeAttempted.current) return;
|
|
@@ -619,13 +640,45 @@ function PayPalButtonInner({
|
|
|
619
640
|
}
|
|
620
641
|
})();
|
|
621
642
|
}, [stripe, onTokenizedBody, onErrorChange, onDecline]);
|
|
622
|
-
const
|
|
643
|
+
const handlePayPalClick = (0, import_react6.useCallback)(async (event) => {
|
|
644
|
+
if (isProcessing || submitting) {
|
|
645
|
+
event.reject();
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("paypal") : { proceed: true };
|
|
649
|
+
if (!beforeClick.proceed) {
|
|
650
|
+
beforeClickRef.current = null;
|
|
651
|
+
event.reject();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
beforeClickRef.current = {
|
|
655
|
+
accountPatch: beforeClick.accountPatch,
|
|
656
|
+
sessionId: beforeClick.sessionId
|
|
657
|
+
};
|
|
658
|
+
event.resolve();
|
|
659
|
+
}, [isProcessing, runBeforeButtonClick, submitting]);
|
|
660
|
+
const handlePayPalConfirm = (0, import_react6.useCallback)(async (event) => {
|
|
623
661
|
if (!stripe || !elements) return;
|
|
662
|
+
let prepared = beforeClickRef.current;
|
|
663
|
+
beforeClickRef.current = null;
|
|
664
|
+
if (!prepared && runBeforeButtonClick) {
|
|
665
|
+
const beforeClick = await runBeforeButtonClick("paypal");
|
|
666
|
+
if (!beforeClick.proceed) {
|
|
667
|
+
event.paymentFailed({ reason: "fail", message: "PayPal checkout was cancelled." });
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
prepared = {
|
|
671
|
+
accountPatch: beforeClick.accountPatch,
|
|
672
|
+
sessionId: beforeClick.sessionId
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
676
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
624
677
|
onButtonClick?.("paypal");
|
|
625
678
|
try {
|
|
626
679
|
setSubmitting(true);
|
|
627
680
|
onErrorChange?.(null);
|
|
628
|
-
if (!
|
|
681
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
629
682
|
throw new Error("Missing sessionId or email for PayPal payment");
|
|
630
683
|
}
|
|
631
684
|
const createPM = stripe.createPaymentMethod;
|
|
@@ -637,8 +690,8 @@ function PayPalButtonInner({
|
|
|
637
690
|
method: "POST",
|
|
638
691
|
headers: { "Content-Type": "application/json" },
|
|
639
692
|
body: JSON.stringify({
|
|
640
|
-
sessionId,
|
|
641
|
-
email,
|
|
693
|
+
sessionId: effectiveSessionId,
|
|
694
|
+
email: effectiveEmail,
|
|
642
695
|
paymentMethodType: paymentMethod?.id ?? "paypal",
|
|
643
696
|
isPaypal: "true"
|
|
644
697
|
})
|
|
@@ -672,21 +725,26 @@ function PayPalButtonInner({
|
|
|
672
725
|
type: "card",
|
|
673
726
|
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
674
727
|
isPaypal: true
|
|
728
|
+
}, {
|
|
729
|
+
accountPatch: prepared?.accountPatch,
|
|
730
|
+
sessionId: effectiveSessionId
|
|
675
731
|
});
|
|
676
732
|
} catch (err) {
|
|
677
733
|
onErrorChange?.(err instanceof Error ? err.message : "PayPal payment failed. Please try again.");
|
|
678
734
|
} finally {
|
|
679
735
|
setSubmitting(false);
|
|
680
736
|
}
|
|
681
|
-
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
|
|
737
|
+
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
|
|
682
738
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
683
739
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
684
740
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
685
741
|
{
|
|
686
742
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
687
743
|
onLoadError: () => setLoadState("unavailable"),
|
|
744
|
+
onClick: handlePayPalClick,
|
|
688
745
|
onConfirm: handlePayPalConfirm,
|
|
689
746
|
onCancel: () => {
|
|
747
|
+
beforeClickRef.current = null;
|
|
690
748
|
onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
691
749
|
},
|
|
692
750
|
options: {
|
|
@@ -712,7 +770,8 @@ function WalletButtonInner({
|
|
|
712
770
|
onTokenizedBody,
|
|
713
771
|
onErrorChange,
|
|
714
772
|
onButtonClick,
|
|
715
|
-
onDecline
|
|
773
|
+
onDecline,
|
|
774
|
+
runBeforeButtonClick
|
|
716
775
|
}) {
|
|
717
776
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
718
777
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
@@ -720,10 +779,29 @@ function WalletButtonInner({
|
|
|
720
779
|
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
721
780
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
722
781
|
const lastWalletMethodRef = (0, import_react6.useRef)("card");
|
|
782
|
+
const beforeClickRef = (0, import_react6.useRef)(null);
|
|
723
783
|
const handleWalletConfirm = (0, import_react6.useCallback)(
|
|
724
|
-
async (
|
|
784
|
+
async (event) => {
|
|
725
785
|
if (!stripe || !elements) return;
|
|
726
|
-
const walletType =
|
|
786
|
+
const walletType = event.expressPaymentType;
|
|
787
|
+
let prepared = beforeClickRef.current;
|
|
788
|
+
beforeClickRef.current = null;
|
|
789
|
+
if (!prepared && runBeforeButtonClick) {
|
|
790
|
+
const beforeClick = await runBeforeButtonClick(
|
|
791
|
+
walletType === "apple_pay" ? "apple_pay" : "google_pay"
|
|
792
|
+
);
|
|
793
|
+
if (!beforeClick.proceed) {
|
|
794
|
+
event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
prepared = {
|
|
798
|
+
accountPatch: beforeClick.accountPatch,
|
|
799
|
+
sessionId: beforeClick.sessionId
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
803
|
+
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
804
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
727
805
|
onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
|
|
728
806
|
try {
|
|
729
807
|
setSubmitting(true);
|
|
@@ -738,15 +816,15 @@ function WalletButtonInner({
|
|
|
738
816
|
onErrorChange?.(pmError?.message ?? "Failed to create payment method.");
|
|
739
817
|
return;
|
|
740
818
|
}
|
|
741
|
-
if (!
|
|
819
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
742
820
|
throw new Error("Missing sessionId or email for wallet payment");
|
|
743
821
|
}
|
|
744
822
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
745
823
|
method: "POST",
|
|
746
824
|
headers: { "Content-Type": "application/json" },
|
|
747
825
|
body: JSON.stringify({
|
|
748
|
-
sessionId,
|
|
749
|
-
email,
|
|
826
|
+
sessionId: effectiveSessionId,
|
|
827
|
+
email: effectiveEmail,
|
|
750
828
|
paymentMethodType: paymentMethod.id,
|
|
751
829
|
isPaypal: false
|
|
752
830
|
})
|
|
@@ -760,7 +838,6 @@ function WalletButtonInner({
|
|
|
760
838
|
{ payment_method: paymentMethod.id }
|
|
761
839
|
);
|
|
762
840
|
if (confirmError) {
|
|
763
|
-
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
764
841
|
const message = confirmError.message ?? "Wallet payment failed.";
|
|
765
842
|
onErrorChange?.(message);
|
|
766
843
|
onDecline?.(buildDeclineEvent(method, message, {
|
|
@@ -772,6 +849,9 @@ function WalletButtonInner({
|
|
|
772
849
|
id: paymentMethod.id,
|
|
773
850
|
type: "card",
|
|
774
851
|
threeDSecureActionResultTokenId: paymentIntent?.id
|
|
852
|
+
}, {
|
|
853
|
+
accountPatch: prepared?.accountPatch,
|
|
854
|
+
sessionId: effectiveSessionId
|
|
775
855
|
});
|
|
776
856
|
} catch (err) {
|
|
777
857
|
onErrorChange?.(err instanceof Error ? err.message : "Wallet payment failed. Please try again.");
|
|
@@ -779,7 +859,7 @@ function WalletButtonInner({
|
|
|
779
859
|
setSubmitting(false);
|
|
780
860
|
}
|
|
781
861
|
},
|
|
782
|
-
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
|
|
862
|
+
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
|
|
783
863
|
);
|
|
784
864
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
785
865
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -787,12 +867,23 @@ function WalletButtonInner({
|
|
|
787
867
|
{
|
|
788
868
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
|
|
789
869
|
onLoadError: () => setLoadState("unavailable"),
|
|
790
|
-
onClick: (event) => {
|
|
870
|
+
onClick: async (event) => {
|
|
791
871
|
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
872
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
|
|
873
|
+
if (!beforeClick.proceed) {
|
|
874
|
+
beforeClickRef.current = null;
|
|
875
|
+
event.reject();
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
beforeClickRef.current = {
|
|
879
|
+
accountPatch: beforeClick.accountPatch,
|
|
880
|
+
sessionId: beforeClick.sessionId
|
|
881
|
+
};
|
|
792
882
|
event.resolve();
|
|
793
883
|
},
|
|
794
884
|
onConfirm: handleWalletConfirm,
|
|
795
885
|
onCancel: () => {
|
|
886
|
+
beforeClickRef.current = null;
|
|
796
887
|
onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
|
|
797
888
|
},
|
|
798
889
|
options: {
|
|
@@ -954,55 +1045,83 @@ function SplitCardFormInner({
|
|
|
954
1045
|
onFirstNameChange?.(parts[0] ?? "");
|
|
955
1046
|
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
956
1047
|
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
957
|
-
const
|
|
958
|
-
|
|
1048
|
+
const applyInlineSessionPatch = (0, import_react6.useCallback)(
|
|
1049
|
+
(patch, method) => {
|
|
1050
|
+
if (!checkout.applyInlineSessionPatch) {
|
|
1051
|
+
return Promise.resolve({ error: null, sessionId });
|
|
1052
|
+
}
|
|
1053
|
+
return checkout.applyInlineSessionPatch(patch).then((result) => ({
|
|
1054
|
+
error: null,
|
|
1055
|
+
sessionId: result.sessionId || sessionId
|
|
1056
|
+
})).catch((err) => {
|
|
1057
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
1058
|
+
updateError(floPayErr.message);
|
|
1059
|
+
onError?.(floPayErr);
|
|
1060
|
+
return { error: floPayErr, sessionId };
|
|
1061
|
+
});
|
|
1062
|
+
},
|
|
1063
|
+
[checkout.applyInlineSessionPatch, onError, sessionId, updateError]
|
|
1064
|
+
);
|
|
1065
|
+
const runBeforeButtonClick = (0, import_react6.useCallback)(async (method) => {
|
|
1066
|
+
if (!onBeforeButtonClick) return { proceed: true };
|
|
959
1067
|
try {
|
|
960
1068
|
const result = await onBeforeButtonClick({
|
|
961
|
-
method
|
|
962
|
-
sessionId: sessionId || void 0
|
|
1069
|
+
method,
|
|
1070
|
+
sessionId: sessionId || void 0,
|
|
1071
|
+
createSession: checkout.inlineSessionDraft
|
|
963
1072
|
});
|
|
964
1073
|
if (result === false) {
|
|
965
|
-
return false;
|
|
1074
|
+
return { proceed: false };
|
|
966
1075
|
}
|
|
967
1076
|
if (result && typeof result === "object") {
|
|
968
|
-
await checkout.applyInlineSessionPatch?.(result);
|
|
969
1077
|
if (result.account) {
|
|
970
1078
|
setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
|
|
971
1079
|
}
|
|
1080
|
+
const patchResult = await applyInlineSessionPatch(result, method);
|
|
1081
|
+
if (patchResult.error) {
|
|
1082
|
+
return {
|
|
1083
|
+
proceed: false,
|
|
1084
|
+
accountPatch: result.account
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
return {
|
|
1088
|
+
proceed: true,
|
|
1089
|
+
accountPatch: result.account,
|
|
1090
|
+
sessionId: patchResult.sessionId
|
|
1091
|
+
};
|
|
972
1092
|
}
|
|
973
|
-
return true;
|
|
1093
|
+
return { proceed: true };
|
|
974
1094
|
} catch (err) {
|
|
975
|
-
const floPayErr =
|
|
976
|
-
err instanceof Error ? err.message : "Card before-click hook failed.",
|
|
977
|
-
"validation_error"
|
|
978
|
-
);
|
|
1095
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
979
1096
|
updateError(floPayErr.message);
|
|
980
1097
|
onError?.(floPayErr);
|
|
981
|
-
return false;
|
|
1098
|
+
return { proceed: false };
|
|
982
1099
|
}
|
|
983
|
-
}, [checkout.
|
|
1100
|
+
}, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
|
|
984
1101
|
const processPaymentInternal = (0, import_react6.useCallback)(
|
|
985
|
-
async (tokenizedBody) => {
|
|
1102
|
+
async (tokenizedBody, overrides) => {
|
|
986
1103
|
if (processingRef.current) return;
|
|
987
1104
|
processingRef.current = true;
|
|
988
1105
|
setProcessing(true);
|
|
989
1106
|
setOverlayStatus("processing");
|
|
990
1107
|
updateError(null);
|
|
1108
|
+
const effectiveSessionId = overrides?.sessionId ?? sessionId;
|
|
1109
|
+
const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
|
|
991
1110
|
try {
|
|
992
1111
|
const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
|
|
993
1112
|
method: "POST",
|
|
994
1113
|
headers: {
|
|
995
1114
|
"Content-Type": "application/json",
|
|
996
|
-
"x-user-id":
|
|
1115
|
+
"x-user-id": effectiveAccount.userId ?? ""
|
|
997
1116
|
},
|
|
998
1117
|
body: JSON.stringify({
|
|
999
|
-
sessionId,
|
|
1118
|
+
sessionId: effectiveSessionId,
|
|
1000
1119
|
tokenizedData: tokenizedBody,
|
|
1001
1120
|
accountData: {
|
|
1002
|
-
userId:
|
|
1003
|
-
email:
|
|
1004
|
-
firstName:
|
|
1005
|
-
lastName:
|
|
1121
|
+
userId: effectiveAccount.userId ?? "",
|
|
1122
|
+
email: effectiveAccount.email ?? "",
|
|
1123
|
+
firstName: effectiveAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
|
|
1124
|
+
lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
1006
1125
|
...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
|
|
1007
1126
|
},
|
|
1008
1127
|
chv
|
|
@@ -1111,11 +1230,11 @@ function SplitCardFormInner({
|
|
|
1111
1230
|
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
|
|
1112
1231
|
);
|
|
1113
1232
|
const dispatchTokenizedBody = (0, import_react6.useCallback)(
|
|
1114
|
-
(tokenizedBody) => {
|
|
1233
|
+
(tokenizedBody, overrides) => {
|
|
1115
1234
|
if (onTokenizedBody) {
|
|
1116
1235
|
onTokenizedBody(tokenizedBody);
|
|
1117
1236
|
} else {
|
|
1118
|
-
processPaymentInternal(tokenizedBody);
|
|
1237
|
+
processPaymentInternal(tokenizedBody, overrides);
|
|
1119
1238
|
}
|
|
1120
1239
|
},
|
|
1121
1240
|
[onTokenizedBody, processPaymentInternal]
|
|
@@ -1542,6 +1661,7 @@ function SplitCardFormInner({
|
|
|
1542
1661
|
if (layout === "buttons") {
|
|
1543
1662
|
const isButtonsView = viewState === "buttons" || viewState === "expanding";
|
|
1544
1663
|
const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
|
|
1664
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
1545
1665
|
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;
|
|
1546
1666
|
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;
|
|
1547
1667
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
@@ -1567,9 +1687,10 @@ function SplitCardFormInner({
|
|
|
1567
1687
|
onErrorChange: updateError,
|
|
1568
1688
|
isProcessing: isSubmitting,
|
|
1569
1689
|
onButtonClick,
|
|
1570
|
-
onDecline
|
|
1690
|
+
onDecline,
|
|
1691
|
+
runBeforeButtonClick
|
|
1571
1692
|
}
|
|
1572
|
-
) }) : showPayPal ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height:
|
|
1693
|
+
) }) : showPayPal ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
1573
1694
|
showWallets && stripeInstance ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1574
1695
|
WalletButtonInner,
|
|
1575
1696
|
{
|
|
@@ -1581,24 +1702,25 @@ function SplitCardFormInner({
|
|
|
1581
1702
|
onTokenizedBody: dispatchTokenizedBody,
|
|
1582
1703
|
onErrorChange: updateError,
|
|
1583
1704
|
onButtonClick,
|
|
1584
|
-
onDecline
|
|
1705
|
+
onDecline,
|
|
1706
|
+
runBeforeButtonClick
|
|
1585
1707
|
}
|
|
1586
|
-
) }) : showWallets ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height:
|
|
1708
|
+
) }) : showWallets ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
1587
1709
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1588
1710
|
"button",
|
|
1589
1711
|
{
|
|
1590
1712
|
type: "button",
|
|
1591
1713
|
onClick: async () => {
|
|
1592
1714
|
if (isSubmitting) return;
|
|
1593
|
-
const
|
|
1594
|
-
if (!
|
|
1715
|
+
const beforeClick = await runBeforeButtonClick("card");
|
|
1716
|
+
if (!beforeClick.proceed) return;
|
|
1595
1717
|
onButtonClick?.("card");
|
|
1596
1718
|
expandToCard();
|
|
1597
1719
|
},
|
|
1598
1720
|
disabled: isSubmitting,
|
|
1599
1721
|
style: {
|
|
1600
1722
|
width: "100%",
|
|
1601
|
-
|
|
1723
|
+
...cardButtonSizing,
|
|
1602
1724
|
backgroundColor: "white",
|
|
1603
1725
|
color: "#262833",
|
|
1604
1726
|
border: "1px solid #d1d5db",
|
|
@@ -1697,6 +1819,7 @@ function SplitCardFormInner({
|
|
|
1697
1819
|
|
|
1698
1820
|
// src/flopay-checkout.tsx
|
|
1699
1821
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1822
|
+
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
1700
1823
|
function hasInlineSessionPatchData(patch) {
|
|
1701
1824
|
if (!patch) return false;
|
|
1702
1825
|
return Boolean(
|
|
@@ -2003,16 +2126,27 @@ function FloPayCheckout({
|
|
|
2003
2126
|
[fallbackPublishableKey, locale, resolvedBillingUrl]
|
|
2004
2127
|
);
|
|
2005
2128
|
const handleInlineSessionPatch = (0, import_react7.useCallback)(async (patch) => {
|
|
2006
|
-
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending)
|
|
2129
|
+
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
|
|
2130
|
+
return {
|
|
2131
|
+
sessionId: resolvedSessionId,
|
|
2132
|
+
session
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2007
2135
|
setCardBootstrapPending(true);
|
|
2008
2136
|
try {
|
|
2009
|
-
await bootstrapInlineSession(patch);
|
|
2137
|
+
const resolved = await bootstrapInlineSession(patch);
|
|
2138
|
+
return {
|
|
2139
|
+
sessionId: resolved.sid,
|
|
2140
|
+
session: resolved.result.data.session ?? null
|
|
2141
|
+
};
|
|
2010
2142
|
} finally {
|
|
2011
2143
|
setCardBootstrapPending(false);
|
|
2012
2144
|
}
|
|
2013
2145
|
}, [
|
|
2014
2146
|
bootstrapInlineSession,
|
|
2015
|
-
cardBootstrapPending
|
|
2147
|
+
cardBootstrapPending,
|
|
2148
|
+
resolvedSessionId,
|
|
2149
|
+
session
|
|
2016
2150
|
]);
|
|
2017
2151
|
(0, import_react7.useEffect)(() => {
|
|
2018
2152
|
let cancelled = false;
|
|
@@ -2165,6 +2299,7 @@ function FloPayCheckout({
|
|
|
2165
2299
|
loading: isLoading,
|
|
2166
2300
|
error: loadError,
|
|
2167
2301
|
checkoutMode: currentMode,
|
|
2302
|
+
inlineSessionDraft: effectiveCreateSession,
|
|
2168
2303
|
applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
|
|
2169
2304
|
inlineSessionPatchProcessing: cardBootstrapPending
|
|
2170
2305
|
}),
|
|
@@ -2173,6 +2308,7 @@ function FloPayCheckout({
|
|
|
2173
2308
|
isLoading,
|
|
2174
2309
|
loadError,
|
|
2175
2310
|
currentMode,
|
|
2311
|
+
effectiveCreateSession,
|
|
2176
2312
|
shouldHandleInlineSessionPatch,
|
|
2177
2313
|
handleInlineSessionPatch,
|
|
2178
2314
|
cardBootstrapPending
|
|
@@ -2189,9 +2325,9 @@ function FloPayCheckout({
|
|
|
2189
2325
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
2190
2326
|
} });
|
|
2191
2327
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2192
|
-
showPayPal && skeletonBar(
|
|
2193
|
-
(showApplePay || showGooglePay) && skeletonBar(
|
|
2194
|
-
skeletonBar(
|
|
2328
|
+
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2329
|
+
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2330
|
+
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2195
2331
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
2196
2332
|
] });
|
|
2197
2333
|
}
|
|
@@ -2405,6 +2541,7 @@ function InterimButtonsView({
|
|
|
2405
2541
|
background: "#e5e7eb",
|
|
2406
2542
|
animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
|
|
2407
2543
|
} });
|
|
2544
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2408
2545
|
if (showCardForm) {
|
|
2409
2546
|
const inputBorder = bStyles.cardInputBorder ?? "#e5e7eb";
|
|
2410
2547
|
const inputBg = bStyles.cardInputBackground ?? "white";
|
|
@@ -2495,8 +2632,8 @@ function InterimButtonsView({
|
|
|
2495
2632
|
] });
|
|
2496
2633
|
}
|
|
2497
2634
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2498
|
-
showPayPal && skeleton(
|
|
2499
|
-
(showApplePay || showGooglePay) && skeleton(
|
|
2635
|
+
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2636
|
+
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2500
2637
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2501
2638
|
"button",
|
|
2502
2639
|
{
|
|
@@ -2513,7 +2650,7 @@ function InterimButtonsView({
|
|
|
2513
2650
|
disabled: cardLoading,
|
|
2514
2651
|
style: {
|
|
2515
2652
|
width: "100%",
|
|
2516
|
-
|
|
2653
|
+
...cardButtonSizing,
|
|
2517
2654
|
backgroundColor: "white",
|
|
2518
2655
|
color: "#262833",
|
|
2519
2656
|
border: "1px solid #d1d5db",
|