@flopay/react 1.1.5 → 1.2.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 +42 -11
- package/dist/index.cjs +1461 -318
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -11
- package/dist/index.d.ts +75 -11
- package/dist/index.mjs +1472 -319
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -234,6 +234,7 @@ var AddressElement = createElementComponent("address", "AddressElement");
|
|
|
234
234
|
// src/split-card-form.tsx
|
|
235
235
|
import {
|
|
236
236
|
ExpressCheckoutElement,
|
|
237
|
+
PaymentElement as PaymentElement2,
|
|
237
238
|
Elements as StripeElements,
|
|
238
239
|
useElements as useStripeElements,
|
|
239
240
|
useStripe as useStripeRaw
|
|
@@ -246,10 +247,19 @@ import {
|
|
|
246
247
|
COUNTRY_OPTIONS,
|
|
247
248
|
resolveAVSConfig,
|
|
248
249
|
isAVSFieldVisible,
|
|
249
|
-
getStateFromPostalCode
|
|
250
|
+
getStateFromPostalCode,
|
|
251
|
+
filterStripeMethodsByCurrency,
|
|
252
|
+
filterStripeMethodsByCountry,
|
|
253
|
+
filterStripeMethodsByAmount,
|
|
254
|
+
getStripeMethodDisplayName,
|
|
255
|
+
hasVendoredStripeMethodLogo,
|
|
256
|
+
needsStripeMethodExplicitConfirm,
|
|
257
|
+
resolveStripeMethodBrandVariant,
|
|
258
|
+
partitionStripeMethods,
|
|
259
|
+
stripeExpressMethodToOptionKey
|
|
250
260
|
} from "@flopay/shared";
|
|
251
261
|
import { PaymentAPI as PaymentAPI2 } from "@flopay/js";
|
|
252
|
-
import { forwardRef, useCallback, useContext as useContext3, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
262
|
+
import React6, { forwardRef, useCallback, useContext as useContext3, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
253
263
|
|
|
254
264
|
// src/hooks.ts
|
|
255
265
|
import { useContext as useContext2 } from "react";
|
|
@@ -1223,9 +1233,11 @@ ${debugLines.join("\n")}`
|
|
|
1223
1233
|
// src/split-card-form.tsx
|
|
1224
1234
|
import { FloPayError as FloPayError3, resolveTheme } from "@flopay/shared";
|
|
1225
1235
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1226
|
-
var
|
|
1236
|
+
var STRIPE_RESUME_KEY = "flopay_stripe_resume";
|
|
1237
|
+
var LEGACY_WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
1227
1238
|
var FLOPAY_KEYFRAMES = `
|
|
1228
1239
|
.paypal-buttons { margin: 0 !important; vertical-align: top !important; }
|
|
1240
|
+
@keyframes flopay-spin { to { transform: rotate(360deg); } }
|
|
1229
1241
|
@keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
1230
1242
|
@keyframes flopay-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
|
|
1231
1243
|
@keyframes flopay-buttons-enter {
|
|
@@ -1246,6 +1258,33 @@ var FLOPAY_KEYFRAMES = `
|
|
|
1246
1258
|
}
|
|
1247
1259
|
`;
|
|
1248
1260
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
|
|
1261
|
+
function derivePrimaryTileStyle(opts) {
|
|
1262
|
+
if (!opts.themeBundle) {
|
|
1263
|
+
return {
|
|
1264
|
+
backgroundColor: "white",
|
|
1265
|
+
color: "#262833",
|
|
1266
|
+
border: "1px solid #d1d5db",
|
|
1267
|
+
borderRadius: "8px",
|
|
1268
|
+
boxShadow: "0 1px 2px rgba(0,0,0,0.04)"
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
const submit = opts.submitButtonStyle ?? {};
|
|
1272
|
+
return {
|
|
1273
|
+
backgroundColor: submit.backgroundColor ?? opts.resolvedPrimaryColor,
|
|
1274
|
+
color: submit.color ?? "white",
|
|
1275
|
+
border: submit.border ?? "none",
|
|
1276
|
+
borderRadius: submit.borderRadius ?? opts.resolvedBorderRadius,
|
|
1277
|
+
boxShadow: submit.boxShadow
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
var BUTTONS_PANEL_HIDDEN_STYLE = {
|
|
1281
|
+
visibility: "hidden",
|
|
1282
|
+
position: "absolute",
|
|
1283
|
+
pointerEvents: "none",
|
|
1284
|
+
width: "100%",
|
|
1285
|
+
height: 0,
|
|
1286
|
+
overflow: "hidden"
|
|
1287
|
+
};
|
|
1249
1288
|
function getButtonMethodLabel(method) {
|
|
1250
1289
|
switch (method) {
|
|
1251
1290
|
case "paypal":
|
|
@@ -1283,6 +1322,7 @@ function resolveExpressCheckoutLoadState(event, methods) {
|
|
|
1283
1322
|
function ExpressCheckoutReadySwap({
|
|
1284
1323
|
state,
|
|
1285
1324
|
placeholderTestId,
|
|
1325
|
+
borderRadius = 8,
|
|
1286
1326
|
children
|
|
1287
1327
|
}) {
|
|
1288
1328
|
if (state === "unavailable" || state === "load_error") return null;
|
|
@@ -1296,7 +1336,7 @@ function ExpressCheckoutReadySwap({
|
|
|
1296
1336
|
position: "absolute",
|
|
1297
1337
|
inset: 0,
|
|
1298
1338
|
height: 44,
|
|
1299
|
-
borderRadius
|
|
1339
|
+
borderRadius,
|
|
1300
1340
|
background: "#e5e7eb",
|
|
1301
1341
|
animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
|
|
1302
1342
|
opacity: state === "ready" ? 0 : 1,
|
|
@@ -1339,7 +1379,8 @@ function PayPalButtonInner({
|
|
|
1339
1379
|
onButtonClick,
|
|
1340
1380
|
onDecline,
|
|
1341
1381
|
runBeforeButtonClick,
|
|
1342
|
-
onLoadStateChange
|
|
1382
|
+
onLoadStateChange,
|
|
1383
|
+
placeholderBorderRadius
|
|
1343
1384
|
}) {
|
|
1344
1385
|
const stripe = useStripeRaw();
|
|
1345
1386
|
const elements = useStripeElements();
|
|
@@ -1509,31 +1550,39 @@ function PayPalButtonInner({
|
|
|
1509
1550
|
}
|
|
1510
1551
|
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
|
|
1511
1552
|
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1512
|
-
/* @__PURE__ */ jsx6(
|
|
1513
|
-
|
|
1553
|
+
/* @__PURE__ */ jsx6(
|
|
1554
|
+
ExpressCheckoutReadySwap,
|
|
1514
1555
|
{
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1556
|
+
state: loadState,
|
|
1557
|
+
placeholderTestId: "flopay-paypal-placeholder",
|
|
1558
|
+
borderRadius: placeholderBorderRadius,
|
|
1559
|
+
children: /* @__PURE__ */ jsx6(
|
|
1560
|
+
ExpressCheckoutElement,
|
|
1561
|
+
{
|
|
1562
|
+
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
1563
|
+
onLoadError: () => setLoadState("load_error"),
|
|
1564
|
+
onClick: handlePayPalClick,
|
|
1565
|
+
onConfirm: handlePayPalConfirm,
|
|
1566
|
+
onCancel: () => {
|
|
1567
|
+
beforeClickRef.current = null;
|
|
1568
|
+
onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
1569
|
+
},
|
|
1570
|
+
options: {
|
|
1571
|
+
buttonType: { paypal: "paypal" },
|
|
1572
|
+
billingAddressRequired: false,
|
|
1573
|
+
phoneNumberRequired: false,
|
|
1574
|
+
shippingAddressRequired: false,
|
|
1575
|
+
paymentMethods: {
|
|
1576
|
+
applePay: "never",
|
|
1577
|
+
googlePay: "never",
|
|
1578
|
+
paypal: "auto",
|
|
1579
|
+
link: "never"
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1533
1582
|
}
|
|
1534
|
-
|
|
1583
|
+
)
|
|
1535
1584
|
}
|
|
1536
|
-
)
|
|
1585
|
+
),
|
|
1537
1586
|
submitting && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: "processing" })
|
|
1538
1587
|
] });
|
|
1539
1588
|
}
|
|
@@ -1541,14 +1590,14 @@ function WalletButtonInner({
|
|
|
1541
1590
|
sessionId,
|
|
1542
1591
|
email,
|
|
1543
1592
|
billingApiUrl,
|
|
1544
|
-
|
|
1545
|
-
showGooglePay = true,
|
|
1593
|
+
expressMethods,
|
|
1546
1594
|
onTokenizedBody,
|
|
1547
1595
|
onErrorChange,
|
|
1548
1596
|
onButtonClick,
|
|
1549
1597
|
onDecline,
|
|
1550
1598
|
runBeforeButtonClick,
|
|
1551
|
-
onLoadStateChange
|
|
1599
|
+
onLoadStateChange,
|
|
1600
|
+
placeholderBorderRadius
|
|
1552
1601
|
}) {
|
|
1553
1602
|
const stripe = useStripeRaw();
|
|
1554
1603
|
const elements = useStripeElements();
|
|
@@ -1566,10 +1615,9 @@ function WalletButtonInner({
|
|
|
1566
1615
|
const walletType = event.expressPaymentType;
|
|
1567
1616
|
let prepared = beforeClickRef.current;
|
|
1568
1617
|
beforeClickRef.current = null;
|
|
1618
|
+
const buttonMethod = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1569
1619
|
if (!prepared && runBeforeButtonClick) {
|
|
1570
|
-
const beforeClick = await runBeforeButtonClick(
|
|
1571
|
-
walletType === "apple_pay" ? "apple_pay" : "google_pay"
|
|
1572
|
-
);
|
|
1620
|
+
const beforeClick = await runBeforeButtonClick(buttonMethod);
|
|
1573
1621
|
if (!beforeClick.proceed) {
|
|
1574
1622
|
event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
|
|
1575
1623
|
return;
|
|
@@ -1579,7 +1627,7 @@ function WalletButtonInner({
|
|
|
1579
1627
|
sessionId: beforeClick.sessionId
|
|
1580
1628
|
};
|
|
1581
1629
|
}
|
|
1582
|
-
const method =
|
|
1630
|
+
const method = buttonMethod;
|
|
1583
1631
|
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
1584
1632
|
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
1585
1633
|
try {
|
|
@@ -1649,52 +1697,654 @@ function WalletButtonInner({
|
|
|
1649
1697
|
},
|
|
1650
1698
|
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
|
|
1651
1699
|
);
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1700
|
+
const expressMethodMap = useMemo3(() => {
|
|
1701
|
+
const allKeys = ["applePay", "googlePay", "paypal", "link", "amazonPay", "klarna"];
|
|
1702
|
+
const alwaysCapable = /* @__PURE__ */ new Set(["applePay", "googlePay"]);
|
|
1703
|
+
const enabledKeys = new Set(expressMethods.map(stripeExpressMethodToOptionKey));
|
|
1704
|
+
const out = {};
|
|
1705
|
+
for (const key of allKeys) {
|
|
1706
|
+
if (!enabledKeys.has(key)) {
|
|
1707
|
+
out[key] = "never";
|
|
1708
|
+
} else {
|
|
1709
|
+
out[key] = alwaysCapable.has(key) ? "always" : "auto";
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return out;
|
|
1713
|
+
}, [expressMethods]);
|
|
1714
|
+
const availableMethodKeys = useMemo3(
|
|
1715
|
+
() => expressMethods.map(stripeExpressMethodToOptionKey),
|
|
1716
|
+
[expressMethods]
|
|
1717
|
+
);
|
|
1718
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1719
|
+
/* @__PURE__ */ jsx6(
|
|
1720
|
+
ExpressCheckoutReadySwap,
|
|
1721
|
+
{
|
|
1722
|
+
state: loadState,
|
|
1723
|
+
placeholderTestId: "flopay-wallet-placeholder",
|
|
1724
|
+
borderRadius: placeholderBorderRadius,
|
|
1725
|
+
children: /* @__PURE__ */ jsx6(
|
|
1726
|
+
ExpressCheckoutElement,
|
|
1727
|
+
{
|
|
1728
|
+
onReady: (event) => {
|
|
1729
|
+
setLoadState(resolveExpressCheckoutLoadState(event, availableMethodKeys));
|
|
1730
|
+
},
|
|
1731
|
+
onLoadError: (_event) => {
|
|
1732
|
+
setLoadState("load_error");
|
|
1733
|
+
},
|
|
1734
|
+
onClick: async (event) => {
|
|
1735
|
+
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1736
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
|
|
1737
|
+
if (!beforeClick.proceed) {
|
|
1738
|
+
beforeClickRef.current = null;
|
|
1739
|
+
event.reject();
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
beforeClickRef.current = {
|
|
1743
|
+
accountPatch: beforeClick.accountPatch,
|
|
1744
|
+
sessionId: beforeClick.sessionId
|
|
1745
|
+
};
|
|
1746
|
+
onButtonClick?.(lastWalletMethodRef.current);
|
|
1747
|
+
event.resolve();
|
|
1748
|
+
},
|
|
1749
|
+
onConfirm: handleWalletConfirm,
|
|
1750
|
+
onCancel: () => {
|
|
1751
|
+
beforeClickRef.current = null;
|
|
1752
|
+
onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
|
|
1753
|
+
},
|
|
1754
|
+
options: {
|
|
1755
|
+
buttonType: { applePay: "plain", googlePay: "plain" },
|
|
1756
|
+
paymentMethods: expressMethodMap,
|
|
1757
|
+
layout: { maxColumns: 1, overflow: "never" }
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
)
|
|
1761
|
+
}
|
|
1762
|
+
),
|
|
1763
|
+
submitting && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: "processing" })
|
|
1764
|
+
] });
|
|
1765
|
+
}
|
|
1766
|
+
function StripeMethodButton({
|
|
1767
|
+
method,
|
|
1768
|
+
themeId,
|
|
1769
|
+
submitting = false,
|
|
1770
|
+
disabled = false,
|
|
1771
|
+
highlighted = false,
|
|
1772
|
+
hasNextStep = false,
|
|
1773
|
+
onClick,
|
|
1774
|
+
backgroundColor,
|
|
1775
|
+
borderColor,
|
|
1776
|
+
textColor,
|
|
1777
|
+
borderRadius,
|
|
1778
|
+
fontFamily
|
|
1779
|
+
}) {
|
|
1780
|
+
const brand = resolveStripeMethodBrandVariant(method, themeId);
|
|
1781
|
+
const resolvedBackground = brand?.backgroundColor ?? backgroundColor ?? "#ffffff";
|
|
1782
|
+
const resolvedBorder = brand?.borderColor ?? borderColor ?? "#d1d5db";
|
|
1783
|
+
const resolvedTextColor = brand?.textColor ?? textColor ?? "#262833";
|
|
1784
|
+
return /* @__PURE__ */ jsx6(
|
|
1785
|
+
"button",
|
|
1786
|
+
{
|
|
1787
|
+
type: "button",
|
|
1788
|
+
"data-testid": `flopay-stripe-method-button-${method}`,
|
|
1789
|
+
"data-method": method,
|
|
1790
|
+
onClick: () => {
|
|
1791
|
+
if (!submitting && !disabled) onClick();
|
|
1792
|
+
},
|
|
1793
|
+
disabled: submitting || disabled,
|
|
1794
|
+
"aria-busy": submitting || void 0,
|
|
1795
|
+
style: {
|
|
1796
|
+
position: "relative",
|
|
1797
|
+
width: "100%",
|
|
1798
|
+
boxSizing: "border-box",
|
|
1799
|
+
height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT,
|
|
1800
|
+
padding: "0 1rem",
|
|
1801
|
+
backgroundColor: resolvedBackground,
|
|
1802
|
+
color: resolvedTextColor,
|
|
1803
|
+
border: `1px solid ${resolvedBorder}`,
|
|
1804
|
+
borderRadius: borderRadius ?? 8,
|
|
1805
|
+
fontSize: "0.95rem",
|
|
1806
|
+
fontWeight: 600,
|
|
1807
|
+
fontFamily,
|
|
1808
|
+
cursor: submitting || disabled ? "not-allowed" : "pointer",
|
|
1809
|
+
opacity: disabled && !submitting ? 0.55 : 1,
|
|
1810
|
+
// Submitting state pulses the whole button background, mirroring
|
|
1811
|
+
// the wallet ECE's `flopay-pulse` skeleton. This keeps the loading
|
|
1812
|
+
// affordance consistent between embedded wallets (Apple Pay,
|
|
1813
|
+
// Google Pay) and these custom APM tile buttons — same animation
|
|
1814
|
+
// curve, same duration, only the surface colour changes (grey for
|
|
1815
|
+
// the wallet skeleton vs. brand colour for an in-flight tile).
|
|
1816
|
+
animation: submitting ? "flopay-pulse 1.5s ease-in-out infinite" : void 0,
|
|
1817
|
+
display: "flex",
|
|
1818
|
+
alignItems: "center",
|
|
1819
|
+
// Always center the logo+name group. The drill-in chevron (input
|
|
1820
|
+
// methods) is absolutely positioned at the right edge below so it
|
|
1821
|
+
// doesn't pull the label off-center.
|
|
1822
|
+
justifyContent: "center",
|
|
1823
|
+
gap: 8,
|
|
1824
|
+
transition: "transform 0.1s, opacity 140ms ease-out, border-color 140ms ease-out",
|
|
1825
|
+
boxShadow: highlighted ? "0 0 0 2px rgba(74, 73, 255, 0.15)" : void 0
|
|
1826
|
+
},
|
|
1827
|
+
children: submitting ? (
|
|
1828
|
+
// Pulse-skeleton parity with the wallet ECE: no spinner, just the
|
|
1829
|
+
// status text on top of the pulsing background. Keeps the loading
|
|
1830
|
+
// affordance shape-equivalent across both kinds of tile.
|
|
1831
|
+
/* @__PURE__ */ jsx6("span", { style: { margin: "0 auto" }, children: `Connecting to ${getStripeMethodDisplayName(method)}\u2026` })
|
|
1832
|
+
) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1833
|
+
/* @__PURE__ */ jsxs4(
|
|
1834
|
+
"span",
|
|
1835
|
+
{
|
|
1836
|
+
style: {
|
|
1837
|
+
display: "inline-flex",
|
|
1838
|
+
alignItems: "center",
|
|
1839
|
+
// Real vendored logos are self-contained brand cards, so they
|
|
1840
|
+
// get an 8px gap from the label. The generated placeholder
|
|
1841
|
+
// monogram reads as part of the label (the tile's first letter),
|
|
1842
|
+
// so it sits flush (0px) against the name.
|
|
1843
|
+
gap: hasVendoredStripeMethodLogo(method) ? 8 : 0
|
|
1844
|
+
},
|
|
1845
|
+
children: [
|
|
1846
|
+
brand?.logoSvg && /* @__PURE__ */ jsx6(
|
|
1847
|
+
"span",
|
|
1848
|
+
{
|
|
1849
|
+
"aria-hidden": "true",
|
|
1850
|
+
style: {
|
|
1851
|
+
// 3:2 box matching the vendored datatrans logos' 120×80
|
|
1852
|
+
// viewBox. Each logo ships with its own white rounded-rect
|
|
1853
|
+
// background baked in, so the mark stays legible on any
|
|
1854
|
+
// brand-coloured tile without an extra chip wrapper here.
|
|
1855
|
+
width: 30,
|
|
1856
|
+
height: 20,
|
|
1857
|
+
flexShrink: 0,
|
|
1858
|
+
display: "inline-flex",
|
|
1859
|
+
borderRadius: 3,
|
|
1860
|
+
overflow: "hidden"
|
|
1861
|
+
},
|
|
1862
|
+
dangerouslySetInnerHTML: { __html: brand.logoSvg }
|
|
1863
|
+
}
|
|
1864
|
+
),
|
|
1865
|
+
/* @__PURE__ */ jsx6("span", { children: getStripeMethodDisplayName(method) })
|
|
1866
|
+
]
|
|
1867
|
+
}
|
|
1868
|
+
),
|
|
1869
|
+
hasNextStep && /* @__PURE__ */ jsx6(
|
|
1870
|
+
"svg",
|
|
1871
|
+
{
|
|
1872
|
+
width: "14",
|
|
1873
|
+
height: "14",
|
|
1874
|
+
viewBox: "0 0 24 24",
|
|
1875
|
+
fill: "none",
|
|
1876
|
+
stroke: resolvedTextColor,
|
|
1877
|
+
strokeWidth: "2.5",
|
|
1878
|
+
strokeLinecap: "round",
|
|
1879
|
+
strokeLinejoin: "round",
|
|
1880
|
+
style: {
|
|
1881
|
+
position: "absolute",
|
|
1882
|
+
right: "1rem",
|
|
1883
|
+
top: "50%",
|
|
1884
|
+
transform: "translateY(-50%)",
|
|
1885
|
+
flexShrink: 0,
|
|
1886
|
+
opacity: 0.7
|
|
1887
|
+
},
|
|
1888
|
+
"aria-hidden": "true",
|
|
1889
|
+
children: /* @__PURE__ */ jsx6("path", { d: "M9 18l6-6-6-6" })
|
|
1890
|
+
}
|
|
1891
|
+
)
|
|
1892
|
+
] })
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
function StripeMethodInlineForm({
|
|
1897
|
+
method,
|
|
1898
|
+
sessionId,
|
|
1899
|
+
email,
|
|
1900
|
+
billingName,
|
|
1901
|
+
billingApiUrl,
|
|
1902
|
+
onTokenizedBody,
|
|
1903
|
+
onErrorChange,
|
|
1904
|
+
onDecline,
|
|
1905
|
+
onCancel,
|
|
1906
|
+
runBeforeButtonClick,
|
|
1907
|
+
onButtonClick,
|
|
1908
|
+
isProcessing,
|
|
1909
|
+
submitButtonColor,
|
|
1910
|
+
submitButtonBorderRadius,
|
|
1911
|
+
submitButtonStyle
|
|
1912
|
+
}) {
|
|
1913
|
+
const stripe = useStripeRaw();
|
|
1914
|
+
const elements = useStripeElements();
|
|
1915
|
+
const [submitting, setSubmitting] = useState3(false);
|
|
1916
|
+
const submittingRef = useRef3(false);
|
|
1917
|
+
const [isMethodComplete, setIsMethodComplete] = useState3(false);
|
|
1918
|
+
const [loadState, setLoadState] = useState3("loading");
|
|
1919
|
+
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1920
|
+
const handlePay = useCallback(async () => {
|
|
1921
|
+
if (!stripe || !elements || isProcessing || submittingRef.current || !isMethodComplete) return;
|
|
1922
|
+
submittingRef.current = true;
|
|
1923
|
+
setSubmitting(true);
|
|
1924
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("card") : { proceed: true };
|
|
1925
|
+
if (!beforeClick.proceed) {
|
|
1926
|
+
submittingRef.current = false;
|
|
1927
|
+
setSubmitting(false);
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
onButtonClick?.("card");
|
|
1931
|
+
const effectiveSessionId = beforeClick.sessionId ?? sessionId;
|
|
1932
|
+
const effectiveEmail = beforeClick.accountPatch?.email ?? email;
|
|
1933
|
+
try {
|
|
1934
|
+
onErrorChange?.(null);
|
|
1935
|
+
const submitRes = await elements.submit();
|
|
1936
|
+
if (submitRes.error) {
|
|
1937
|
+
onErrorChange?.(submitRes.error.message ?? "Payment failed.");
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
const pmRes = await stripe.createPaymentMethod({ elements });
|
|
1941
|
+
if (pmRes.error || !pmRes.paymentMethod) {
|
|
1942
|
+
onErrorChange?.(pmRes.error?.message ?? "Failed to create payment method.");
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
const paymentMethod = pmRes.paymentMethod;
|
|
1946
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
1947
|
+
throw new Error("Missing sessionId or email for payment.");
|
|
1948
|
+
}
|
|
1949
|
+
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
1950
|
+
method: "POST",
|
|
1951
|
+
headers: { "Content-Type": "application/json" },
|
|
1952
|
+
body: JSON.stringify({
|
|
1953
|
+
sessionId: effectiveSessionId,
|
|
1954
|
+
email: effectiveEmail,
|
|
1955
|
+
paymentMethodType: paymentMethod.type || method,
|
|
1956
|
+
isPaypal: false
|
|
1957
|
+
})
|
|
1958
|
+
});
|
|
1959
|
+
if (!intentResponse.ok) {
|
|
1960
|
+
const intentError = await buildFloPayApiErrorFromResponse(intentResponse, "Failed to create payment intent");
|
|
1961
|
+
onErrorChange?.(intentError.message);
|
|
1962
|
+
onDecline?.(buildDeclineEvent("card", intentError));
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
const intentJson = await intentResponse.json();
|
|
1966
|
+
const intentClientSecret = intentJson.data?.id;
|
|
1967
|
+
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
1968
|
+
if (typeof window !== "undefined") {
|
|
1969
|
+
try {
|
|
1970
|
+
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
1971
|
+
sessionId: effectiveSessionId,
|
|
1972
|
+
paymentMethodId: paymentMethod.id,
|
|
1973
|
+
paymentMethodType: paymentMethod.type ?? method,
|
|
1974
|
+
gateway: "stripe"
|
|
1975
|
+
}));
|
|
1976
|
+
} catch {
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
const { error: confirmError, paymentIntent } = await stripe.confirmPayment({
|
|
1980
|
+
clientSecret: intentClientSecret,
|
|
1981
|
+
confirmParams: {
|
|
1982
|
+
return_url: window.location.href,
|
|
1983
|
+
payment_method: paymentMethod.id
|
|
1984
|
+
},
|
|
1985
|
+
redirect: "if_required"
|
|
1986
|
+
});
|
|
1987
|
+
if (confirmError) {
|
|
1988
|
+
if (typeof window !== "undefined") {
|
|
1989
|
+
try {
|
|
1990
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
1991
|
+
} catch {
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
const message = confirmError.message ?? "Payment failed.";
|
|
1995
|
+
onErrorChange?.(message);
|
|
1996
|
+
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
const SUCCESSFUL_PI_STATUSES = /* @__PURE__ */ new Set(["succeeded", "requires_capture", "processing"]);
|
|
2000
|
+
const piStatus = paymentIntent?.status;
|
|
2001
|
+
if (!piStatus || !SUCCESSFUL_PI_STATUSES.has(piStatus)) {
|
|
2002
|
+
if (typeof window !== "undefined") {
|
|
2003
|
+
try {
|
|
2004
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
2009
|
+
onErrorChange?.(message);
|
|
2010
|
+
onDecline?.(buildDeclineEvent("card", message, { code: piStatus ?? "missing_payment_intent" }));
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
if (typeof window !== "undefined") {
|
|
2014
|
+
try {
|
|
2015
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2016
|
+
} catch {
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
const confirmedPmId = typeof paymentIntent?.payment_method === "string" ? paymentIntent.payment_method : paymentIntent?.payment_method?.id;
|
|
2020
|
+
onTokenizedBody({
|
|
2021
|
+
id: confirmedPmId ?? paymentMethod.id,
|
|
2022
|
+
type: "card",
|
|
2023
|
+
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
2024
|
+
gateway: "stripe",
|
|
2025
|
+
paymentMethodType: paymentMethod.type ?? method
|
|
2026
|
+
}, {
|
|
2027
|
+
accountPatch: beforeClick.accountPatch,
|
|
2028
|
+
sessionId: effectiveSessionId
|
|
2029
|
+
});
|
|
2030
|
+
} catch (err) {
|
|
2031
|
+
onErrorChange?.(err instanceof Error ? err.message : "Payment failed. Please try again.");
|
|
2032
|
+
} finally {
|
|
2033
|
+
submittingRef.current = false;
|
|
2034
|
+
setSubmitting(false);
|
|
2035
|
+
}
|
|
2036
|
+
}, [
|
|
2037
|
+
stripe,
|
|
2038
|
+
elements,
|
|
2039
|
+
isProcessing,
|
|
2040
|
+
isMethodComplete,
|
|
2041
|
+
runBeforeButtonClick,
|
|
2042
|
+
onButtonClick,
|
|
2043
|
+
sessionId,
|
|
2044
|
+
email,
|
|
2045
|
+
baseUrl,
|
|
2046
|
+
method,
|
|
2047
|
+
onTokenizedBody,
|
|
2048
|
+
onErrorChange,
|
|
2049
|
+
onDecline
|
|
2050
|
+
]);
|
|
2051
|
+
void onCancel;
|
|
2052
|
+
return /* @__PURE__ */ jsxs4("div", { "data-testid": `flopay-stripe-method-form-${method}`, style: { display: "flex", flexDirection: "column" }, children: [
|
|
2053
|
+
/* @__PURE__ */ jsx6(
|
|
2054
|
+
PaymentElement2,
|
|
2055
|
+
{
|
|
2056
|
+
onReady: () => setLoadState("ready"),
|
|
2057
|
+
onLoadError: () => setLoadState("load_error"),
|
|
2058
|
+
onChange: (event) => {
|
|
2059
|
+
const evRecord = event;
|
|
2060
|
+
setIsMethodComplete(!!evRecord.complete);
|
|
2061
|
+
},
|
|
2062
|
+
options: {
|
|
2063
|
+
layout: { type: "accordion", defaultCollapsed: false, radios: "never" },
|
|
2064
|
+
defaultValues: {
|
|
2065
|
+
billingDetails: {
|
|
2066
|
+
name: billingName && billingName.trim().length >= 3 ? billingName.trim() : "FloPay Customer",
|
|
2067
|
+
...email ? { email } : {}
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
),
|
|
2073
|
+
/* @__PURE__ */ jsx6(
|
|
2074
|
+
"button",
|
|
2075
|
+
{
|
|
2076
|
+
type: "button",
|
|
2077
|
+
"data-testid": `flopay-stripe-method-pay-${method}`,
|
|
2078
|
+
onClick: () => {
|
|
2079
|
+
void handlePay();
|
|
2080
|
+
},
|
|
2081
|
+
disabled: !isMethodComplete || submitting || isProcessing || loadState !== "ready",
|
|
2082
|
+
style: {
|
|
2083
|
+
width: "100%",
|
|
2084
|
+
marginTop: "0.75rem",
|
|
2085
|
+
padding: "0.875rem",
|
|
2086
|
+
backgroundColor: submitButtonColor,
|
|
2087
|
+
color: "white",
|
|
2088
|
+
border: "none",
|
|
2089
|
+
borderRadius: submitButtonBorderRadius,
|
|
2090
|
+
fontSize: "1rem",
|
|
2091
|
+
fontWeight: 600,
|
|
2092
|
+
cursor: !isMethodComplete || submitting || isProcessing || loadState !== "ready" ? "not-allowed" : "pointer",
|
|
2093
|
+
opacity: !isMethodComplete || submitting || isProcessing || loadState !== "ready" ? 0.5 : 1,
|
|
2094
|
+
transition: "opacity 120ms ease-out",
|
|
2095
|
+
...submitButtonStyle ?? {}
|
|
2096
|
+
},
|
|
2097
|
+
children: submitting ? "Processing\u2026" : `Pay with ${getStripeMethodDisplayName(method)}`
|
|
2098
|
+
}
|
|
2099
|
+
)
|
|
2100
|
+
] });
|
|
2101
|
+
}
|
|
2102
|
+
function StripePaymentElementInner({
|
|
2103
|
+
sessionId,
|
|
2104
|
+
email,
|
|
2105
|
+
billingName,
|
|
2106
|
+
billingApiUrl,
|
|
2107
|
+
paymentElementMethods,
|
|
2108
|
+
stripeInstance,
|
|
2109
|
+
paymentElementBaseOptions,
|
|
2110
|
+
onTokenizedBody,
|
|
2111
|
+
onErrorChange,
|
|
2112
|
+
onButtonClick,
|
|
2113
|
+
onDecline,
|
|
2114
|
+
runBeforeButtonClick,
|
|
2115
|
+
onLoadStateChange,
|
|
2116
|
+
isProcessing = false,
|
|
2117
|
+
submitButtonColor = "#4A49FF",
|
|
2118
|
+
submitButtonBorderRadius = 8,
|
|
2119
|
+
submitButtonStyle,
|
|
2120
|
+
buttonAppearance,
|
|
2121
|
+
themeId,
|
|
2122
|
+
onExpandApm,
|
|
2123
|
+
expandedApmMethod
|
|
2124
|
+
}) {
|
|
2125
|
+
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
2126
|
+
const [expandedMethod, setExpandedMethod] = useState3(null);
|
|
2127
|
+
const [submittingMethod, setSubmittingMethod] = useState3(null);
|
|
2128
|
+
const submittingRef = useRef3(false);
|
|
2129
|
+
useEffect4(() => {
|
|
2130
|
+
if (paymentElementMethods.length > 0 && stripeInstance) {
|
|
2131
|
+
onLoadStateChange?.("ready");
|
|
2132
|
+
} else if (!stripeInstance) {
|
|
2133
|
+
onLoadStateChange?.("loading");
|
|
2134
|
+
}
|
|
2135
|
+
}, [paymentElementMethods.length, stripeInstance, onLoadStateChange]);
|
|
2136
|
+
const handleAutoConfirm = useCallback(async (method) => {
|
|
2137
|
+
if (!stripeInstance) return;
|
|
2138
|
+
if (submittingRef.current || isProcessing) return;
|
|
2139
|
+
submittingRef.current = true;
|
|
2140
|
+
setSubmittingMethod(method);
|
|
2141
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("card") : { proceed: true };
|
|
2142
|
+
if (!beforeClick.proceed) {
|
|
2143
|
+
submittingRef.current = false;
|
|
2144
|
+
setSubmittingMethod(null);
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
onButtonClick?.("card");
|
|
2148
|
+
const effectiveSessionId = beforeClick.sessionId ?? sessionId;
|
|
2149
|
+
const effectiveEmail = beforeClick.accountPatch?.email ?? email;
|
|
2150
|
+
try {
|
|
2151
|
+
onErrorChange?.(null);
|
|
2152
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
2153
|
+
throw new Error("Missing sessionId or email for payment.");
|
|
2154
|
+
}
|
|
2155
|
+
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
2156
|
+
method: "POST",
|
|
2157
|
+
headers: { "Content-Type": "application/json" },
|
|
2158
|
+
body: JSON.stringify({
|
|
2159
|
+
sessionId: effectiveSessionId,
|
|
2160
|
+
email: effectiveEmail,
|
|
2161
|
+
// Wire type, not pm_xxx — backend scopes `payment_method_types`
|
|
2162
|
+
// to this single method so unrelated account-wide methods
|
|
2163
|
+
// (apple_pay without domain verification, …) don't poison PI
|
|
2164
|
+
// creation.
|
|
2165
|
+
paymentMethodType: method,
|
|
2166
|
+
isPaypal: false
|
|
2167
|
+
})
|
|
2168
|
+
});
|
|
2169
|
+
if (!intentResponse.ok) {
|
|
2170
|
+
const intentError = await buildFloPayApiErrorFromResponse(intentResponse, "Failed to create payment intent");
|
|
2171
|
+
onErrorChange?.(intentError.message);
|
|
2172
|
+
onDecline?.(buildDeclineEvent("card", intentError));
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
const intentJson = await intentResponse.json();
|
|
2176
|
+
const intentClientSecret = intentJson.data?.id;
|
|
2177
|
+
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2178
|
+
if (typeof window !== "undefined") {
|
|
2179
|
+
try {
|
|
2180
|
+
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
2181
|
+
sessionId: effectiveSessionId,
|
|
2182
|
+
paymentMethodType: method,
|
|
2183
|
+
gateway: "stripe"
|
|
2184
|
+
}));
|
|
2185
|
+
} catch {
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
const { error: confirmError, paymentIntent } = await stripeInstance.confirmPayment({
|
|
2189
|
+
clientSecret: intentClientSecret,
|
|
2190
|
+
confirmParams: {
|
|
2191
|
+
return_url: window.location.href,
|
|
2192
|
+
// Inline the method data — no Elements / PaymentElement
|
|
2193
|
+
// required. Stripe creates the PaymentMethod during confirm
|
|
2194
|
+
// and proceeds to its popup/redirect UI.
|
|
2195
|
+
payment_method_data: {
|
|
2196
|
+
type: method,
|
|
2197
|
+
billing_details: {
|
|
2198
|
+
name: billingName && billingName.trim().length >= 3 ? billingName.trim() : "FloPay Customer",
|
|
2199
|
+
...effectiveEmail ? { email: effectiveEmail } : {}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
},
|
|
2203
|
+
redirect: "if_required"
|
|
2204
|
+
});
|
|
2205
|
+
if (confirmError) {
|
|
2206
|
+
if (typeof window !== "undefined") {
|
|
2207
|
+
try {
|
|
2208
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2209
|
+
} catch {
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
const message = confirmError.message ?? "Payment failed.";
|
|
2213
|
+
onErrorChange?.(message);
|
|
2214
|
+
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
2215
|
+
return;
|
|
2216
|
+
}
|
|
2217
|
+
const SUCCESSFUL_PI_STATUSES = /* @__PURE__ */ new Set(["succeeded", "requires_capture", "processing"]);
|
|
2218
|
+
const piStatus = paymentIntent?.status;
|
|
2219
|
+
if (!piStatus || !SUCCESSFUL_PI_STATUSES.has(piStatus)) {
|
|
2220
|
+
if (typeof window !== "undefined") {
|
|
2221
|
+
try {
|
|
2222
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2223
|
+
} catch {
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
2227
|
+
onErrorChange?.(message);
|
|
2228
|
+
onDecline?.(buildDeclineEvent("card", message, { code: piStatus ?? "missing_payment_intent" }));
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
if (typeof window !== "undefined") {
|
|
2232
|
+
try {
|
|
2233
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2234
|
+
} catch {
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
const confirmedPmId = typeof paymentIntent?.payment_method === "string" ? paymentIntent.payment_method : paymentIntent?.payment_method?.id;
|
|
2238
|
+
onTokenizedBody({
|
|
2239
|
+
id: confirmedPmId ?? paymentIntent?.id,
|
|
2240
|
+
type: "card",
|
|
2241
|
+
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
2242
|
+
gateway: "stripe",
|
|
2243
|
+
paymentMethodType: method
|
|
2244
|
+
}, {
|
|
2245
|
+
accountPatch: beforeClick.accountPatch,
|
|
2246
|
+
sessionId: effectiveSessionId
|
|
2247
|
+
});
|
|
2248
|
+
} catch (err) {
|
|
2249
|
+
onErrorChange?.(err instanceof Error ? err.message : "Payment failed. Please try again.");
|
|
2250
|
+
} finally {
|
|
2251
|
+
submittingRef.current = false;
|
|
2252
|
+
setSubmittingMethod(null);
|
|
2253
|
+
}
|
|
2254
|
+
}, [
|
|
2255
|
+
stripeInstance,
|
|
2256
|
+
isProcessing,
|
|
2257
|
+
runBeforeButtonClick,
|
|
2258
|
+
onButtonClick,
|
|
2259
|
+
sessionId,
|
|
2260
|
+
email,
|
|
2261
|
+
baseUrl,
|
|
2262
|
+
billingName,
|
|
2263
|
+
onTokenizedBody,
|
|
2264
|
+
onErrorChange,
|
|
2265
|
+
onDecline
|
|
2266
|
+
]);
|
|
2267
|
+
const [localExpandedMethod, setLocalExpandedMethod] = useState3(null);
|
|
2268
|
+
const activeExpandedMethod = onExpandApm ? expandedApmMethod ?? null : localExpandedMethod;
|
|
2269
|
+
const handleMethodClick = useCallback((method) => {
|
|
2270
|
+
if (submittingRef.current || isProcessing) return;
|
|
2271
|
+
if (activeExpandedMethod && activeExpandedMethod !== method) return;
|
|
2272
|
+
if (needsStripeMethodExplicitConfirm(method)) {
|
|
2273
|
+
if (onExpandApm) {
|
|
2274
|
+
onExpandApm(method);
|
|
2275
|
+
} else {
|
|
2276
|
+
setLocalExpandedMethod(method);
|
|
2277
|
+
}
|
|
2278
|
+
} else {
|
|
2279
|
+
void handleAutoConfirm(method);
|
|
2280
|
+
}
|
|
2281
|
+
}, [activeExpandedMethod, isProcessing, handleAutoConfirm, onExpandApm]);
|
|
2282
|
+
const localInlineElementsOptions = useMemo3(() => {
|
|
2283
|
+
if (!localExpandedMethod) return null;
|
|
2284
|
+
return {
|
|
2285
|
+
...paymentElementBaseOptions,
|
|
2286
|
+
paymentMethodTypes: [localExpandedMethod]
|
|
2287
|
+
};
|
|
2288
|
+
}, [localExpandedMethod, paymentElementBaseOptions]);
|
|
2289
|
+
return /* @__PURE__ */ jsx6(
|
|
2290
|
+
"div",
|
|
2291
|
+
{
|
|
2292
|
+
"data-testid": "flopay-stripe-payment-element-region",
|
|
2293
|
+
style: { display: "flex", flexDirection: "column", gap: "0.5rem" },
|
|
2294
|
+
children: paymentElementMethods.map((method) => {
|
|
2295
|
+
const isExpanded = expandedApmMethod === method;
|
|
2296
|
+
const isSubmittingThis = submittingMethod === method;
|
|
2297
|
+
const otherInProgress = submittingMethod !== null && submittingMethod !== method || expandedApmMethod !== null && expandedApmMethod !== void 0 && expandedApmMethod !== method;
|
|
2298
|
+
return /* @__PURE__ */ jsxs4(React6.Fragment, { children: [
|
|
2299
|
+
/* @__PURE__ */ jsx6(
|
|
2300
|
+
StripeMethodButton,
|
|
2301
|
+
{
|
|
2302
|
+
method,
|
|
2303
|
+
themeId,
|
|
2304
|
+
submitting: isSubmittingThis,
|
|
2305
|
+
disabled: otherInProgress,
|
|
2306
|
+
highlighted: isExpanded,
|
|
2307
|
+
hasNextStep: needsStripeMethodExplicitConfirm(method),
|
|
2308
|
+
onClick: () => handleMethodClick(method),
|
|
2309
|
+
backgroundColor: buttonAppearance?.backgroundColor,
|
|
2310
|
+
borderColor: buttonAppearance?.borderColor,
|
|
2311
|
+
textColor: buttonAppearance?.textColor,
|
|
2312
|
+
borderRadius: buttonAppearance?.borderRadius,
|
|
2313
|
+
fontFamily: buttonAppearance?.fontFamily
|
|
2314
|
+
}
|
|
2315
|
+
),
|
|
2316
|
+
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */ jsx6(
|
|
2317
|
+
StripeElements,
|
|
2318
|
+
{
|
|
2319
|
+
stripe: stripeInstance,
|
|
2320
|
+
options: localInlineElementsOptions,
|
|
2321
|
+
children: /* @__PURE__ */ jsx6(
|
|
2322
|
+
StripeMethodInlineForm,
|
|
2323
|
+
{
|
|
2324
|
+
method,
|
|
2325
|
+
sessionId,
|
|
2326
|
+
email,
|
|
2327
|
+
billingName,
|
|
2328
|
+
billingApiUrl,
|
|
2329
|
+
onTokenizedBody,
|
|
2330
|
+
onErrorChange,
|
|
2331
|
+
onDecline,
|
|
2332
|
+
onCancel: () => setLocalExpandedMethod(null),
|
|
2333
|
+
runBeforeButtonClick,
|
|
2334
|
+
onButtonClick,
|
|
2335
|
+
isProcessing,
|
|
2336
|
+
submitButtonColor,
|
|
2337
|
+
submitButtonBorderRadius,
|
|
2338
|
+
submitButtonStyle
|
|
2339
|
+
}
|
|
2340
|
+
)
|
|
2341
|
+
},
|
|
2342
|
+
method
|
|
2343
|
+
)
|
|
2344
|
+
] }, method);
|
|
2345
|
+
})
|
|
2346
|
+
}
|
|
2347
|
+
);
|
|
1698
2348
|
}
|
|
1699
2349
|
function SplitCardFormInner({
|
|
1700
2350
|
sessionId,
|
|
@@ -1718,6 +2368,8 @@ function SplitCardFormInner({
|
|
|
1718
2368
|
onFirstNameChange,
|
|
1719
2369
|
onLastNameChange,
|
|
1720
2370
|
showPayPal = true,
|
|
2371
|
+
showStripe = true,
|
|
2372
|
+
enabledPaymentMethods,
|
|
1721
2373
|
showApplePay = true,
|
|
1722
2374
|
showGooglePay = true,
|
|
1723
2375
|
layout = "default",
|
|
@@ -1777,6 +2429,7 @@ function SplitCardFormInner({
|
|
|
1777
2429
|
const avsConfig = useMemo3(() => resolveAVSConfig(enableAVSProp), [enableAVSProp]);
|
|
1778
2430
|
const enableAVS = avsConfig !== null;
|
|
1779
2431
|
const [viewState, setViewState] = useState3(initialCardOpen ? "card" : "buttons");
|
|
2432
|
+
const [expandedApmMethod, setExpandedApmMethod] = useState3(null);
|
|
1780
2433
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
1781
2434
|
const TRANSITION_MS = 280;
|
|
1782
2435
|
const expandToCard = useCallback(() => {
|
|
@@ -1787,6 +2440,18 @@ function SplitCardFormInner({
|
|
|
1787
2440
|
setViewState("collapsing");
|
|
1788
2441
|
setTimeout(() => setViewState("buttons"), TRANSITION_MS);
|
|
1789
2442
|
}, []);
|
|
2443
|
+
const expandToApm = useCallback((method) => {
|
|
2444
|
+
setExpandedApmMethod(method);
|
|
2445
|
+
setViewState("apm-expanding");
|
|
2446
|
+
setTimeout(() => setViewState("apm-form"), TRANSITION_MS);
|
|
2447
|
+
}, []);
|
|
2448
|
+
const collapseFromApm = useCallback(() => {
|
|
2449
|
+
setViewState("apm-collapsing");
|
|
2450
|
+
setTimeout(() => {
|
|
2451
|
+
setViewState("buttons");
|
|
2452
|
+
setExpandedApmMethod(null);
|
|
2453
|
+
}, TRANSITION_MS);
|
|
2454
|
+
}, []);
|
|
1790
2455
|
useEffect4(() => {
|
|
1791
2456
|
if (layout === "buttons" && initialCardOpen) {
|
|
1792
2457
|
setViewState("card");
|
|
@@ -1840,20 +2505,43 @@ function SplitCardFormInner({
|
|
|
1840
2505
|
return paypalFlopay.getRawProvider();
|
|
1841
2506
|
}, [paypalFlopay]);
|
|
1842
2507
|
const amountInCents = totalAmount || 100;
|
|
2508
|
+
const stripeAppearanceProp = appearance ? { appearance } : null;
|
|
2509
|
+
const paymentElementAppearance = useMemo3(() => {
|
|
2510
|
+
const base = appearance ?? {};
|
|
2511
|
+
const baseRules = base.rules ?? {};
|
|
2512
|
+
return {
|
|
2513
|
+
...base,
|
|
2514
|
+
rules: {
|
|
2515
|
+
...baseRules,
|
|
2516
|
+
".AccordionItem": {
|
|
2517
|
+
padding: "10px 14px",
|
|
2518
|
+
boxShadow: "none",
|
|
2519
|
+
...baseRules[".AccordionItem"] ?? {}
|
|
2520
|
+
},
|
|
2521
|
+
".AccordionItemContents": {
|
|
2522
|
+
padding: "6px 14px 12px",
|
|
2523
|
+
boxShadow: "none",
|
|
2524
|
+
...baseRules[".AccordionItemContents"] ?? {}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
}, [appearance]);
|
|
1843
2529
|
const walletOptions = useMemo3(() => ({
|
|
1844
2530
|
mode: "payment",
|
|
1845
2531
|
amount: amountInCents,
|
|
1846
2532
|
currency: currency.toLowerCase(),
|
|
1847
2533
|
paymentMethodCreation: "manual",
|
|
1848
|
-
captureMethod: "manual"
|
|
1849
|
-
|
|
2534
|
+
captureMethod: "manual",
|
|
2535
|
+
...stripeAppearanceProp
|
|
2536
|
+
}), [amountInCents, currency, stripeAppearanceProp]);
|
|
1850
2537
|
const paypalOptions = useMemo3(() => ({
|
|
1851
2538
|
mode: "payment",
|
|
1852
2539
|
amount: amountInCents,
|
|
1853
2540
|
currency: currency.toLowerCase(),
|
|
1854
2541
|
captureMethod: "manual",
|
|
1855
|
-
setupFutureUsage: "off_session"
|
|
1856
|
-
|
|
2542
|
+
setupFutureUsage: "off_session",
|
|
2543
|
+
...stripeAppearanceProp
|
|
2544
|
+
}), [amountInCents, currency, stripeAppearanceProp]);
|
|
1857
2545
|
const updateError = useCallback(
|
|
1858
2546
|
(err) => {
|
|
1859
2547
|
setError(err);
|
|
@@ -1867,22 +2555,98 @@ function SplitCardFormInner({
|
|
|
1867
2555
|
},
|
|
1868
2556
|
[onDecline]
|
|
1869
2557
|
);
|
|
1870
|
-
const
|
|
2558
|
+
const directPaypalConfigured = !!directPaypal?.clientId;
|
|
2559
|
+
const hasEnabledMethodsPayload = Array.isArray(enabledPaymentMethods);
|
|
2560
|
+
const hasEnabledMethods = hasEnabledMethodsPayload && enabledPaymentMethods.length > 0;
|
|
2561
|
+
const paypalEnabled = hasEnabledMethodsPayload && enabledPaymentMethods.includes("paypal");
|
|
2562
|
+
const { expressMethods, paymentElementMethods } = useMemo3(
|
|
2563
|
+
() => partitionStripeMethods(enabledPaymentMethods, {
|
|
2564
|
+
excludePaypal: directPaypalConfigured
|
|
2565
|
+
}),
|
|
2566
|
+
[enabledPaymentMethods, directPaypalConfigured]
|
|
2567
|
+
);
|
|
2568
|
+
const paypalRenderedSeparately = directPaypalConfigured || !!paypalFlopay;
|
|
2569
|
+
const expressMethodsForWalletRow = useMemo3(
|
|
2570
|
+
() => paypalRenderedSeparately ? expressMethods.filter((m) => m !== "paypal") : expressMethods,
|
|
2571
|
+
[expressMethods, paypalRenderedSeparately]
|
|
2572
|
+
);
|
|
2573
|
+
const legacyExpressMethods = useMemo3(() => {
|
|
2574
|
+
const out = [];
|
|
2575
|
+
if (showApplePay) out.push("apple_pay");
|
|
2576
|
+
if (showGooglePay) out.push("google_pay");
|
|
2577
|
+
return out;
|
|
2578
|
+
}, [showApplePay, showGooglePay]);
|
|
2579
|
+
const walletExpressMethods = hasEnabledMethodsPayload ? expressMethodsForWalletRow : legacyExpressMethods;
|
|
2580
|
+
const showWallets = showStripe && walletExpressMethods.length > 0;
|
|
2581
|
+
const paymentElementMethodsForCurrency = useMemo3(
|
|
2582
|
+
() => filterStripeMethodsByAmount(
|
|
2583
|
+
filterStripeMethodsByCountry(
|
|
2584
|
+
filterStripeMethodsByCurrency(paymentElementMethods, currency),
|
|
2585
|
+
countryProp
|
|
2586
|
+
),
|
|
2587
|
+
currency,
|
|
2588
|
+
amountInCents
|
|
2589
|
+
),
|
|
2590
|
+
[paymentElementMethods, currency, countryProp, amountInCents]
|
|
2591
|
+
);
|
|
2592
|
+
const paymentElementBaseOptions = useMemo3(() => ({
|
|
2593
|
+
mode: "payment",
|
|
2594
|
+
amount: amountInCents,
|
|
2595
|
+
currency: currency.toLowerCase(),
|
|
2596
|
+
paymentMethodCreation: "manual",
|
|
2597
|
+
appearance: paymentElementAppearance
|
|
2598
|
+
}), [amountInCents, currency, paymentElementAppearance]);
|
|
1871
2599
|
const [paypalLoadState, setPaypalLoadState] = useState3("loading");
|
|
1872
2600
|
const [walletLoadState, setWalletLoadState] = useState3("loading");
|
|
2601
|
+
const [paymentElementLoadState, setPaymentElementLoadState] = useState3("loading");
|
|
1873
2602
|
const [directPaypalReady, setDirectPaypalReady] = useState3(false);
|
|
1874
2603
|
const [inAppBrowserDetected, setInAppBrowserDetected] = useState3();
|
|
1875
2604
|
useEffect4(() => {
|
|
1876
2605
|
setInAppBrowserDetected(isInAppBrowser());
|
|
1877
2606
|
}, []);
|
|
1878
|
-
const
|
|
1879
|
-
const
|
|
1880
|
-
const shouldShowWallets = showWallets;
|
|
2607
|
+
const shouldShowPayPal = showPayPal && (directPaypalConfigured || (hasEnabledMethodsPayload ? paypalEnabled : inAppBrowserDetected === false));
|
|
2608
|
+
const shouldShowWallets = showStripe && showWallets;
|
|
1881
2609
|
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
1882
2610
|
const shouldRenderStripePayPal = shouldShowPayPal && !directPaypalConfigured && !!paypalStripeInstance;
|
|
1883
2611
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
2612
|
+
const shouldRenderPaymentElement = showStripe && hasEnabledMethods && paymentElementMethodsForCurrency.length > 0 && !!stripeInstance;
|
|
1884
2613
|
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
1885
2614
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
2615
|
+
const shouldDisplayPaymentElementRow = shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
2616
|
+
const validationFiredRef = useRef3(false);
|
|
2617
|
+
useEffect4(() => {
|
|
2618
|
+
if (validationFiredRef.current) return;
|
|
2619
|
+
if (!showStripe && !showPayPal) {
|
|
2620
|
+
validationFiredRef.current = true;
|
|
2621
|
+
const err = new FloPayError3(
|
|
2622
|
+
"FloPay: both `showStripe` and `showPayPal` are false \u2014 nothing to render.",
|
|
2623
|
+
"validation_error"
|
|
2624
|
+
);
|
|
2625
|
+
onError?.(err);
|
|
2626
|
+
updateError(err.message);
|
|
2627
|
+
} else if (!showStripe && showPayPal && !directPaypalConfigured && !paypalStripeInstance) {
|
|
2628
|
+
validationFiredRef.current = true;
|
|
2629
|
+
const err = new FloPayError3(
|
|
2630
|
+
"FloPay: `showStripe` is false and no PayPal gateway is configured for this session \u2014 nothing to render.",
|
|
2631
|
+
"validation_error"
|
|
2632
|
+
);
|
|
2633
|
+
onError?.(err);
|
|
2634
|
+
updateError(err.message);
|
|
2635
|
+
}
|
|
2636
|
+
}, [showStripe, showPayPal, directPaypalConfigured, paypalStripeInstance, onError, updateError]);
|
|
2637
|
+
const deprecationLoggedRef = useRef3(false);
|
|
2638
|
+
useEffect4(() => {
|
|
2639
|
+
if (deprecationLoggedRef.current) return;
|
|
2640
|
+
if (!hasEnabledMethods) return;
|
|
2641
|
+
const stale = [];
|
|
2642
|
+
if (showApplePay !== true) stale.push("showApplePay");
|
|
2643
|
+
if (showGooglePay !== true) stale.push("showGooglePay");
|
|
2644
|
+
if (stale.length === 0) return;
|
|
2645
|
+
deprecationLoggedRef.current = true;
|
|
2646
|
+
console.warn(
|
|
2647
|
+
`[FloPay] ${stale.join(" / ")} ${stale.length === 1 ? "is" : "are"} deprecated: the Apple Pay / Google Pay surface is now driven by \`gateways.stripe.enabledPaymentMethods\` on the session response. Remove the legacy prop(s) to silence this warning.`
|
|
2648
|
+
);
|
|
2649
|
+
}, [hasEnabledMethods, showApplePay, showGooglePay]);
|
|
1886
2650
|
const handleNameChange = useCallback((value) => {
|
|
1887
2651
|
setFullName(value);
|
|
1888
2652
|
onFullNameChange?.(value);
|
|
@@ -2183,24 +2947,75 @@ function SplitCardFormInner({
|
|
|
2183
2947
|
}
|
|
2184
2948
|
}
|
|
2185
2949
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
2950
|
+
const stripeResumeAttemptedRef = useRef3(false);
|
|
2186
2951
|
useEffect4(() => {
|
|
2187
|
-
if (typeof window === "undefined") return;
|
|
2188
|
-
const
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2952
|
+
if (typeof window === "undefined" || stripeResumeAttemptedRef.current) return;
|
|
2953
|
+
const params = new URLSearchParams(window.location.search);
|
|
2954
|
+
const paymentIntentId = params.get("payment_intent");
|
|
2955
|
+
const clientSecret = params.get("payment_intent_client_secret");
|
|
2956
|
+
const redirectStatus = params.get("redirect_status");
|
|
2957
|
+
if (!paymentIntentId || !clientSecret) return;
|
|
2958
|
+
const readPayload = (key) => {
|
|
2959
|
+
const raw = localStorage.getItem(key);
|
|
2960
|
+
if (!raw) return null;
|
|
2961
|
+
try {
|
|
2962
|
+
return JSON.parse(raw);
|
|
2963
|
+
} catch {
|
|
2964
|
+
localStorage.removeItem(key);
|
|
2965
|
+
return null;
|
|
2199
2966
|
}
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2967
|
+
};
|
|
2968
|
+
const payload = readPayload(STRIPE_RESUME_KEY) ?? readPayload(LEGACY_WALLET_RESUME_KEY);
|
|
2969
|
+
if (payload?.sessionId && payload.sessionId !== sessionId) return;
|
|
2970
|
+
stripeResumeAttemptedRef.current = true;
|
|
2971
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2972
|
+
localStorage.removeItem(LEGACY_WALLET_RESUME_KEY);
|
|
2973
|
+
const cleanedUrl = new URL(window.location.href);
|
|
2974
|
+
cleanedUrl.searchParams.delete("payment_intent");
|
|
2975
|
+
cleanedUrl.searchParams.delete("payment_intent_client_secret");
|
|
2976
|
+
cleanedUrl.searchParams.delete("redirect_status");
|
|
2977
|
+
window.history.replaceState({}, "", cleanedUrl.toString());
|
|
2978
|
+
const paymentMethodType = payload?.paymentMethodType ?? payload?.tokenType ?? "card";
|
|
2979
|
+
const declineMethod = "card";
|
|
2980
|
+
(async () => {
|
|
2981
|
+
const rawProvider = flopay?.getRawProvider();
|
|
2982
|
+
if (!rawProvider) {
|
|
2983
|
+
const message = "Payment is not available \u2014 please refresh and try again.";
|
|
2984
|
+
updateError(message);
|
|
2985
|
+
emitDecline(declineMethod, message);
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2988
|
+
if (redirectStatus === "failed") {
|
|
2989
|
+
const message = "Payment was declined. Please try again.";
|
|
2990
|
+
updateError(message);
|
|
2991
|
+
emitDecline(declineMethod, message);
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
const { paymentIntent, error: error2 } = await rawProvider.retrievePaymentIntent(clientSecret);
|
|
2995
|
+
if (error2) {
|
|
2996
|
+
const message = error2.message ?? "Failed to retrieve payment status.";
|
|
2997
|
+
updateError(message);
|
|
2998
|
+
emitDecline(declineMethod, message, { code: error2.code });
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
3001
|
+
const piStatus = paymentIntent?.status;
|
|
3002
|
+
const successful = piStatus === "succeeded" || piStatus === "requires_capture" || piStatus === "processing";
|
|
3003
|
+
if (!paymentIntent || !successful) {
|
|
3004
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
3005
|
+
updateError(message);
|
|
3006
|
+
emitDecline(declineMethod, message, { code: piStatus ?? "missing_payment_intent" });
|
|
3007
|
+
return;
|
|
3008
|
+
}
|
|
3009
|
+
const resolvedPmId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
3010
|
+
dispatchTokenizedBody({
|
|
3011
|
+
id: resolvedPmId ?? payload?.paymentMethodId ?? payload?.tokenId ?? paymentIntent.id,
|
|
3012
|
+
type: "card",
|
|
3013
|
+
threeDSecureActionResultTokenId: paymentIntent.id,
|
|
3014
|
+
gateway: payload?.gateway ?? "stripe",
|
|
3015
|
+
paymentMethodType
|
|
3016
|
+
});
|
|
3017
|
+
})();
|
|
3018
|
+
}, [sessionId, dispatchTokenizedBody, flopay, updateError, emitDecline]);
|
|
2204
3019
|
const handleSubmit = useCallback(
|
|
2205
3020
|
async (e) => {
|
|
2206
3021
|
e.preventDefault();
|
|
@@ -2483,17 +3298,23 @@ function SplitCardFormInner({
|
|
|
2483
3298
|
/* @__PURE__ */ jsx6("div", { style: {
|
|
2484
3299
|
flex: 1,
|
|
2485
3300
|
backgroundColor: cardInputBg,
|
|
2486
|
-
|
|
3301
|
+
// Longhand only — mixing `border` shorthand with per-side
|
|
3302
|
+
// overrides triggers React's "shorthand vs longhand" warning
|
|
3303
|
+
// because render order isn't deterministic.
|
|
2487
3304
|
borderTop: "none",
|
|
2488
3305
|
borderRight: "none",
|
|
3306
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3307
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2489
3308
|
borderBottomLeftRadius: "8px",
|
|
2490
3309
|
padding: "10px"
|
|
2491
3310
|
}, children: /* @__PURE__ */ jsx6(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
2492
3311
|
/* @__PURE__ */ jsx6("div", { style: {
|
|
2493
3312
|
flex: 1,
|
|
2494
3313
|
backgroundColor: cardInputBg,
|
|
2495
|
-
border: `1px solid ${resolvedBorder}`,
|
|
2496
3314
|
borderTop: "none",
|
|
3315
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3316
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3317
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2497
3318
|
borderBottomRightRadius: "8px",
|
|
2498
3319
|
padding: "10px"
|
|
2499
3320
|
}, children: /* @__PURE__ */ jsx6(CardCvcElement, { options: stripeElementStyle }) })
|
|
@@ -2585,7 +3406,10 @@ function SplitCardFormInner({
|
|
|
2585
3406
|
isAVSFieldVisible(avsConfig.city, cc) && /* @__PURE__ */ jsx6("div", { style: {
|
|
2586
3407
|
flex: 1,
|
|
2587
3408
|
backgroundColor: cardInputBg,
|
|
2588
|
-
|
|
3409
|
+
borderTop: `1px solid ${resolvedBorder}`,
|
|
3410
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3411
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3412
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2589
3413
|
padding: "10px",
|
|
2590
3414
|
borderTopLeftRadius: "8px",
|
|
2591
3415
|
borderBottomLeftRadius: "8px",
|
|
@@ -2662,7 +3486,10 @@ function SplitCardFormInner({
|
|
|
2662
3486
|
isAVSFieldVisible(avsConfig.country, cc) && /* @__PURE__ */ jsx6("div", { style: {
|
|
2663
3487
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2664
3488
|
backgroundColor: cardInputBg,
|
|
2665
|
-
|
|
3489
|
+
borderTop: `1px solid ${resolvedBorder}`,
|
|
3490
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3491
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3492
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2666
3493
|
padding: "10px",
|
|
2667
3494
|
...avsLayoutProp === "row" && isAVSFieldVisible(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
|
|
2668
3495
|
...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
|
|
@@ -2757,221 +3584,465 @@ function SplitCardFormInner({
|
|
|
2757
3584
|
}
|
|
2758
3585
|
)
|
|
2759
3586
|
] });
|
|
3587
|
+
const gateDebugStyle = {
|
|
3588
|
+
margin: 0,
|
|
3589
|
+
padding: "6px 8px",
|
|
3590
|
+
background: "#eef2ff",
|
|
3591
|
+
border: "1px solid #c7d2fe",
|
|
3592
|
+
borderRadius: 6,
|
|
3593
|
+
color: "#111827",
|
|
3594
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
3595
|
+
whiteSpace: "pre-wrap",
|
|
3596
|
+
wordBreak: "break-word"
|
|
3597
|
+
};
|
|
3598
|
+
const renderDirectPaypalGateDebug = (testId) => {
|
|
3599
|
+
if (!debug) return null;
|
|
3600
|
+
if (!showPayPal || !directPaypalConfigured) {
|
|
3601
|
+
return /* @__PURE__ */ jsx6("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/DirectPayPal-debug - not enabled" });
|
|
3602
|
+
}
|
|
3603
|
+
return /* @__PURE__ */ jsx6("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3604
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
3605
|
+
` showPayPal=${showPayPal}`,
|
|
3606
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
3607
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
3608
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
3609
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
3610
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
3611
|
+
].join("\n") });
|
|
3612
|
+
};
|
|
3613
|
+
const renderStripeGateDebug = (testId) => {
|
|
3614
|
+
if (!debug) return null;
|
|
3615
|
+
if (!showStripe || !stripeInstance) {
|
|
3616
|
+
return /* @__PURE__ */ jsx6("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/Stripe-debug - not enabled" });
|
|
3617
|
+
}
|
|
3618
|
+
return /* @__PURE__ */ jsx6("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3619
|
+
"FloPay/Stripe-debug (parent gate)",
|
|
3620
|
+
` showStripe=${showStripe}`,
|
|
3621
|
+
` currency=${currency}`,
|
|
3622
|
+
` amountInCents=${amountInCents}`,
|
|
3623
|
+
` enabledPaymentMethods: ${JSON.stringify(enabledPaymentMethods ?? [])}`,
|
|
3624
|
+
` enabledPaymentMethodsProvided=${hasEnabledMethodsPayload}`,
|
|
3625
|
+
` hasEnabledMethods=${hasEnabledMethods}`,
|
|
3626
|
+
` expressMethods: ${JSON.stringify(expressMethods)}`,
|
|
3627
|
+
` walletExpressMethods: ${JSON.stringify(walletExpressMethods)}`,
|
|
3628
|
+
` paymentElementMethods: ${JSON.stringify(paymentElementMethods)}`,
|
|
3629
|
+
` paymentElementMethodsForCurrency: ${JSON.stringify(paymentElementMethodsForCurrency)}`,
|
|
3630
|
+
` hasStripeInstance=${!!stripeInstance}`,
|
|
3631
|
+
` shouldRenderWallets=${shouldRenderWallets}`,
|
|
3632
|
+
` shouldRenderPaymentElement=${shouldRenderPaymentElement}`
|
|
3633
|
+
].join("\n") });
|
|
3634
|
+
};
|
|
3635
|
+
const isApmView = viewState === "apm-expanding" || viewState === "apm-form" || viewState === "apm-collapsing";
|
|
3636
|
+
const apmAnim = viewState === "apm-expanding" ? `flopay-card-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : viewState === "apm-collapsing" ? `flopay-card-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : void 0;
|
|
3637
|
+
const apmInlineOptions = expandedApmMethod ? {
|
|
3638
|
+
...paymentElementBaseOptions,
|
|
3639
|
+
paymentMethodTypes: [expandedApmMethod]
|
|
3640
|
+
} : null;
|
|
2760
3641
|
if (layout === "buttons") {
|
|
2761
|
-
const isButtonsView = viewState === "buttons" || viewState === "expanding";
|
|
3642
|
+
const isButtonsView = viewState === "buttons" || viewState === "expanding" || viewState === "apm-expanding";
|
|
2762
3643
|
const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
|
|
2763
3644
|
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2764
|
-
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;
|
|
3645
|
+
const buttonsAnim = viewState === "expanding" || viewState === "apm-expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" || viewState === "apm-collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
|
|
2765
3646
|
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;
|
|
2766
3647
|
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2767
3648
|
/* @__PURE__ */ jsx6(FloPayKeyframes, {}),
|
|
2768
3649
|
overlayStatus && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2769
3650
|
/* @__PURE__ */ jsxs4("div", { style: { display: "grid" }, children: [
|
|
2770
|
-
/* @__PURE__ */ jsxs4(
|
|
3651
|
+
/* @__PURE__ */ jsxs4(
|
|
3652
|
+
"div",
|
|
3653
|
+
{
|
|
3654
|
+
"data-testid": "flopay-buttons-panel",
|
|
3655
|
+
"aria-hidden": !isButtonsView && !buttonsAnim ? true : void 0,
|
|
3656
|
+
style: {
|
|
3657
|
+
gridArea: "1 / 1",
|
|
3658
|
+
display: "flex",
|
|
3659
|
+
flexDirection: "column",
|
|
3660
|
+
gap: "0.5rem",
|
|
3661
|
+
// When card form is showing (and not transitioning), hide but keep mounted.
|
|
3662
|
+
...!isButtonsView && !buttonsAnim ? BUTTONS_PANEL_HIDDEN_STYLE : {},
|
|
3663
|
+
...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
|
|
3664
|
+
},
|
|
3665
|
+
children: [
|
|
3666
|
+
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug"),
|
|
3667
|
+
renderStripeGateDebug("flopay-stripe-gate-debug"),
|
|
3668
|
+
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3669
|
+
paypalDirectRetry && /* @__PURE__ */ jsx6(
|
|
3670
|
+
"div",
|
|
3671
|
+
{
|
|
3672
|
+
"data-testid": "flopay-paypal-direct-retry-notice",
|
|
3673
|
+
style: {
|
|
3674
|
+
padding: "8px 10px",
|
|
3675
|
+
background: "#fef3c7",
|
|
3676
|
+
border: "1px solid #fcd34d",
|
|
3677
|
+
borderRadius: 6,
|
|
3678
|
+
color: "#78350f",
|
|
3679
|
+
fontSize: 13,
|
|
3680
|
+
lineHeight: 1.4
|
|
3681
|
+
},
|
|
3682
|
+
children: "Please confirm your PayPal payment to complete checkout."
|
|
3683
|
+
}
|
|
3684
|
+
),
|
|
3685
|
+
/* @__PURE__ */ jsx6(
|
|
3686
|
+
DirectPayPalButton,
|
|
3687
|
+
{
|
|
3688
|
+
sessionId,
|
|
3689
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3690
|
+
email: resolvedAccount.email,
|
|
3691
|
+
clientId: directPaypal.clientId,
|
|
3692
|
+
environment: directPaypal.environment,
|
|
3693
|
+
currency: currency.toUpperCase(),
|
|
3694
|
+
isSubscription,
|
|
3695
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3696
|
+
onComplete,
|
|
3697
|
+
onErrorChange: updateError,
|
|
3698
|
+
onDecline,
|
|
3699
|
+
onButtonClick,
|
|
3700
|
+
runBeforeButtonClick,
|
|
3701
|
+
isProcessing: isSubmitting,
|
|
3702
|
+
onLoadStateChange: setDirectPaypalReady,
|
|
3703
|
+
session: session ?? null,
|
|
3704
|
+
existingOrderId: paypalDirectRetry?.orderId,
|
|
3705
|
+
debug
|
|
3706
|
+
},
|
|
3707
|
+
paypalDirectRetry?.orderId ?? "fresh"
|
|
3708
|
+
)
|
|
3709
|
+
] }),
|
|
3710
|
+
shouldRenderStripePayPal && /* @__PURE__ */ jsx6(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx6(
|
|
3711
|
+
PayPalButtonInner,
|
|
3712
|
+
{
|
|
3713
|
+
sessionId,
|
|
3714
|
+
email: resolvedAccount.email,
|
|
3715
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3716
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3717
|
+
onErrorChange: updateError,
|
|
3718
|
+
isProcessing: isSubmitting,
|
|
3719
|
+
onButtonClick,
|
|
3720
|
+
onDecline,
|
|
3721
|
+
runBeforeButtonClick,
|
|
3722
|
+
onLoadStateChange: setPaypalLoadState,
|
|
3723
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
3724
|
+
}
|
|
3725
|
+
) }),
|
|
3726
|
+
shouldRenderWallets ? /* @__PURE__ */ jsx6(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx6(
|
|
3727
|
+
WalletButtonInner,
|
|
3728
|
+
{
|
|
3729
|
+
sessionId,
|
|
3730
|
+
email: resolvedAccount.email,
|
|
3731
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3732
|
+
expressMethods: walletExpressMethods,
|
|
3733
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3734
|
+
onErrorChange: updateError,
|
|
3735
|
+
onButtonClick,
|
|
3736
|
+
onDecline,
|
|
3737
|
+
runBeforeButtonClick,
|
|
3738
|
+
onLoadStateChange: setWalletLoadState,
|
|
3739
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
3740
|
+
}
|
|
3741
|
+
) }) : shouldShowWallets ? /* @__PURE__ */ jsx6("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
3742
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx6(
|
|
3743
|
+
StripePaymentElementInner,
|
|
3744
|
+
{
|
|
3745
|
+
sessionId,
|
|
3746
|
+
email: resolvedAccount.email,
|
|
3747
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
3748
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3749
|
+
paymentElementMethods: paymentElementMethodsForCurrency,
|
|
3750
|
+
stripeInstance,
|
|
3751
|
+
paymentElementBaseOptions,
|
|
3752
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3753
|
+
onErrorChange: updateError,
|
|
3754
|
+
onButtonClick,
|
|
3755
|
+
onDecline,
|
|
3756
|
+
runBeforeButtonClick,
|
|
3757
|
+
onLoadStateChange: setPaymentElementLoadState,
|
|
3758
|
+
isProcessing: isSubmitting,
|
|
3759
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
3760
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
3761
|
+
submitButtonStyle: bStyles.submitButton,
|
|
3762
|
+
onExpandApm: expandToApm,
|
|
3763
|
+
expandedApmMethod,
|
|
3764
|
+
themeId: theme,
|
|
3765
|
+
buttonAppearance: {
|
|
3766
|
+
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
3767
|
+
borderColor: bStyles.cardInputBorder,
|
|
3768
|
+
textColor: bStyles.cardButton?.color,
|
|
3769
|
+
borderRadius: bStyles.cardButton?.borderRadius
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
),
|
|
3773
|
+
showStripe && /* @__PURE__ */ jsx6(
|
|
3774
|
+
"button",
|
|
3775
|
+
{
|
|
3776
|
+
type: "button",
|
|
3777
|
+
onClick: async () => {
|
|
3778
|
+
if (isSubmitting) return;
|
|
3779
|
+
const beforeClick = await runBeforeButtonClick("card");
|
|
3780
|
+
if (!beforeClick.proceed) return;
|
|
3781
|
+
onButtonClick?.("card");
|
|
3782
|
+
expandToCard();
|
|
3783
|
+
},
|
|
3784
|
+
disabled: isSubmitting,
|
|
3785
|
+
style: {
|
|
3786
|
+
width: "100%",
|
|
3787
|
+
...cardButtonSizing,
|
|
3788
|
+
// `bStyles.cardButton` first — supplies the bundle's
|
|
3789
|
+
// padding / typography / border-radius — then the
|
|
3790
|
+
// primary surface overrides on top, so the card button
|
|
3791
|
+
// ends up wearing the *submit* button's colours rather
|
|
3792
|
+
// than the bundle's neutral white-tile `cardButton`
|
|
3793
|
+
// colours. Without this order flip, every non-classic
|
|
3794
|
+
// bundle's `cardButton.backgroundColor` was winning
|
|
3795
|
+
// over the primary fill we just derived above it.
|
|
3796
|
+
...bStyles.cardButton,
|
|
3797
|
+
...derivePrimaryTileStyle({
|
|
3798
|
+
themeBundle,
|
|
3799
|
+
resolvedPrimaryColor,
|
|
3800
|
+
resolvedBorderRadius,
|
|
3801
|
+
submitButtonStyle: bStyles.submitButton
|
|
3802
|
+
}),
|
|
3803
|
+
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
3804
|
+
fontWeight: 600,
|
|
3805
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
3806
|
+
display: "flex",
|
|
3807
|
+
alignItems: "center",
|
|
3808
|
+
justifyContent: "center",
|
|
3809
|
+
gap: "0.625rem",
|
|
3810
|
+
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
3811
|
+
position: "relative",
|
|
3812
|
+
opacity: isSubmitting ? 0.6 : 1
|
|
3813
|
+
},
|
|
3814
|
+
onMouseDown: (e) => {
|
|
3815
|
+
e.currentTarget.style.transform = "scale(0.985)";
|
|
3816
|
+
},
|
|
3817
|
+
onMouseUp: (e) => {
|
|
3818
|
+
e.currentTarget.style.transform = "scale(1)";
|
|
3819
|
+
},
|
|
3820
|
+
children: /* @__PURE__ */ jsx6(CardButtonContentSlot, { content: cardButtonContent })
|
|
3821
|
+
}
|
|
3822
|
+
),
|
|
3823
|
+
displayError && viewState === "buttons" && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
|
|
3824
|
+
margin: "0.25rem 0",
|
|
3825
|
+
padding: "0.625rem 0.875rem",
|
|
3826
|
+
background: "#FEF2F2",
|
|
3827
|
+
border: "1px solid #FECACA",
|
|
3828
|
+
borderRadius: "8px",
|
|
3829
|
+
color: "#991B1B",
|
|
3830
|
+
fontSize: "0.85rem",
|
|
3831
|
+
fontWeight: 600,
|
|
3832
|
+
display: "flex",
|
|
3833
|
+
alignItems: "center",
|
|
3834
|
+
gap: "0.5rem",
|
|
3835
|
+
...bStyles.errorBanner ? bStyles.errorBanner : {}
|
|
3836
|
+
}, children: [
|
|
3837
|
+
/* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx6("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
3838
|
+
displayError
|
|
3839
|
+
] })
|
|
3840
|
+
]
|
|
3841
|
+
}
|
|
3842
|
+
),
|
|
3843
|
+
showStripe && isCardView && /* @__PURE__ */ jsx6("div", { style: {
|
|
2771
3844
|
gridArea: "1 / 1",
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
...
|
|
3845
|
+
...cardAnim ? { animation: cardAnim } : {},
|
|
3846
|
+
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
3847
|
+
}, children: cardFormBlock }),
|
|
3848
|
+
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */ jsx6("div", { style: {
|
|
3849
|
+
gridArea: "1 / 1",
|
|
3850
|
+
...apmAnim ? { animation: apmAnim } : {},
|
|
3851
|
+
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
3852
|
+
}, children: /* @__PURE__ */ jsxs4("div", { style: {
|
|
3853
|
+
backgroundColor: cardBg,
|
|
3854
|
+
borderRadius: containerRadius,
|
|
3855
|
+
...containerOverrides,
|
|
3856
|
+
padding: containerPadding
|
|
2778
3857
|
}, children: [
|
|
2779
|
-
|
|
2780
|
-
"
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
background: "#eef2ff",
|
|
2787
|
-
border: "1px solid #c7d2fe",
|
|
2788
|
-
borderRadius: 6,
|
|
2789
|
-
color: "#111827",
|
|
2790
|
-
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2791
|
-
whiteSpace: "pre-wrap",
|
|
2792
|
-
wordBreak: "break-word"
|
|
2793
|
-
},
|
|
2794
|
-
children: [
|
|
2795
|
-
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2796
|
-
` showPayPal=${showPayPal}`,
|
|
2797
|
-
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2798
|
-
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2799
|
-
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2800
|
-
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2801
|
-
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2802
|
-
].join("\n")
|
|
2803
|
-
}
|
|
2804
|
-
),
|
|
2805
|
-
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2806
|
-
paypalDirectRetry && /* @__PURE__ */ jsx6(
|
|
2807
|
-
"div",
|
|
3858
|
+
/* @__PURE__ */ jsxs4("div", { style: {
|
|
3859
|
+
display: "flex",
|
|
3860
|
+
alignItems: "center",
|
|
3861
|
+
padding: "0.75rem 0 0.625rem"
|
|
3862
|
+
}, children: [
|
|
3863
|
+
/* @__PURE__ */ jsxs4(
|
|
3864
|
+
"button",
|
|
2808
3865
|
{
|
|
2809
|
-
|
|
3866
|
+
type: "button",
|
|
3867
|
+
"data-testid": "flopay-apm-back-button",
|
|
3868
|
+
onClick: collapseFromApm,
|
|
2810
3869
|
style: {
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
3870
|
+
display: "inline-flex",
|
|
3871
|
+
alignItems: "center",
|
|
3872
|
+
gap: hideBackButtonLabel ? 0 : "0.5rem",
|
|
3873
|
+
background: "none",
|
|
3874
|
+
border: "none",
|
|
3875
|
+
cursor: "pointer",
|
|
3876
|
+
color: "#4b5563",
|
|
3877
|
+
fontSize: bStyles.backButtonFontSize ?? "0.85rem",
|
|
3878
|
+
fontWeight: 500,
|
|
3879
|
+
padding: 0,
|
|
3880
|
+
transition: "color 0.15s",
|
|
3881
|
+
flexShrink: 0,
|
|
3882
|
+
...bStyles.backButton
|
|
2818
3883
|
},
|
|
2819
|
-
|
|
3884
|
+
"aria-label": "Back to payment methods",
|
|
3885
|
+
children: [
|
|
3886
|
+
/* @__PURE__ */ jsx6("span", { style: {
|
|
3887
|
+
display: "inline-flex",
|
|
3888
|
+
alignItems: "center",
|
|
3889
|
+
justifyContent: "center",
|
|
3890
|
+
width: 28,
|
|
3891
|
+
height: 28,
|
|
3892
|
+
borderRadius: "50%",
|
|
3893
|
+
backgroundColor: "#f3f4f6",
|
|
3894
|
+
transition: "background-color 0.15s",
|
|
3895
|
+
...bStyles.backButtonIcon
|
|
3896
|
+
}, children: /* @__PURE__ */ jsx6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx6("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
3897
|
+
/* @__PURE__ */ jsx6(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3898
|
+
]
|
|
2820
3899
|
}
|
|
2821
3900
|
),
|
|
2822
|
-
/* @__PURE__ */ jsx6(
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
isSubscription,
|
|
2832
|
-
onTokenizedBody: dispatchTokenizedBody,
|
|
2833
|
-
onComplete,
|
|
2834
|
-
onErrorChange: updateError,
|
|
2835
|
-
onDecline,
|
|
2836
|
-
onButtonClick,
|
|
2837
|
-
runBeforeButtonClick,
|
|
2838
|
-
isProcessing: isSubmitting,
|
|
2839
|
-
onLoadStateChange: setDirectPaypalReady,
|
|
2840
|
-
session: session ?? null,
|
|
2841
|
-
existingOrderId: paypalDirectRetry?.orderId,
|
|
2842
|
-
debug
|
|
2843
|
-
},
|
|
2844
|
-
paypalDirectRetry?.orderId ?? "fresh"
|
|
2845
|
-
)
|
|
3901
|
+
/* @__PURE__ */ jsx6("div", { style: {
|
|
3902
|
+
flex: 1,
|
|
3903
|
+
textAlign: "center",
|
|
3904
|
+
fontWeight: 600,
|
|
3905
|
+
fontSize: bStyles.titleFontSize ?? "1.05rem",
|
|
3906
|
+
color: resolvedTitleColor,
|
|
3907
|
+
paddingRight: 80,
|
|
3908
|
+
...bStyles.title
|
|
3909
|
+
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
2846
3910
|
] }),
|
|
2847
|
-
shouldRenderStripePayPal && /* @__PURE__ */ jsx6(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx6(
|
|
2848
|
-
PayPalButtonInner,
|
|
2849
|
-
{
|
|
2850
|
-
sessionId,
|
|
2851
|
-
email: resolvedAccount.email,
|
|
2852
|
-
billingApiUrl: resolvedBillingApiUrl,
|
|
2853
|
-
onTokenizedBody: dispatchTokenizedBody,
|
|
2854
|
-
onErrorChange: updateError,
|
|
2855
|
-
isProcessing: isSubmitting,
|
|
2856
|
-
onButtonClick,
|
|
2857
|
-
onDecline,
|
|
2858
|
-
runBeforeButtonClick,
|
|
2859
|
-
onLoadStateChange: setPaypalLoadState
|
|
2860
|
-
}
|
|
2861
|
-
) }),
|
|
2862
|
-
shouldRenderWallets ? /* @__PURE__ */ jsx6(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx6(
|
|
2863
|
-
WalletButtonInner,
|
|
2864
|
-
{
|
|
2865
|
-
sessionId,
|
|
2866
|
-
email: resolvedAccount.email,
|
|
2867
|
-
billingApiUrl: resolvedBillingApiUrl,
|
|
2868
|
-
showApplePay,
|
|
2869
|
-
showGooglePay,
|
|
2870
|
-
onTokenizedBody: dispatchTokenizedBody,
|
|
2871
|
-
onErrorChange: updateError,
|
|
2872
|
-
onButtonClick,
|
|
2873
|
-
onDecline,
|
|
2874
|
-
runBeforeButtonClick,
|
|
2875
|
-
onLoadStateChange: setWalletLoadState
|
|
2876
|
-
}
|
|
2877
|
-
) }) : shouldShowWallets ? /* @__PURE__ */ jsx6("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
|
|
2878
3911
|
/* @__PURE__ */ jsx6(
|
|
3912
|
+
StripeElements,
|
|
3913
|
+
{
|
|
3914
|
+
stripe: stripeInstance,
|
|
3915
|
+
options: apmInlineOptions,
|
|
3916
|
+
children: /* @__PURE__ */ jsx6(
|
|
3917
|
+
StripeMethodInlineForm,
|
|
3918
|
+
{
|
|
3919
|
+
method: expandedApmMethod,
|
|
3920
|
+
sessionId,
|
|
3921
|
+
email: resolvedAccount.email,
|
|
3922
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
3923
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3924
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3925
|
+
onErrorChange: updateError,
|
|
3926
|
+
onDecline,
|
|
3927
|
+
onCancel: collapseFromApm,
|
|
3928
|
+
runBeforeButtonClick,
|
|
3929
|
+
onButtonClick,
|
|
3930
|
+
isProcessing: isSubmitting,
|
|
3931
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
3932
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
3933
|
+
submitButtonStyle: bStyles.submitButton
|
|
3934
|
+
}
|
|
3935
|
+
)
|
|
3936
|
+
},
|
|
3937
|
+
expandedApmMethod
|
|
3938
|
+
)
|
|
3939
|
+
] }) })
|
|
3940
|
+
] })
|
|
3941
|
+
] });
|
|
3942
|
+
}
|
|
3943
|
+
if (isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && showStripe) {
|
|
3944
|
+
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
3945
|
+
/* @__PURE__ */ jsx6(FloPayKeyframes, {}),
|
|
3946
|
+
overlayStatus && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
3947
|
+
/* @__PURE__ */ jsx6("div", { style: {
|
|
3948
|
+
...apmAnim ? { animation: apmAnim } : {},
|
|
3949
|
+
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
3950
|
+
}, children: /* @__PURE__ */ jsxs4("div", { style: {
|
|
3951
|
+
backgroundColor: cardBg,
|
|
3952
|
+
borderRadius: containerRadius,
|
|
3953
|
+
...containerOverrides,
|
|
3954
|
+
padding: containerPadding
|
|
3955
|
+
}, children: [
|
|
3956
|
+
/* @__PURE__ */ jsxs4("div", { style: {
|
|
3957
|
+
display: "flex",
|
|
3958
|
+
alignItems: "center",
|
|
3959
|
+
padding: "0.75rem 0 0.625rem"
|
|
3960
|
+
}, children: [
|
|
3961
|
+
/* @__PURE__ */ jsxs4(
|
|
2879
3962
|
"button",
|
|
2880
3963
|
{
|
|
2881
3964
|
type: "button",
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
const beforeClick = await runBeforeButtonClick("card");
|
|
2885
|
-
if (!beforeClick.proceed) return;
|
|
2886
|
-
onButtonClick?.("card");
|
|
2887
|
-
expandToCard();
|
|
2888
|
-
},
|
|
2889
|
-
disabled: isSubmitting,
|
|
3965
|
+
"data-testid": "flopay-apm-back-button-default",
|
|
3966
|
+
onClick: collapseFromApm,
|
|
2890
3967
|
style: {
|
|
2891
|
-
|
|
2892
|
-
...cardButtonSizing,
|
|
2893
|
-
backgroundColor: "white",
|
|
2894
|
-
color: "#262833",
|
|
2895
|
-
border: "1px solid #d1d5db",
|
|
2896
|
-
borderRadius: "8px",
|
|
2897
|
-
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
2898
|
-
fontWeight: 600,
|
|
2899
|
-
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
2900
|
-
display: "flex",
|
|
3968
|
+
display: "inline-flex",
|
|
2901
3969
|
alignItems: "center",
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3970
|
+
gap: hideBackButtonLabel ? 0 : "0.5rem",
|
|
3971
|
+
background: "none",
|
|
3972
|
+
border: "none",
|
|
3973
|
+
cursor: "pointer",
|
|
3974
|
+
color: "#4b5563",
|
|
3975
|
+
fontSize: bStyles.backButtonFontSize ?? "0.85rem",
|
|
3976
|
+
fontWeight: 500,
|
|
3977
|
+
padding: 0,
|
|
3978
|
+
transition: "color 0.15s",
|
|
3979
|
+
flexShrink: 0,
|
|
3980
|
+
...bStyles.backButton
|
|
2909
3981
|
},
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
3982
|
+
"aria-label": "Back to payment methods",
|
|
3983
|
+
children: [
|
|
3984
|
+
/* @__PURE__ */ jsx6("span", { style: {
|
|
3985
|
+
display: "inline-flex",
|
|
3986
|
+
alignItems: "center",
|
|
3987
|
+
justifyContent: "center",
|
|
3988
|
+
width: 28,
|
|
3989
|
+
height: 28,
|
|
3990
|
+
borderRadius: "50%",
|
|
3991
|
+
backgroundColor: "#f3f4f6",
|
|
3992
|
+
transition: "background-color 0.15s",
|
|
3993
|
+
...bStyles.backButtonIcon
|
|
3994
|
+
}, children: /* @__PURE__ */ jsx6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx6("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
3995
|
+
/* @__PURE__ */ jsx6(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3996
|
+
]
|
|
2917
3997
|
}
|
|
2918
3998
|
),
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
background: "#FEF2F2",
|
|
2923
|
-
border: "1px solid #FECACA",
|
|
2924
|
-
borderRadius: "8px",
|
|
2925
|
-
color: "#991B1B",
|
|
2926
|
-
fontSize: "0.85rem",
|
|
3999
|
+
/* @__PURE__ */ jsx6("div", { style: {
|
|
4000
|
+
flex: 1,
|
|
4001
|
+
textAlign: "center",
|
|
2927
4002
|
fontWeight: 600,
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
...bStyles.
|
|
2932
|
-
}, children:
|
|
2933
|
-
/* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx6("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
2934
|
-
displayError
|
|
2935
|
-
] })
|
|
4003
|
+
fontSize: bStyles.titleFontSize ?? "1.05rem",
|
|
4004
|
+
color: resolvedTitleColor,
|
|
4005
|
+
paddingRight: 80,
|
|
4006
|
+
...bStyles.title
|
|
4007
|
+
}, children: `Pay with ${getStripeMethodDisplayName(expandedApmMethod)}` })
|
|
2936
4008
|
] }),
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
4009
|
+
/* @__PURE__ */ jsx6(
|
|
4010
|
+
StripeElements,
|
|
4011
|
+
{
|
|
4012
|
+
stripe: stripeInstance,
|
|
4013
|
+
options: apmInlineOptions,
|
|
4014
|
+
children: /* @__PURE__ */ jsx6(
|
|
4015
|
+
StripeMethodInlineForm,
|
|
4016
|
+
{
|
|
4017
|
+
method: expandedApmMethod,
|
|
4018
|
+
sessionId,
|
|
4019
|
+
email: resolvedAccount.email,
|
|
4020
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
4021
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
4022
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
4023
|
+
onErrorChange: updateError,
|
|
4024
|
+
onDecline,
|
|
4025
|
+
onCancel: collapseFromApm,
|
|
4026
|
+
runBeforeButtonClick,
|
|
4027
|
+
onButtonClick,
|
|
4028
|
+
isProcessing: isSubmitting,
|
|
4029
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
4030
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4031
|
+
submitButtonStyle: bStyles.submitButton
|
|
4032
|
+
}
|
|
4033
|
+
)
|
|
4034
|
+
},
|
|
4035
|
+
expandedApmMethod
|
|
4036
|
+
)
|
|
4037
|
+
] }) })
|
|
2943
4038
|
] });
|
|
2944
4039
|
}
|
|
2945
4040
|
return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2946
4041
|
/* @__PURE__ */ jsx6(FloPayKeyframes, {}),
|
|
2947
4042
|
overlayStatus && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
2948
4043
|
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2949
|
-
debug
|
|
2950
|
-
|
|
2951
|
-
{
|
|
2952
|
-
"data-testid": "flopay-direct-paypal-gate-debug-default",
|
|
2953
|
-
style: {
|
|
2954
|
-
margin: 0,
|
|
2955
|
-
padding: "6px 8px",
|
|
2956
|
-
background: "#eef2ff",
|
|
2957
|
-
border: "1px solid #c7d2fe",
|
|
2958
|
-
borderRadius: 6,
|
|
2959
|
-
color: "#111827",
|
|
2960
|
-
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2961
|
-
whiteSpace: "pre-wrap",
|
|
2962
|
-
wordBreak: "break-word"
|
|
2963
|
-
},
|
|
2964
|
-
children: [
|
|
2965
|
-
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2966
|
-
` showPayPal=${showPayPal}`,
|
|
2967
|
-
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2968
|
-
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2969
|
-
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2970
|
-
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2971
|
-
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2972
|
-
].join("\n")
|
|
2973
|
-
}
|
|
2974
|
-
),
|
|
4044
|
+
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug-default"),
|
|
4045
|
+
renderStripeGateDebug("flopay-stripe-gate-debug-default"),
|
|
2975
4046
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2976
4047
|
paypalDirectRetry && /* @__PURE__ */ jsx6(
|
|
2977
4048
|
"div",
|
|
@@ -3026,7 +4097,8 @@ function SplitCardFormInner({
|
|
|
3026
4097
|
onButtonClick,
|
|
3027
4098
|
onDecline,
|
|
3028
4099
|
runBeforeButtonClick,
|
|
3029
|
-
onLoadStateChange: setPaypalLoadState
|
|
4100
|
+
onLoadStateChange: setPaypalLoadState,
|
|
4101
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
3030
4102
|
}
|
|
3031
4103
|
) }),
|
|
3032
4104
|
shouldRenderWallets && /* @__PURE__ */ jsx6(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx6(
|
|
@@ -3035,18 +4107,49 @@ function SplitCardFormInner({
|
|
|
3035
4107
|
sessionId,
|
|
3036
4108
|
email: resolvedAccount.email,
|
|
3037
4109
|
billingApiUrl: resolvedBillingApiUrl,
|
|
3038
|
-
|
|
3039
|
-
|
|
4110
|
+
expressMethods: walletExpressMethods,
|
|
4111
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
4112
|
+
onErrorChange: updateError,
|
|
4113
|
+
onButtonClick,
|
|
4114
|
+
onDecline,
|
|
4115
|
+
runBeforeButtonClick,
|
|
4116
|
+
onLoadStateChange: setWalletLoadState,
|
|
4117
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
4118
|
+
}
|
|
4119
|
+
) }),
|
|
4120
|
+
shouldRenderPaymentElement && /* @__PURE__ */ jsx6(
|
|
4121
|
+
StripePaymentElementInner,
|
|
4122
|
+
{
|
|
4123
|
+
sessionId,
|
|
4124
|
+
email: resolvedAccount.email,
|
|
4125
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
4126
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
4127
|
+
paymentElementMethods: paymentElementMethodsForCurrency,
|
|
4128
|
+
stripeInstance,
|
|
4129
|
+
paymentElementBaseOptions,
|
|
3040
4130
|
onTokenizedBody: dispatchTokenizedBody,
|
|
3041
4131
|
onErrorChange: updateError,
|
|
3042
4132
|
onButtonClick,
|
|
3043
4133
|
onDecline,
|
|
3044
4134
|
runBeforeButtonClick,
|
|
3045
|
-
onLoadStateChange:
|
|
4135
|
+
onLoadStateChange: setPaymentElementLoadState,
|
|
4136
|
+
isProcessing: isSubmitting,
|
|
4137
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
4138
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4139
|
+
submitButtonStyle: bStyles.submitButton,
|
|
4140
|
+
themeId: theme,
|
|
4141
|
+
onExpandApm: expandToApm,
|
|
4142
|
+
expandedApmMethod,
|
|
4143
|
+
buttonAppearance: {
|
|
4144
|
+
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
4145
|
+
borderColor: bStyles.cardInputBorder,
|
|
4146
|
+
textColor: bStyles.cardButton?.color,
|
|
4147
|
+
borderRadius: bStyles.cardButton?.borderRadius
|
|
4148
|
+
}
|
|
3046
4149
|
}
|
|
3047
|
-
)
|
|
4150
|
+
)
|
|
3048
4151
|
] }),
|
|
3049
|
-
(shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ jsxs4("div", { style: {
|
|
4152
|
+
showStripe && (shouldDisplayWalletRow || shouldDisplayPayPalRow || shouldDisplayPaymentElementRow) && /* @__PURE__ */ jsxs4("div", { style: {
|
|
3050
4153
|
display: "flex",
|
|
3051
4154
|
alignItems: "center",
|
|
3052
4155
|
gap: "0.75rem",
|
|
@@ -3058,7 +4161,7 @@ function SplitCardFormInner({
|
|
|
3058
4161
|
/* @__PURE__ */ jsx6("span", { children: "or pay with card" }),
|
|
3059
4162
|
/* @__PURE__ */ jsx6("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
3060
4163
|
] }),
|
|
3061
|
-
cardFormBlock
|
|
4164
|
+
showStripe && cardFormBlock
|
|
3062
4165
|
] });
|
|
3063
4166
|
}
|
|
3064
4167
|
|
|
@@ -3591,6 +4694,7 @@ function hasInlineSessionPatchData(patch) {
|
|
|
3591
4694
|
}
|
|
3592
4695
|
function FloPayCheckout({
|
|
3593
4696
|
sessionId: sessionIdProp,
|
|
4697
|
+
nonce: nonceProp,
|
|
3594
4698
|
createSession: createSessionParams,
|
|
3595
4699
|
billingApiUrl,
|
|
3596
4700
|
appearance: appearanceOverride,
|
|
@@ -3604,6 +4708,7 @@ function FloPayCheckout({
|
|
|
3604
4708
|
onCountryChange,
|
|
3605
4709
|
onZipChange,
|
|
3606
4710
|
showPayPal = true,
|
|
4711
|
+
showStripe = true,
|
|
3607
4712
|
showApplePay = true,
|
|
3608
4713
|
showGooglePay = true,
|
|
3609
4714
|
debug = false,
|
|
@@ -3950,6 +5055,14 @@ function FloPayCheckout({
|
|
|
3950
5055
|
},
|
|
3951
5056
|
successUrl: params?.successUrl,
|
|
3952
5057
|
cancelUrl: params?.cancelUrl,
|
|
5058
|
+
// Unified products[] is the post-#760 wire shape. Must be included or
|
|
5059
|
+
// carts that only set `products` (no legacy items/subscriptions) all
|
|
5060
|
+
// hash to the same key — the bootstrap effect's `createSessionHash`
|
|
5061
|
+
// dep then never changes when products change, the session-id cache
|
|
5062
|
+
// hits the wrong session, and the backend's enabledPaymentMethods
|
|
5063
|
+
// result for the *previous* cart sticks until a fresh page-load with
|
|
5064
|
+
// the session cache cleared.
|
|
5065
|
+
p: params?.products?.map((x) => `${x.type ?? ""}:${x.code ?? x.providerItemId ?? x.providerPlanId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
3953
5066
|
i: params?.items?.map((x) => `${x.code ?? x.providerItemId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
3954
5067
|
s: params?.subscriptions?.map((x) => `${x.code ?? x.providerPlanId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
3955
5068
|
couponCodes: params?.couponCodes,
|
|
@@ -4176,7 +5289,7 @@ function FloPayCheckout({
|
|
|
4176
5289
|
async function init() {
|
|
4177
5290
|
try {
|
|
4178
5291
|
const api = new PaymentAPI4(resolvedBillingUrl);
|
|
4179
|
-
const result = await api.getUnifiedCheckoutSession(activeSessionId);
|
|
5292
|
+
const result = await api.getUnifiedCheckoutSession(activeSessionId, nonceProp);
|
|
4180
5293
|
if (cancelled) return;
|
|
4181
5294
|
setUnified(result);
|
|
4182
5295
|
const sess = result.data.session ?? null;
|
|
@@ -4263,6 +5376,7 @@ function FloPayCheckout({
|
|
|
4263
5376
|
createSessionHash,
|
|
4264
5377
|
effectiveCreateSessionMode,
|
|
4265
5378
|
initSessionDependency,
|
|
5379
|
+
nonceProp,
|
|
4266
5380
|
runSavedPaymentFlow
|
|
4267
5381
|
]);
|
|
4268
5382
|
const handleConfirmCheckout = useCallback2(async () => {
|
|
@@ -4336,17 +5450,18 @@ function FloPayCheckout({
|
|
|
4336
5450
|
] });
|
|
4337
5451
|
}
|
|
4338
5452
|
if (layout === "buttons") {
|
|
5453
|
+
const bundleRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
4339
5454
|
const skeletonBar = (h) => /* @__PURE__ */ jsx7("div", { style: {
|
|
4340
5455
|
height: h,
|
|
4341
|
-
borderRadius:
|
|
5456
|
+
borderRadius: bundleRadius,
|
|
4342
5457
|
background: "#e5e7eb",
|
|
4343
5458
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
4344
5459
|
} });
|
|
4345
5460
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
4346
5461
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4347
5462
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4348
|
-
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4349
|
-
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5463
|
+
showStripe && (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5464
|
+
showStripe && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4350
5465
|
/* @__PURE__ */ jsx7("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
4351
5466
|
] }),
|
|
4352
5467
|
modeOverlay
|
|
@@ -4391,6 +5506,7 @@ function FloPayCheckout({
|
|
|
4391
5506
|
{
|
|
4392
5507
|
onButtonClick,
|
|
4393
5508
|
showPayPal,
|
|
5509
|
+
showStripe,
|
|
4394
5510
|
showApplePay,
|
|
4395
5511
|
showGooglePay,
|
|
4396
5512
|
theme,
|
|
@@ -4535,6 +5651,8 @@ function FloPayCheckout({
|
|
|
4535
5651
|
onErrorChange: setModeError,
|
|
4536
5652
|
onFullNameChange,
|
|
4537
5653
|
showPayPal,
|
|
5654
|
+
showStripe,
|
|
5655
|
+
enabledPaymentMethods: unified?.data.stripe?.enabledPaymentMethods,
|
|
4538
5656
|
showApplePay,
|
|
4539
5657
|
showGooglePay,
|
|
4540
5658
|
layout,
|
|
@@ -4599,6 +5717,7 @@ function InterimButtonsView({
|
|
|
4599
5717
|
cardOpen,
|
|
4600
5718
|
errorMessage,
|
|
4601
5719
|
showPayPal,
|
|
5720
|
+
showStripe = true,
|
|
4602
5721
|
showApplePay,
|
|
4603
5722
|
showGooglePay,
|
|
4604
5723
|
theme,
|
|
@@ -4630,9 +5749,10 @@ function InterimButtonsView({
|
|
|
4630
5749
|
title: { ...base.title, ...stylesOverride.title }
|
|
4631
5750
|
};
|
|
4632
5751
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
5752
|
+
const skeletonRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
4633
5753
|
const skeleton = (h) => /* @__PURE__ */ jsx7("div", { style: {
|
|
4634
5754
|
height: h,
|
|
4635
|
-
borderRadius:
|
|
5755
|
+
borderRadius: skeletonRadius,
|
|
4636
5756
|
background: "#e5e7eb",
|
|
4637
5757
|
animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
|
|
4638
5758
|
} });
|
|
@@ -4703,8 +5823,28 @@ function InterimButtonsView({
|
|
|
4703
5823
|
] }),
|
|
4704
5824
|
/* @__PURE__ */ jsx7("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ jsx7("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4705
5825
|
/* @__PURE__ */ jsxs5("div", { style: { display: "flex" }, children: [
|
|
4706
|
-
/* @__PURE__ */ jsx7("div", { style: {
|
|
4707
|
-
|
|
5826
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5827
|
+
flex: 1,
|
|
5828
|
+
backgroundColor: inputBg,
|
|
5829
|
+
borderTop: "none",
|
|
5830
|
+
borderRight: "none",
|
|
5831
|
+
borderBottom: `1px solid ${inputBorder}`,
|
|
5832
|
+
borderLeft: `1px solid ${inputBorder}`,
|
|
5833
|
+
borderBottomLeftRadius: 8,
|
|
5834
|
+
padding: 12,
|
|
5835
|
+
height: 45
|
|
5836
|
+
}, children: /* @__PURE__ */ jsx7("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
5837
|
+
/* @__PURE__ */ jsx7("div", { style: {
|
|
5838
|
+
flex: 1,
|
|
5839
|
+
backgroundColor: inputBg,
|
|
5840
|
+
borderTop: "none",
|
|
5841
|
+
borderRight: `1px solid ${inputBorder}`,
|
|
5842
|
+
borderBottom: `1px solid ${inputBorder}`,
|
|
5843
|
+
borderLeft: `1px solid ${inputBorder}`,
|
|
5844
|
+
borderBottomRightRadius: 8,
|
|
5845
|
+
padding: 12,
|
|
5846
|
+
height: 45
|
|
5847
|
+
}, children: /* @__PURE__ */ jsx7("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
4708
5848
|
] }),
|
|
4709
5849
|
/* @__PURE__ */ jsx7("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ jsx7("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4710
5850
|
/* @__PURE__ */ jsx7("div", { style: {
|
|
@@ -4728,8 +5868,8 @@ function InterimButtonsView({
|
|
|
4728
5868
|
}
|
|
4729
5869
|
return /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4730
5870
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4731
|
-
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4732
|
-
/* @__PURE__ */ jsx7(
|
|
5871
|
+
showStripe && (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5872
|
+
showStripe && /* @__PURE__ */ jsx7(
|
|
4733
5873
|
"button",
|
|
4734
5874
|
{
|
|
4735
5875
|
type: "button",
|
|
@@ -4798,7 +5938,7 @@ import { PaymentAPI as PaymentAPI5 } from "@flopay/js";
|
|
|
4798
5938
|
import { FloPayError as FloPayError6 } from "@flopay/shared";
|
|
4799
5939
|
import { forwardRef as forwardRef2, useCallback as useCallback3, useEffect as useEffect6, useImperativeHandle as useImperativeHandle2, useState as useState5 } from "react";
|
|
4800
5940
|
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4801
|
-
var
|
|
5941
|
+
var WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
4802
5942
|
var CheckoutForm = forwardRef2(
|
|
4803
5943
|
function CheckoutForm2(props, ref) {
|
|
4804
5944
|
return /* @__PURE__ */ jsx8(CheckoutFormInner, { ...props, innerRef: ref });
|
|
@@ -4924,7 +6064,7 @@ function CheckoutFormInner({
|
|
|
4924
6064
|
onDecline?.(buildDeclineEvent("paypal", message));
|
|
4925
6065
|
return;
|
|
4926
6066
|
}
|
|
4927
|
-
localStorage.setItem(
|
|
6067
|
+
localStorage.setItem(WALLET_RESUME_KEY, JSON.stringify({
|
|
4928
6068
|
sessionId,
|
|
4929
6069
|
paymentIntentId: "",
|
|
4930
6070
|
tokenType: "card",
|
|
@@ -5000,12 +6140,12 @@ function CheckoutFormInner({
|
|
|
5000
6140
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
5001
6141
|
useEffect6(() => {
|
|
5002
6142
|
if (typeof window === "undefined") return;
|
|
5003
|
-
const stored = localStorage.getItem(
|
|
6143
|
+
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
5004
6144
|
if (!stored) return;
|
|
5005
6145
|
try {
|
|
5006
6146
|
const payload = JSON.parse(stored);
|
|
5007
6147
|
if (payload.sessionId === sessionId) {
|
|
5008
|
-
localStorage.removeItem(
|
|
6148
|
+
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
5009
6149
|
dispatchTokenizedBody({
|
|
5010
6150
|
id: payload.tokenId,
|
|
5011
6151
|
type: payload.tokenType,
|
|
@@ -5013,7 +6153,7 @@ function CheckoutFormInner({
|
|
|
5013
6153
|
});
|
|
5014
6154
|
}
|
|
5015
6155
|
} catch {
|
|
5016
|
-
localStorage.removeItem(
|
|
6156
|
+
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
5017
6157
|
}
|
|
5018
6158
|
}, [sessionId, dispatchTokenizedBody]);
|
|
5019
6159
|
const handleSubmit = useCallback3(
|
|
@@ -5358,10 +6498,12 @@ function resolveCreateSessionDraft(props) {
|
|
|
5358
6498
|
if (!props.clientId || !props.account || !props.successUrl || !props.cancelUrl) {
|
|
5359
6499
|
return null;
|
|
5360
6500
|
}
|
|
6501
|
+
const hasProducts = props.products != null;
|
|
5361
6502
|
return {
|
|
5362
6503
|
clientId: props.clientId,
|
|
5363
|
-
|
|
5364
|
-
|
|
6504
|
+
products: props.products,
|
|
6505
|
+
items: hasProducts ? void 0 : props.items,
|
|
6506
|
+
subscriptions: hasProducts ? void 0 : props.subscriptions,
|
|
5365
6507
|
account: props.account,
|
|
5366
6508
|
successUrl: props.successUrl,
|
|
5367
6509
|
cancelUrl: props.cancelUrl,
|
|
@@ -5379,6 +6521,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5379
6521
|
paymentMethodId: _deprecatedPaymentMethodId,
|
|
5380
6522
|
checkoutMethod: _deprecatedCheckoutMethod,
|
|
5381
6523
|
clientId,
|
|
6524
|
+
products,
|
|
5382
6525
|
items,
|
|
5383
6526
|
subscriptions,
|
|
5384
6527
|
account,
|
|
@@ -5409,6 +6552,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5409
6552
|
() => resolveCreateSessionDraft({
|
|
5410
6553
|
createSession,
|
|
5411
6554
|
clientId,
|
|
6555
|
+
products,
|
|
5412
6556
|
items,
|
|
5413
6557
|
subscriptions,
|
|
5414
6558
|
account,
|
|
@@ -5424,6 +6568,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5424
6568
|
clientId,
|
|
5425
6569
|
couponCodes,
|
|
5426
6570
|
createSession,
|
|
6571
|
+
products,
|
|
5427
6572
|
items,
|
|
5428
6573
|
subscriptions,
|
|
5429
6574
|
successUrl,
|
|
@@ -5712,10 +6857,20 @@ function FloPayAutomaticPaymentButton({
|
|
|
5712
6857
|
style: {
|
|
5713
6858
|
width: "100%",
|
|
5714
6859
|
...cardButtonSizing,
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
6860
|
+
// `bStyles.cardButton` first so the bundle's padding / typography
|
|
6861
|
+
// / radius / shadow come through, then `derivePrimaryTileStyle`
|
|
6862
|
+
// on top so the auto-pay button carries the *submit* button's
|
|
6863
|
+
// background and text colours — making it visually identical to
|
|
6864
|
+
// the "Confirm Payment" / "Pay with X" actions it stands in for.
|
|
6865
|
+
// Inline `style` consumer override stays at the end so explicit
|
|
6866
|
+
// per-button overrides still win.
|
|
6867
|
+
...bStyles.cardButton,
|
|
6868
|
+
...derivePrimaryTileStyle({
|
|
6869
|
+
themeBundle,
|
|
6870
|
+
resolvedPrimaryColor: themeBundle?.appearance.variables?.colorPrimary ?? "#4A49FF",
|
|
6871
|
+
resolvedBorderRadius: themeBundle?.appearance.variables?.borderRadius ?? "8px",
|
|
6872
|
+
submitButtonStyle: bStyles.submitButton
|
|
6873
|
+
}),
|
|
5719
6874
|
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
5720
6875
|
fontWeight: 600,
|
|
5721
6876
|
cursor: disabled || isProcessing ? "not-allowed" : "pointer",
|
|
@@ -5723,11 +6878,9 @@ function FloPayAutomaticPaymentButton({
|
|
|
5723
6878
|
alignItems: "center",
|
|
5724
6879
|
justifyContent: "center",
|
|
5725
6880
|
gap: "0.625rem",
|
|
5726
|
-
boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
|
|
5727
6881
|
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
5728
6882
|
position: "relative",
|
|
5729
6883
|
opacity: disabled || isProcessing ? 0.6 : 1,
|
|
5730
|
-
...bStyles.cardButton,
|
|
5731
6884
|
...style
|
|
5732
6885
|
},
|
|
5733
6886
|
onMouseDown: (e) => {
|