@flopay/react 0.3.17 → 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 +8 -4
- package/dist/index.cjs +208 -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 +208 -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,50 @@ 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", { deferInlineSessionPatch: true }) : { proceed: true };
|
|
649
|
+
if (!beforeClick.proceed) {
|
|
650
|
+
beforeClickRef.current = null;
|
|
651
|
+
event.reject();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
beforeClickRef.current = {
|
|
655
|
+
accountPatch: beforeClick.accountPatch,
|
|
656
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch
|
|
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
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
|
|
676
|
+
if (patchResult.error) {
|
|
677
|
+
event.paymentFailed({ reason: "fail", message: patchResult.error.message });
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const effectiveSessionId = patchResult.sessionId ?? sessionId;
|
|
681
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
624
682
|
onButtonClick?.("paypal");
|
|
625
683
|
try {
|
|
626
684
|
setSubmitting(true);
|
|
627
685
|
onErrorChange?.(null);
|
|
628
|
-
if (!
|
|
686
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
629
687
|
throw new Error("Missing sessionId or email for PayPal payment");
|
|
630
688
|
}
|
|
631
689
|
const createPM = stripe.createPaymentMethod;
|
|
@@ -637,8 +695,8 @@ function PayPalButtonInner({
|
|
|
637
695
|
method: "POST",
|
|
638
696
|
headers: { "Content-Type": "application/json" },
|
|
639
697
|
body: JSON.stringify({
|
|
640
|
-
sessionId,
|
|
641
|
-
email,
|
|
698
|
+
sessionId: effectiveSessionId,
|
|
699
|
+
email: effectiveEmail,
|
|
642
700
|
paymentMethodType: paymentMethod?.id ?? "paypal",
|
|
643
701
|
isPaypal: "true"
|
|
644
702
|
})
|
|
@@ -672,21 +730,26 @@ function PayPalButtonInner({
|
|
|
672
730
|
type: "card",
|
|
673
731
|
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
674
732
|
isPaypal: true
|
|
733
|
+
}, {
|
|
734
|
+
accountPatch: prepared?.accountPatch,
|
|
735
|
+
sessionId: effectiveSessionId
|
|
675
736
|
});
|
|
676
737
|
} catch (err) {
|
|
677
738
|
onErrorChange?.(err instanceof Error ? err.message : "PayPal payment failed. Please try again.");
|
|
678
739
|
} finally {
|
|
679
740
|
setSubmitting(false);
|
|
680
741
|
}
|
|
681
|
-
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
|
|
742
|
+
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
|
|
682
743
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
683
744
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
684
745
|
import_react_stripe_js.ExpressCheckoutElement,
|
|
685
746
|
{
|
|
686
747
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
687
748
|
onLoadError: () => setLoadState("unavailable"),
|
|
749
|
+
onClick: handlePayPalClick,
|
|
688
750
|
onConfirm: handlePayPalConfirm,
|
|
689
751
|
onCancel: () => {
|
|
752
|
+
beforeClickRef.current = null;
|
|
690
753
|
onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
691
754
|
},
|
|
692
755
|
options: {
|
|
@@ -712,7 +775,8 @@ function WalletButtonInner({
|
|
|
712
775
|
onTokenizedBody,
|
|
713
776
|
onErrorChange,
|
|
714
777
|
onButtonClick,
|
|
715
|
-
onDecline
|
|
778
|
+
onDecline,
|
|
779
|
+
runBeforeButtonClick
|
|
716
780
|
}) {
|
|
717
781
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
718
782
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
@@ -720,10 +784,34 @@ function WalletButtonInner({
|
|
|
720
784
|
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
721
785
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
722
786
|
const lastWalletMethodRef = (0, import_react6.useRef)("card");
|
|
787
|
+
const beforeClickRef = (0, import_react6.useRef)(null);
|
|
723
788
|
const handleWalletConfirm = (0, import_react6.useCallback)(
|
|
724
|
-
async (
|
|
789
|
+
async (event) => {
|
|
725
790
|
if (!stripe || !elements) return;
|
|
726
|
-
const walletType =
|
|
791
|
+
const walletType = event.expressPaymentType;
|
|
792
|
+
let prepared = beforeClickRef.current;
|
|
793
|
+
beforeClickRef.current = null;
|
|
794
|
+
if (!prepared && runBeforeButtonClick) {
|
|
795
|
+
const beforeClick = await runBeforeButtonClick(
|
|
796
|
+
walletType === "apple_pay" ? "apple_pay" : "google_pay"
|
|
797
|
+
);
|
|
798
|
+
if (!beforeClick.proceed) {
|
|
799
|
+
event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
prepared = {
|
|
803
|
+
accountPatch: beforeClick.accountPatch,
|
|
804
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
|
|
808
|
+
if (patchResult.error) {
|
|
809
|
+
event.paymentFailed({ reason: "fail", message: patchResult.error.message });
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
813
|
+
const effectiveSessionId = patchResult.sessionId ?? sessionId;
|
|
814
|
+
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
727
815
|
onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
|
|
728
816
|
try {
|
|
729
817
|
setSubmitting(true);
|
|
@@ -738,15 +826,15 @@ function WalletButtonInner({
|
|
|
738
826
|
onErrorChange?.(pmError?.message ?? "Failed to create payment method.");
|
|
739
827
|
return;
|
|
740
828
|
}
|
|
741
|
-
if (!
|
|
829
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
742
830
|
throw new Error("Missing sessionId or email for wallet payment");
|
|
743
831
|
}
|
|
744
832
|
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
745
833
|
method: "POST",
|
|
746
834
|
headers: { "Content-Type": "application/json" },
|
|
747
835
|
body: JSON.stringify({
|
|
748
|
-
sessionId,
|
|
749
|
-
email,
|
|
836
|
+
sessionId: effectiveSessionId,
|
|
837
|
+
email: effectiveEmail,
|
|
750
838
|
paymentMethodType: paymentMethod.id,
|
|
751
839
|
isPaypal: false
|
|
752
840
|
})
|
|
@@ -760,7 +848,6 @@ function WalletButtonInner({
|
|
|
760
848
|
{ payment_method: paymentMethod.id }
|
|
761
849
|
);
|
|
762
850
|
if (confirmError) {
|
|
763
|
-
const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
764
851
|
const message = confirmError.message ?? "Wallet payment failed.";
|
|
765
852
|
onErrorChange?.(message);
|
|
766
853
|
onDecline?.(buildDeclineEvent(method, message, {
|
|
@@ -772,6 +859,9 @@ function WalletButtonInner({
|
|
|
772
859
|
id: paymentMethod.id,
|
|
773
860
|
type: "card",
|
|
774
861
|
threeDSecureActionResultTokenId: paymentIntent?.id
|
|
862
|
+
}, {
|
|
863
|
+
accountPatch: prepared?.accountPatch,
|
|
864
|
+
sessionId: effectiveSessionId
|
|
775
865
|
});
|
|
776
866
|
} catch (err) {
|
|
777
867
|
onErrorChange?.(err instanceof Error ? err.message : "Wallet payment failed. Please try again.");
|
|
@@ -779,7 +869,7 @@ function WalletButtonInner({
|
|
|
779
869
|
setSubmitting(false);
|
|
780
870
|
}
|
|
781
871
|
},
|
|
782
|
-
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
|
|
872
|
+
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
|
|
783
873
|
);
|
|
784
874
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
785
875
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -787,12 +877,23 @@ function WalletButtonInner({
|
|
|
787
877
|
{
|
|
788
878
|
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
|
|
789
879
|
onLoadError: () => setLoadState("unavailable"),
|
|
790
|
-
onClick: (event) => {
|
|
880
|
+
onClick: async (event) => {
|
|
791
881
|
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
882
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current, { deferInlineSessionPatch: true }) : { proceed: true };
|
|
883
|
+
if (!beforeClick.proceed) {
|
|
884
|
+
beforeClickRef.current = null;
|
|
885
|
+
event.reject();
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
beforeClickRef.current = {
|
|
889
|
+
accountPatch: beforeClick.accountPatch,
|
|
890
|
+
pendingInlinePatch: beforeClick.pendingInlinePatch
|
|
891
|
+
};
|
|
792
892
|
event.resolve();
|
|
793
893
|
},
|
|
794
894
|
onConfirm: handleWalletConfirm,
|
|
795
895
|
onCancel: () => {
|
|
896
|
+
beforeClickRef.current = null;
|
|
796
897
|
onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
|
|
797
898
|
},
|
|
798
899
|
options: {
|
|
@@ -954,55 +1055,91 @@ function SplitCardFormInner({
|
|
|
954
1055
|
onFirstNameChange?.(parts[0] ?? "");
|
|
955
1056
|
onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
|
|
956
1057
|
}, [onFullNameChange, onFirstNameChange, onLastNameChange]);
|
|
957
|
-
const
|
|
958
|
-
|
|
1058
|
+
const applyInlineSessionPatch = (0, import_react6.useCallback)(
|
|
1059
|
+
(patch, method) => {
|
|
1060
|
+
if (!checkout.applyInlineSessionPatch) {
|
|
1061
|
+
return Promise.resolve({ error: null, sessionId });
|
|
1062
|
+
}
|
|
1063
|
+
return checkout.applyInlineSessionPatch(patch).then((result) => ({
|
|
1064
|
+
error: null,
|
|
1065
|
+
sessionId: result.sessionId || sessionId
|
|
1066
|
+
})).catch((err) => {
|
|
1067
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
1068
|
+
updateError(floPayErr.message);
|
|
1069
|
+
onError?.(floPayErr);
|
|
1070
|
+
return { error: floPayErr, sessionId };
|
|
1071
|
+
});
|
|
1072
|
+
},
|
|
1073
|
+
[checkout.applyInlineSessionPatch, onError, sessionId, updateError]
|
|
1074
|
+
);
|
|
1075
|
+
const runBeforeButtonClick = (0, import_react6.useCallback)(async (method, options) => {
|
|
1076
|
+
if (!onBeforeButtonClick) return { proceed: true };
|
|
959
1077
|
try {
|
|
960
1078
|
const result = await onBeforeButtonClick({
|
|
961
|
-
method
|
|
962
|
-
sessionId: sessionId || void 0
|
|
1079
|
+
method,
|
|
1080
|
+
sessionId: sessionId || void 0,
|
|
1081
|
+
createSession: checkout.inlineSessionDraft
|
|
963
1082
|
});
|
|
964
1083
|
if (result === false) {
|
|
965
|
-
return false;
|
|
1084
|
+
return { proceed: false };
|
|
966
1085
|
}
|
|
967
1086
|
if (result && typeof result === "object") {
|
|
968
|
-
await checkout.applyInlineSessionPatch?.(result);
|
|
969
1087
|
if (result.account) {
|
|
970
1088
|
setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
|
|
971
1089
|
}
|
|
1090
|
+
const pendingInlinePatch = applyInlineSessionPatch(result, method);
|
|
1091
|
+
if (options?.deferInlineSessionPatch) {
|
|
1092
|
+
return {
|
|
1093
|
+
proceed: true,
|
|
1094
|
+
accountPatch: result.account,
|
|
1095
|
+
pendingInlinePatch
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
const patchResult = await pendingInlinePatch;
|
|
1099
|
+
if (patchResult.error) {
|
|
1100
|
+
return {
|
|
1101
|
+
proceed: false,
|
|
1102
|
+
accountPatch: result.account
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
return {
|
|
1106
|
+
proceed: true,
|
|
1107
|
+
accountPatch: result.account,
|
|
1108
|
+
sessionId: patchResult.sessionId
|
|
1109
|
+
};
|
|
972
1110
|
}
|
|
973
|
-
return true;
|
|
1111
|
+
return { proceed: true };
|
|
974
1112
|
} catch (err) {
|
|
975
|
-
const floPayErr =
|
|
976
|
-
err instanceof Error ? err.message : "Card before-click hook failed.",
|
|
977
|
-
"validation_error"
|
|
978
|
-
);
|
|
1113
|
+
const floPayErr = normalizeBeforeButtonClickError(method, err);
|
|
979
1114
|
updateError(floPayErr.message);
|
|
980
1115
|
onError?.(floPayErr);
|
|
981
|
-
return false;
|
|
1116
|
+
return { proceed: false };
|
|
982
1117
|
}
|
|
983
|
-
}, [checkout.
|
|
1118
|
+
}, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
|
|
984
1119
|
const processPaymentInternal = (0, import_react6.useCallback)(
|
|
985
|
-
async (tokenizedBody) => {
|
|
1120
|
+
async (tokenizedBody, overrides) => {
|
|
986
1121
|
if (processingRef.current) return;
|
|
987
1122
|
processingRef.current = true;
|
|
988
1123
|
setProcessing(true);
|
|
989
1124
|
setOverlayStatus("processing");
|
|
990
1125
|
updateError(null);
|
|
1126
|
+
const effectiveSessionId = overrides?.sessionId ?? sessionId;
|
|
1127
|
+
const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
|
|
991
1128
|
try {
|
|
992
1129
|
const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
|
|
993
1130
|
method: "POST",
|
|
994
1131
|
headers: {
|
|
995
1132
|
"Content-Type": "application/json",
|
|
996
|
-
"x-user-id":
|
|
1133
|
+
"x-user-id": effectiveAccount.userId ?? ""
|
|
997
1134
|
},
|
|
998
1135
|
body: JSON.stringify({
|
|
999
|
-
sessionId,
|
|
1136
|
+
sessionId: effectiveSessionId,
|
|
1000
1137
|
tokenizedData: tokenizedBody,
|
|
1001
1138
|
accountData: {
|
|
1002
|
-
userId:
|
|
1003
|
-
email:
|
|
1004
|
-
firstName:
|
|
1005
|
-
lastName:
|
|
1139
|
+
userId: effectiveAccount.userId ?? "",
|
|
1140
|
+
email: effectiveAccount.email ?? "",
|
|
1141
|
+
firstName: effectiveAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
|
|
1142
|
+
lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
|
|
1006
1143
|
...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
|
|
1007
1144
|
},
|
|
1008
1145
|
chv
|
|
@@ -1111,11 +1248,11 @@ function SplitCardFormInner({
|
|
|
1111
1248
|
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
|
|
1112
1249
|
);
|
|
1113
1250
|
const dispatchTokenizedBody = (0, import_react6.useCallback)(
|
|
1114
|
-
(tokenizedBody) => {
|
|
1251
|
+
(tokenizedBody, overrides) => {
|
|
1115
1252
|
if (onTokenizedBody) {
|
|
1116
1253
|
onTokenizedBody(tokenizedBody);
|
|
1117
1254
|
} else {
|
|
1118
|
-
processPaymentInternal(tokenizedBody);
|
|
1255
|
+
processPaymentInternal(tokenizedBody, overrides);
|
|
1119
1256
|
}
|
|
1120
1257
|
},
|
|
1121
1258
|
[onTokenizedBody, processPaymentInternal]
|
|
@@ -1542,6 +1679,7 @@ function SplitCardFormInner({
|
|
|
1542
1679
|
if (layout === "buttons") {
|
|
1543
1680
|
const isButtonsView = viewState === "buttons" || viewState === "expanding";
|
|
1544
1681
|
const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
|
|
1682
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
1545
1683
|
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
1684
|
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
1685
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
@@ -1567,9 +1705,10 @@ function SplitCardFormInner({
|
|
|
1567
1705
|
onErrorChange: updateError,
|
|
1568
1706
|
isProcessing: isSubmitting,
|
|
1569
1707
|
onButtonClick,
|
|
1570
|
-
onDecline
|
|
1708
|
+
onDecline,
|
|
1709
|
+
runBeforeButtonClick
|
|
1571
1710
|
}
|
|
1572
|
-
) }) : showPayPal ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height:
|
|
1711
|
+
) }) : 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
1712
|
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
1713
|
WalletButtonInner,
|
|
1575
1714
|
{
|
|
@@ -1581,24 +1720,25 @@ function SplitCardFormInner({
|
|
|
1581
1720
|
onTokenizedBody: dispatchTokenizedBody,
|
|
1582
1721
|
onErrorChange: updateError,
|
|
1583
1722
|
onButtonClick,
|
|
1584
|
-
onDecline
|
|
1723
|
+
onDecline,
|
|
1724
|
+
runBeforeButtonClick
|
|
1585
1725
|
}
|
|
1586
|
-
) }) : showWallets ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { height:
|
|
1726
|
+
) }) : 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
1727
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1588
1728
|
"button",
|
|
1589
1729
|
{
|
|
1590
1730
|
type: "button",
|
|
1591
1731
|
onClick: async () => {
|
|
1592
1732
|
if (isSubmitting) return;
|
|
1593
|
-
const
|
|
1594
|
-
if (!
|
|
1733
|
+
const beforeClick = await runBeforeButtonClick("card");
|
|
1734
|
+
if (!beforeClick.proceed) return;
|
|
1595
1735
|
onButtonClick?.("card");
|
|
1596
1736
|
expandToCard();
|
|
1597
1737
|
},
|
|
1598
1738
|
disabled: isSubmitting,
|
|
1599
1739
|
style: {
|
|
1600
1740
|
width: "100%",
|
|
1601
|
-
|
|
1741
|
+
...cardButtonSizing,
|
|
1602
1742
|
backgroundColor: "white",
|
|
1603
1743
|
color: "#262833",
|
|
1604
1744
|
border: "1px solid #d1d5db",
|
|
@@ -1697,6 +1837,7 @@ function SplitCardFormInner({
|
|
|
1697
1837
|
|
|
1698
1838
|
// src/flopay-checkout.tsx
|
|
1699
1839
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1840
|
+
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
|
|
1700
1841
|
function hasInlineSessionPatchData(patch) {
|
|
1701
1842
|
if (!patch) return false;
|
|
1702
1843
|
return Boolean(
|
|
@@ -2003,16 +2144,27 @@ function FloPayCheckout({
|
|
|
2003
2144
|
[fallbackPublishableKey, locale, resolvedBillingUrl]
|
|
2004
2145
|
);
|
|
2005
2146
|
const handleInlineSessionPatch = (0, import_react7.useCallback)(async (patch) => {
|
|
2006
|
-
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending)
|
|
2147
|
+
if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
|
|
2148
|
+
return {
|
|
2149
|
+
sessionId: resolvedSessionId,
|
|
2150
|
+
session
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2007
2153
|
setCardBootstrapPending(true);
|
|
2008
2154
|
try {
|
|
2009
|
-
await bootstrapInlineSession(patch);
|
|
2155
|
+
const resolved = await bootstrapInlineSession(patch);
|
|
2156
|
+
return {
|
|
2157
|
+
sessionId: resolved.sid,
|
|
2158
|
+
session: resolved.result.data.session ?? null
|
|
2159
|
+
};
|
|
2010
2160
|
} finally {
|
|
2011
2161
|
setCardBootstrapPending(false);
|
|
2012
2162
|
}
|
|
2013
2163
|
}, [
|
|
2014
2164
|
bootstrapInlineSession,
|
|
2015
|
-
cardBootstrapPending
|
|
2165
|
+
cardBootstrapPending,
|
|
2166
|
+
resolvedSessionId,
|
|
2167
|
+
session
|
|
2016
2168
|
]);
|
|
2017
2169
|
(0, import_react7.useEffect)(() => {
|
|
2018
2170
|
let cancelled = false;
|
|
@@ -2165,6 +2317,7 @@ function FloPayCheckout({
|
|
|
2165
2317
|
loading: isLoading,
|
|
2166
2318
|
error: loadError,
|
|
2167
2319
|
checkoutMode: currentMode,
|
|
2320
|
+
inlineSessionDraft: effectiveCreateSession,
|
|
2168
2321
|
applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
|
|
2169
2322
|
inlineSessionPatchProcessing: cardBootstrapPending
|
|
2170
2323
|
}),
|
|
@@ -2173,6 +2326,7 @@ function FloPayCheckout({
|
|
|
2173
2326
|
isLoading,
|
|
2174
2327
|
loadError,
|
|
2175
2328
|
currentMode,
|
|
2329
|
+
effectiveCreateSession,
|
|
2176
2330
|
shouldHandleInlineSessionPatch,
|
|
2177
2331
|
handleInlineSessionPatch,
|
|
2178
2332
|
cardBootstrapPending
|
|
@@ -2189,9 +2343,9 @@ function FloPayCheckout({
|
|
|
2189
2343
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
2190
2344
|
} });
|
|
2191
2345
|
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(
|
|
2346
|
+
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2347
|
+
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2348
|
+
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2195
2349
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
2196
2350
|
] });
|
|
2197
2351
|
}
|
|
@@ -2405,6 +2559,7 @@ function InterimButtonsView({
|
|
|
2405
2559
|
background: "#e5e7eb",
|
|
2406
2560
|
animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
|
|
2407
2561
|
} });
|
|
2562
|
+
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2408
2563
|
if (showCardForm) {
|
|
2409
2564
|
const inputBorder = bStyles.cardInputBorder ?? "#e5e7eb";
|
|
2410
2565
|
const inputBg = bStyles.cardInputBackground ?? "white";
|
|
@@ -2495,8 +2650,8 @@ function InterimButtonsView({
|
|
|
2495
2650
|
] });
|
|
2496
2651
|
}
|
|
2497
2652
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2498
|
-
showPayPal && skeleton(
|
|
2499
|
-
(showApplePay || showGooglePay) && skeleton(
|
|
2653
|
+
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2654
|
+
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
2500
2655
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2501
2656
|
"button",
|
|
2502
2657
|
{
|
|
@@ -2513,7 +2668,7 @@ function InterimButtonsView({
|
|
|
2513
2668
|
disabled: cardLoading,
|
|
2514
2669
|
style: {
|
|
2515
2670
|
width: "100%",
|
|
2516
|
-
|
|
2671
|
+
...cardButtonSizing,
|
|
2517
2672
|
backgroundColor: "white",
|
|
2518
2673
|
color: "#262833",
|
|
2519
2674
|
border: "1px solid #d1d5db",
|