@flopay/react 0.3.20 → 0.4.0
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 +6 -2
- package/dist/index.cjs +105 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.mjs +103 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -299,9 +299,13 @@ The `SplitCardForm` layout:
|
|
|
299
299
|
|
|
300
300
|
### PayPal Handling
|
|
301
301
|
|
|
302
|
-
PayPal requires its own Stripe Elements instance because it cannot share an Elements group that uses `paymentMethodCreation: 'manual'`.
|
|
302
|
+
PayPal requires its own Stripe Elements instance because it cannot share an Elements group that uses `paymentMethodCreation: 'manual'`. In addition, the billing API may return a dedicated Stripe account for PayPal via `gatewayData.paypalPublishableKey` — when set, every PayPal Stripe operation uses that key. When the field is `null` or missing, PayPal is disabled (the button is not rendered); there is no fallback to the primary `publishableKey`.
|
|
303
303
|
|
|
304
|
-
|
|
304
|
+
The SDK handles this in two ways:
|
|
305
|
+
|
|
306
|
+
- **`SplitCardForm`**: Automatically manages two Elements instances internally. Card/wallet fields use the primary Stripe account with `paymentMethodCreation: 'manual'`. PayPal renders inside a separate `<Elements>` wrapper backed by the dedicated PayPal FloPay instance (exposed via the `usePayPalFloPay()` hook).
|
|
307
|
+
|
|
308
|
+
- **`FloPayProvider`** (manual composition): accepts an optional `paypalFlopay` prop. Load a second `FloPay` instance with the PayPal publishable key yourself, then pass it in alongside the primary instance. `usePayPalFloPay()` exposes it to descendants.
|
|
305
309
|
|
|
306
310
|
- **`PayPalButton`** (standalone): Must be rendered inside its own `FloPayProvider`:
|
|
307
311
|
|
package/dist/index.cjs
CHANGED
|
@@ -43,7 +43,8 @@ __export(index_exports, {
|
|
|
43
43
|
SplitCardForm: () => SplitCardForm,
|
|
44
44
|
useCheckout: () => useCheckout,
|
|
45
45
|
useElements: () => useElements,
|
|
46
|
-
useFloPay: () => useFloPay
|
|
46
|
+
useFloPay: () => useFloPay,
|
|
47
|
+
usePayPalFloPay: () => usePayPalFloPay
|
|
47
48
|
});
|
|
48
49
|
module.exports = __toCommonJS(index_exports);
|
|
49
50
|
|
|
@@ -55,6 +56,7 @@ var import_shared = require("@flopay/shared");
|
|
|
55
56
|
var import_react = require("react");
|
|
56
57
|
var FloPayContext = (0, import_react.createContext)({
|
|
57
58
|
flopay: null,
|
|
59
|
+
paypalFlopay: null,
|
|
58
60
|
elements: null,
|
|
59
61
|
billingApiUrl: ""
|
|
60
62
|
});
|
|
@@ -68,12 +70,16 @@ var CheckoutContext = (0, import_react.createContext)({
|
|
|
68
70
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
69
71
|
function FloPayProvider({
|
|
70
72
|
flopay: floPayProp,
|
|
73
|
+
paypalFlopay: paypalFloPayProp,
|
|
71
74
|
options,
|
|
72
75
|
children
|
|
73
76
|
}) {
|
|
74
77
|
const [flopay, setFloPay] = (0, import_react2.useState)(
|
|
75
78
|
floPayProp instanceof Promise ? null : floPayProp
|
|
76
79
|
);
|
|
80
|
+
const [paypalFlopay, setPaypalFloPay] = (0, import_react2.useState)(
|
|
81
|
+
paypalFloPayProp instanceof Promise || !paypalFloPayProp ? null : paypalFloPayProp
|
|
82
|
+
);
|
|
77
83
|
const [elements, setElements] = (0, import_react2.useState)(null);
|
|
78
84
|
(0, import_react2.useEffect)(() => {
|
|
79
85
|
let cancelled = false;
|
|
@@ -90,6 +96,25 @@ function FloPayProvider({
|
|
|
90
96
|
cancelled = true;
|
|
91
97
|
};
|
|
92
98
|
}, [floPayProp]);
|
|
99
|
+
(0, import_react2.useEffect)(() => {
|
|
100
|
+
let cancelled = false;
|
|
101
|
+
if (!paypalFloPayProp) {
|
|
102
|
+
setPaypalFloPay(null);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (paypalFloPayProp instanceof Promise) {
|
|
106
|
+
paypalFloPayProp.then((instance) => {
|
|
107
|
+
if (!cancelled) {
|
|
108
|
+
setPaypalFloPay(instance);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
setPaypalFloPay(paypalFloPayProp);
|
|
113
|
+
}
|
|
114
|
+
return () => {
|
|
115
|
+
cancelled = true;
|
|
116
|
+
};
|
|
117
|
+
}, [paypalFloPayProp]);
|
|
93
118
|
(0, import_react2.useEffect)(() => {
|
|
94
119
|
if (!flopay) {
|
|
95
120
|
setElements(null);
|
|
@@ -109,8 +134,8 @@ function FloPayProvider({
|
|
|
109
134
|
}, [flopay, options?.appearance, options?.clientSecret, options?.amount, options?.currency]);
|
|
110
135
|
const resolvedBillingApiUrl = (0, import_shared.resolveBillingApiUrl)(options?.billingApiUrl);
|
|
111
136
|
const value = (0, import_react2.useMemo)(
|
|
112
|
-
() => ({ flopay, elements, billingApiUrl: resolvedBillingApiUrl }),
|
|
113
|
-
[flopay, elements, resolvedBillingApiUrl]
|
|
137
|
+
() => ({ flopay, paypalFlopay, elements, billingApiUrl: resolvedBillingApiUrl }),
|
|
138
|
+
[flopay, paypalFlopay, elements, resolvedBillingApiUrl]
|
|
114
139
|
);
|
|
115
140
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FloPayContext.Provider, { value, children });
|
|
116
141
|
}
|
|
@@ -259,6 +284,10 @@ function useFloPay() {
|
|
|
259
284
|
const ctx = (0, import_react5.useContext)(FloPayContext);
|
|
260
285
|
return ctx.flopay;
|
|
261
286
|
}
|
|
287
|
+
function usePayPalFloPay() {
|
|
288
|
+
const ctx = (0, import_react5.useContext)(FloPayContext);
|
|
289
|
+
return ctx.paypalFlopay ?? null;
|
|
290
|
+
}
|
|
262
291
|
function useElements() {
|
|
263
292
|
const ctx = (0, import_react5.useContext)(FloPayContext);
|
|
264
293
|
return ctx.elements;
|
|
@@ -947,6 +976,7 @@ function SplitCardFormInner({
|
|
|
947
976
|
innerRef
|
|
948
977
|
}) {
|
|
949
978
|
const flopay = useFloPay();
|
|
979
|
+
const paypalFlopay = usePayPalFloPay();
|
|
950
980
|
const elements = useElements();
|
|
951
981
|
const checkout = (0, import_react6.useContext)(CheckoutContext);
|
|
952
982
|
const contextBillingUrl = useBillingApiUrl();
|
|
@@ -1010,6 +1040,10 @@ function SplitCardFormInner({
|
|
|
1010
1040
|
if (!flopay) return null;
|
|
1011
1041
|
return flopay.getRawProvider();
|
|
1012
1042
|
}, [flopay]);
|
|
1043
|
+
const paypalStripeInstance = (0, import_react6.useMemo)(() => {
|
|
1044
|
+
if (!paypalFlopay) return null;
|
|
1045
|
+
return paypalFlopay.getRawProvider();
|
|
1046
|
+
}, [paypalFlopay]);
|
|
1013
1047
|
const amountInCents = totalAmount || 100;
|
|
1014
1048
|
const walletOptions = (0, import_react6.useMemo)(() => ({
|
|
1015
1049
|
mode: "payment",
|
|
@@ -1179,9 +1213,9 @@ function SplitCardFormInner({
|
|
|
1179
1213
|
return;
|
|
1180
1214
|
}
|
|
1181
1215
|
try {
|
|
1182
|
-
const
|
|
1183
|
-
if (!
|
|
1184
|
-
updateError("
|
|
1216
|
+
const paypalStripe = paypalFlopay?.getRawProvider();
|
|
1217
|
+
if (!paypalStripe) {
|
|
1218
|
+
updateError("PayPal is not available.");
|
|
1185
1219
|
return;
|
|
1186
1220
|
}
|
|
1187
1221
|
const confirmParams = {
|
|
@@ -1190,7 +1224,7 @@ function SplitCardFormInner({
|
|
|
1190
1224
|
if (savedPmId) {
|
|
1191
1225
|
confirmParams["payment_method"] = savedPmId;
|
|
1192
1226
|
}
|
|
1193
|
-
const { error: confirmError } = await
|
|
1227
|
+
const { error: confirmError } = await paypalStripe.confirmPayment({
|
|
1194
1228
|
clientSecret: secret,
|
|
1195
1229
|
confirmParams,
|
|
1196
1230
|
redirect: "if_required"
|
|
@@ -1227,7 +1261,7 @@ function SplitCardFormInner({
|
|
|
1227
1261
|
processingRef.current = false;
|
|
1228
1262
|
}
|
|
1229
1263
|
},
|
|
1230
|
-
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
|
|
1264
|
+
[baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
|
|
1231
1265
|
);
|
|
1232
1266
|
const dispatchTokenizedBody = (0, import_react6.useCallback)(
|
|
1233
1267
|
(tokenizedBody, overrides) => {
|
|
@@ -1677,7 +1711,7 @@ function SplitCardFormInner({
|
|
|
1677
1711
|
...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
|
|
1678
1712
|
...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
|
|
1679
1713
|
}, children: [
|
|
1680
|
-
showPayPal &&
|
|
1714
|
+
showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1681
1715
|
PayPalButtonInner,
|
|
1682
1716
|
{
|
|
1683
1717
|
sessionId,
|
|
@@ -1690,7 +1724,7 @@ function SplitCardFormInner({
|
|
|
1690
1724
|
onDecline,
|
|
1691
1725
|
runBeforeButtonClick
|
|
1692
1726
|
}
|
|
1693
|
-
) })
|
|
1727
|
+
) }),
|
|
1694
1728
|
showWallets && stripeInstance ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1695
1729
|
WalletButtonInner,
|
|
1696
1730
|
{
|
|
@@ -1789,7 +1823,7 @@ function SplitCardFormInner({
|
|
|
1789
1823
|
onDecline
|
|
1790
1824
|
}
|
|
1791
1825
|
) }),
|
|
1792
|
-
showPayPal &&
|
|
1826
|
+
showPayPal && paypalStripeInstance && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1793
1827
|
PayPalButtonInner,
|
|
1794
1828
|
{
|
|
1795
1829
|
sessionId,
|
|
@@ -1801,7 +1835,7 @@ function SplitCardFormInner({
|
|
|
1801
1835
|
onDecline
|
|
1802
1836
|
}
|
|
1803
1837
|
) }),
|
|
1804
|
-
(showWallets && stripeInstance || showPayPal &&
|
|
1838
|
+
(showWallets && stripeInstance || showPayPal && paypalStripeInstance) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
|
|
1805
1839
|
display: "flex",
|
|
1806
1840
|
alignItems: "center",
|
|
1807
1841
|
gap: "0.75rem",
|
|
@@ -1866,6 +1900,8 @@ function FloPayCheckout({
|
|
|
1866
1900
|
const [unified, setUnified] = (0, import_react7.useState)(null);
|
|
1867
1901
|
const [flopay, setFloPay] = (0, import_react7.useState)(null);
|
|
1868
1902
|
const flopayRef = (0, import_react7.useRef)(null);
|
|
1903
|
+
const [paypalFlopay, setPaypalFloPay] = (0, import_react7.useState)(null);
|
|
1904
|
+
const paypalFlopayRef = (0, import_react7.useRef)(null);
|
|
1869
1905
|
const [session, setSession] = (0, import_react7.useState)(null);
|
|
1870
1906
|
const [resolvedSessionId, setResolvedSessionId] = (0, import_react7.useState)(sessionIdProp ?? "");
|
|
1871
1907
|
const [isLoading, setIsLoading] = (0, import_react7.useState)(true);
|
|
@@ -1983,13 +2019,18 @@ function FloPayCheckout({
|
|
|
1983
2019
|
return false;
|
|
1984
2020
|
}
|
|
1985
2021
|
if (redirectResult.type === "paypal_redirect_required") {
|
|
2022
|
+
const paypalStripe = paypalFlopayRef.current?.getRawProvider();
|
|
2023
|
+
if (!paypalStripe) {
|
|
2024
|
+
setModeError("PayPal is not available.");
|
|
2025
|
+
return false;
|
|
2026
|
+
}
|
|
1986
2027
|
const confirmParams = {
|
|
1987
2028
|
return_url: window.location.href
|
|
1988
2029
|
};
|
|
1989
2030
|
if (redirectResult.paymentMethodId) {
|
|
1990
2031
|
confirmParams["payment_method"] = redirectResult.paymentMethodId;
|
|
1991
2032
|
}
|
|
1992
|
-
const { error } = await
|
|
2033
|
+
const { error } = await paypalStripe.confirmPayment({
|
|
1993
2034
|
clientSecret: redirectResult.threeDSecureToken,
|
|
1994
2035
|
confirmParams,
|
|
1995
2036
|
redirect: "if_required"
|
|
@@ -2098,8 +2139,10 @@ function FloPayCheckout({
|
|
|
2098
2139
|
setResolvedSessionId(sid);
|
|
2099
2140
|
}
|
|
2100
2141
|
let publishableKey;
|
|
2142
|
+
let paypalPublishableKey;
|
|
2101
2143
|
if (realResult.provider === "stripe") {
|
|
2102
2144
|
publishableKey = realResult.data.stripe?.publishableKey;
|
|
2145
|
+
paypalPublishableKey = realResult.data.stripe?.paypalPublishableKey;
|
|
2103
2146
|
}
|
|
2104
2147
|
if (!publishableKey) publishableKey = fallbackPublishableKey;
|
|
2105
2148
|
if (!publishableKey) {
|
|
@@ -2108,12 +2151,30 @@ function FloPayCheckout({
|
|
|
2108
2151
|
"validation_error"
|
|
2109
2152
|
);
|
|
2110
2153
|
}
|
|
2111
|
-
const
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2154
|
+
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2155
|
+
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2156
|
+
(0, import_js.loadFloPay)(publishableKey, {
|
|
2157
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2158
|
+
locale
|
|
2159
|
+
}),
|
|
2160
|
+
needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
|
|
2161
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2162
|
+
locale
|
|
2163
|
+
}).catch((err) => {
|
|
2164
|
+
console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
|
|
2165
|
+
return null;
|
|
2166
|
+
}) : Promise.resolve(null)
|
|
2167
|
+
]);
|
|
2115
2168
|
flopayRef.current = instance;
|
|
2116
2169
|
setFloPay(instance);
|
|
2170
|
+
if (paypalPublishableKey) {
|
|
2171
|
+
const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
|
|
2172
|
+
paypalFlopayRef.current = paypalInstance;
|
|
2173
|
+
setPaypalFloPay(paypalInstance);
|
|
2174
|
+
} else {
|
|
2175
|
+
paypalFlopayRef.current = null;
|
|
2176
|
+
setPaypalFloPay(null);
|
|
2177
|
+
}
|
|
2117
2178
|
setIsLoading(false);
|
|
2118
2179
|
} catch (err) {
|
|
2119
2180
|
if (initializedHashRef.current === cacheKey) {
|
|
@@ -2226,8 +2287,10 @@ function FloPayCheckout({
|
|
|
2226
2287
|
}
|
|
2227
2288
|
async function initStripe(result) {
|
|
2228
2289
|
let publishableKey;
|
|
2290
|
+
let paypalPublishableKey;
|
|
2229
2291
|
if (result.provider === "stripe") {
|
|
2230
2292
|
publishableKey = result.data.stripe?.publishableKey;
|
|
2293
|
+
paypalPublishableKey = result.data.stripe?.paypalPublishableKey;
|
|
2231
2294
|
}
|
|
2232
2295
|
if (!publishableKey) publishableKey = fallbackPublishableKey;
|
|
2233
2296
|
if (!publishableKey) {
|
|
@@ -2236,12 +2299,30 @@ function FloPayCheckout({
|
|
|
2236
2299
|
"validation_error"
|
|
2237
2300
|
);
|
|
2238
2301
|
}
|
|
2239
|
-
const
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2302
|
+
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2303
|
+
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2304
|
+
(0, import_js.loadFloPay)(publishableKey, {
|
|
2305
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2306
|
+
locale
|
|
2307
|
+
}),
|
|
2308
|
+
needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
|
|
2309
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2310
|
+
locale
|
|
2311
|
+
}).catch((err) => {
|
|
2312
|
+
console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
|
|
2313
|
+
return null;
|
|
2314
|
+
}) : Promise.resolve(null)
|
|
2315
|
+
]);
|
|
2243
2316
|
flopayRef.current = instance;
|
|
2244
2317
|
setFloPay(instance);
|
|
2318
|
+
if (paypalPublishableKey) {
|
|
2319
|
+
const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
|
|
2320
|
+
paypalFlopayRef.current = paypalInstance;
|
|
2321
|
+
setPaypalFloPay(paypalInstance);
|
|
2322
|
+
} else {
|
|
2323
|
+
paypalFlopayRef.current = null;
|
|
2324
|
+
setPaypalFloPay(null);
|
|
2325
|
+
}
|
|
2245
2326
|
}
|
|
2246
2327
|
init();
|
|
2247
2328
|
return () => {
|
|
@@ -2376,7 +2457,7 @@ function FloPayCheckout({
|
|
|
2376
2457
|
}
|
|
2377
2458
|
if (!flopay || !providerOptions) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
|
|
2378
2459
|
if (currentMode === "confirm") {
|
|
2379
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayProvider, { flopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, children: [
|
|
2460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, children: [
|
|
2380
2461
|
modeError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2381
2462
|
"div",
|
|
2382
2463
|
{
|
|
@@ -3208,6 +3289,7 @@ function PayPalButton({
|
|
|
3208
3289
|
SplitCardForm,
|
|
3209
3290
|
useCheckout,
|
|
3210
3291
|
useElements,
|
|
3211
|
-
useFloPay
|
|
3292
|
+
useFloPay,
|
|
3293
|
+
usePayPalFloPay
|
|
3212
3294
|
});
|
|
3213
3295
|
//# sourceMappingURL=index.cjs.map
|