@flopay/react 0.3.20 → 0.4.1
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 +115 -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 +114 -23
- 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",
|
|
@@ -1863,9 +1897,13 @@ function FloPayCheckout({
|
|
|
1863
1897
|
onSessionCompleted
|
|
1864
1898
|
}) {
|
|
1865
1899
|
const resolvedBillingUrl = (0, import_shared6.resolveBillingApiUrl)(billingApiUrl);
|
|
1900
|
+
const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
|
|
1901
|
+
const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
|
|
1866
1902
|
const [unified, setUnified] = (0, import_react7.useState)(null);
|
|
1867
1903
|
const [flopay, setFloPay] = (0, import_react7.useState)(null);
|
|
1868
1904
|
const flopayRef = (0, import_react7.useRef)(null);
|
|
1905
|
+
const [paypalFlopay, setPaypalFloPay] = (0, import_react7.useState)(null);
|
|
1906
|
+
const paypalFlopayRef = (0, import_react7.useRef)(null);
|
|
1869
1907
|
const [session, setSession] = (0, import_react7.useState)(null);
|
|
1870
1908
|
const [resolvedSessionId, setResolvedSessionId] = (0, import_react7.useState)(sessionIdProp ?? "");
|
|
1871
1909
|
const [isLoading, setIsLoading] = (0, import_react7.useState)(true);
|
|
@@ -1885,6 +1923,14 @@ function FloPayCheckout({
|
|
|
1885
1923
|
onDeclineRef.current = onDecline;
|
|
1886
1924
|
const onSessionCompletedRef = (0, import_react7.useRef)(onSessionCompleted);
|
|
1887
1925
|
onSessionCompletedRef.current = onSessionCompleted;
|
|
1926
|
+
(0, import_react7.useEffect)(() => {
|
|
1927
|
+
console.info("[FloPay] Checkout initialized", {
|
|
1928
|
+
sdk_version: import_shared6.SDK_VERSION,
|
|
1929
|
+
checkout_type: checkoutType,
|
|
1930
|
+
checkout_layout: checkoutLayout,
|
|
1931
|
+
billing_api_url: resolvedBillingUrl
|
|
1932
|
+
});
|
|
1933
|
+
}, [checkoutLayout, checkoutType, resolvedBillingUrl]);
|
|
1888
1934
|
const baseCreateSessionHash = (0, import_react7.useMemo)(
|
|
1889
1935
|
() => createSessionParams ? hashCreateParams(createSessionParams) : "",
|
|
1890
1936
|
[createSessionParams]
|
|
@@ -1983,13 +2029,18 @@ function FloPayCheckout({
|
|
|
1983
2029
|
return false;
|
|
1984
2030
|
}
|
|
1985
2031
|
if (redirectResult.type === "paypal_redirect_required") {
|
|
2032
|
+
const paypalStripe = paypalFlopayRef.current?.getRawProvider();
|
|
2033
|
+
if (!paypalStripe) {
|
|
2034
|
+
setModeError("PayPal is not available.");
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
1986
2037
|
const confirmParams = {
|
|
1987
2038
|
return_url: window.location.href
|
|
1988
2039
|
};
|
|
1989
2040
|
if (redirectResult.paymentMethodId) {
|
|
1990
2041
|
confirmParams["payment_method"] = redirectResult.paymentMethodId;
|
|
1991
2042
|
}
|
|
1992
|
-
const { error } = await
|
|
2043
|
+
const { error } = await paypalStripe.confirmPayment({
|
|
1993
2044
|
clientSecret: redirectResult.threeDSecureToken,
|
|
1994
2045
|
confirmParams,
|
|
1995
2046
|
redirect: "if_required"
|
|
@@ -2098,8 +2149,10 @@ function FloPayCheckout({
|
|
|
2098
2149
|
setResolvedSessionId(sid);
|
|
2099
2150
|
}
|
|
2100
2151
|
let publishableKey;
|
|
2152
|
+
let paypalPublishableKey;
|
|
2101
2153
|
if (realResult.provider === "stripe") {
|
|
2102
2154
|
publishableKey = realResult.data.stripe?.publishableKey;
|
|
2155
|
+
paypalPublishableKey = realResult.data.stripe?.paypalPublishableKey;
|
|
2103
2156
|
}
|
|
2104
2157
|
if (!publishableKey) publishableKey = fallbackPublishableKey;
|
|
2105
2158
|
if (!publishableKey) {
|
|
@@ -2108,12 +2161,30 @@ function FloPayCheckout({
|
|
|
2108
2161
|
"validation_error"
|
|
2109
2162
|
);
|
|
2110
2163
|
}
|
|
2111
|
-
const
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2164
|
+
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2165
|
+
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2166
|
+
(0, import_js.loadFloPay)(publishableKey, {
|
|
2167
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2168
|
+
locale
|
|
2169
|
+
}),
|
|
2170
|
+
needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
|
|
2171
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2172
|
+
locale
|
|
2173
|
+
}).catch((err) => {
|
|
2174
|
+
console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
|
|
2175
|
+
return null;
|
|
2176
|
+
}) : Promise.resolve(null)
|
|
2177
|
+
]);
|
|
2115
2178
|
flopayRef.current = instance;
|
|
2116
2179
|
setFloPay(instance);
|
|
2180
|
+
if (paypalPublishableKey) {
|
|
2181
|
+
const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
|
|
2182
|
+
paypalFlopayRef.current = paypalInstance;
|
|
2183
|
+
setPaypalFloPay(paypalInstance);
|
|
2184
|
+
} else {
|
|
2185
|
+
paypalFlopayRef.current = null;
|
|
2186
|
+
setPaypalFloPay(null);
|
|
2187
|
+
}
|
|
2117
2188
|
setIsLoading(false);
|
|
2118
2189
|
} catch (err) {
|
|
2119
2190
|
if (initializedHashRef.current === cacheKey) {
|
|
@@ -2226,8 +2297,10 @@ function FloPayCheckout({
|
|
|
2226
2297
|
}
|
|
2227
2298
|
async function initStripe(result) {
|
|
2228
2299
|
let publishableKey;
|
|
2300
|
+
let paypalPublishableKey;
|
|
2229
2301
|
if (result.provider === "stripe") {
|
|
2230
2302
|
publishableKey = result.data.stripe?.publishableKey;
|
|
2303
|
+
paypalPublishableKey = result.data.stripe?.paypalPublishableKey;
|
|
2231
2304
|
}
|
|
2232
2305
|
if (!publishableKey) publishableKey = fallbackPublishableKey;
|
|
2233
2306
|
if (!publishableKey) {
|
|
@@ -2236,12 +2309,30 @@ function FloPayCheckout({
|
|
|
2236
2309
|
"validation_error"
|
|
2237
2310
|
);
|
|
2238
2311
|
}
|
|
2239
|
-
const
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2312
|
+
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
2313
|
+
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
2314
|
+
(0, import_js.loadFloPay)(publishableKey, {
|
|
2315
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2316
|
+
locale
|
|
2317
|
+
}),
|
|
2318
|
+
needsSeparatePaypal ? (0, import_js.loadFloPay)(paypalPublishableKey, {
|
|
2319
|
+
billingApiUrl: resolvedBillingUrl,
|
|
2320
|
+
locale
|
|
2321
|
+
}).catch((err) => {
|
|
2322
|
+
console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
|
|
2323
|
+
return null;
|
|
2324
|
+
}) : Promise.resolve(null)
|
|
2325
|
+
]);
|
|
2243
2326
|
flopayRef.current = instance;
|
|
2244
2327
|
setFloPay(instance);
|
|
2328
|
+
if (paypalPublishableKey) {
|
|
2329
|
+
const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
|
|
2330
|
+
paypalFlopayRef.current = paypalInstance;
|
|
2331
|
+
setPaypalFloPay(paypalInstance);
|
|
2332
|
+
} else {
|
|
2333
|
+
paypalFlopayRef.current = null;
|
|
2334
|
+
setPaypalFloPay(null);
|
|
2335
|
+
}
|
|
2245
2336
|
}
|
|
2246
2337
|
init();
|
|
2247
2338
|
return () => {
|
|
@@ -2376,7 +2467,7 @@ function FloPayCheckout({
|
|
|
2376
2467
|
}
|
|
2377
2468
|
if (!flopay || !providerOptions) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
|
|
2378
2469
|
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: [
|
|
2470
|
+
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
2471
|
modeError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2381
2472
|
"div",
|
|
2382
2473
|
{
|
|
@@ -3208,6 +3299,7 @@ function PayPalButton({
|
|
|
3208
3299
|
SplitCardForm,
|
|
3209
3300
|
useCheckout,
|
|
3210
3301
|
useElements,
|
|
3211
|
-
useFloPay
|
|
3302
|
+
useFloPay,
|
|
3303
|
+
usePayPalFloPay
|
|
3212
3304
|
});
|
|
3213
3305
|
//# sourceMappingURL=index.cjs.map
|