@flopay/react 1.1.6 → 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 +1323 -196
- 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 +1334 -197
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -287,7 +287,7 @@ var AddressElement = createElementComponent("address", "AddressElement");
|
|
|
287
287
|
var import_react_stripe_js = require("@stripe/react-stripe-js");
|
|
288
288
|
var import_shared5 = require("@flopay/shared");
|
|
289
289
|
var import_js2 = require("@flopay/js");
|
|
290
|
-
var import_react8 = require("react");
|
|
290
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
291
291
|
|
|
292
292
|
// src/hooks.ts
|
|
293
293
|
var import_react5 = require("react");
|
|
@@ -1261,9 +1261,11 @@ ${debugLines.join("\n")}`
|
|
|
1261
1261
|
// src/split-card-form.tsx
|
|
1262
1262
|
var import_shared6 = require("@flopay/shared");
|
|
1263
1263
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1264
|
-
var
|
|
1264
|
+
var STRIPE_RESUME_KEY = "flopay_stripe_resume";
|
|
1265
|
+
var LEGACY_WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
1265
1266
|
var FLOPAY_KEYFRAMES = `
|
|
1266
1267
|
.paypal-buttons { margin: 0 !important; vertical-align: top !important; }
|
|
1268
|
+
@keyframes flopay-spin { to { transform: rotate(360deg); } }
|
|
1267
1269
|
@keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
1268
1270
|
@keyframes flopay-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
|
|
1269
1271
|
@keyframes flopay-buttons-enter {
|
|
@@ -1284,6 +1286,25 @@ var FLOPAY_KEYFRAMES = `
|
|
|
1284
1286
|
}
|
|
1285
1287
|
`;
|
|
1286
1288
|
var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
|
|
1289
|
+
function derivePrimaryTileStyle(opts) {
|
|
1290
|
+
if (!opts.themeBundle) {
|
|
1291
|
+
return {
|
|
1292
|
+
backgroundColor: "white",
|
|
1293
|
+
color: "#262833",
|
|
1294
|
+
border: "1px solid #d1d5db",
|
|
1295
|
+
borderRadius: "8px",
|
|
1296
|
+
boxShadow: "0 1px 2px rgba(0,0,0,0.04)"
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
const submit = opts.submitButtonStyle ?? {};
|
|
1300
|
+
return {
|
|
1301
|
+
backgroundColor: submit.backgroundColor ?? opts.resolvedPrimaryColor,
|
|
1302
|
+
color: submit.color ?? "white",
|
|
1303
|
+
border: submit.border ?? "none",
|
|
1304
|
+
borderRadius: submit.borderRadius ?? opts.resolvedBorderRadius,
|
|
1305
|
+
boxShadow: submit.boxShadow
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1287
1308
|
var BUTTONS_PANEL_HIDDEN_STYLE = {
|
|
1288
1309
|
visibility: "hidden",
|
|
1289
1310
|
position: "absolute",
|
|
@@ -1329,6 +1350,7 @@ function resolveExpressCheckoutLoadState(event, methods) {
|
|
|
1329
1350
|
function ExpressCheckoutReadySwap({
|
|
1330
1351
|
state,
|
|
1331
1352
|
placeholderTestId,
|
|
1353
|
+
borderRadius = 8,
|
|
1332
1354
|
children
|
|
1333
1355
|
}) {
|
|
1334
1356
|
if (state === "unavailable" || state === "load_error") return null;
|
|
@@ -1342,7 +1364,7 @@ function ExpressCheckoutReadySwap({
|
|
|
1342
1364
|
position: "absolute",
|
|
1343
1365
|
inset: 0,
|
|
1344
1366
|
height: 44,
|
|
1345
|
-
borderRadius
|
|
1367
|
+
borderRadius,
|
|
1346
1368
|
background: "#e5e7eb",
|
|
1347
1369
|
animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
|
|
1348
1370
|
opacity: state === "ready" ? 0 : 1,
|
|
@@ -1385,7 +1407,8 @@ function PayPalButtonInner({
|
|
|
1385
1407
|
onButtonClick,
|
|
1386
1408
|
onDecline,
|
|
1387
1409
|
runBeforeButtonClick,
|
|
1388
|
-
onLoadStateChange
|
|
1410
|
+
onLoadStateChange,
|
|
1411
|
+
placeholderBorderRadius
|
|
1389
1412
|
}) {
|
|
1390
1413
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
1391
1414
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
@@ -1555,31 +1578,39 @@ function PayPalButtonInner({
|
|
|
1555
1578
|
}
|
|
1556
1579
|
}, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
|
|
1557
1580
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1558
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1559
|
-
|
|
1581
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1582
|
+
ExpressCheckoutReadySwap,
|
|
1560
1583
|
{
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1584
|
+
state: loadState,
|
|
1585
|
+
placeholderTestId: "flopay-paypal-placeholder",
|
|
1586
|
+
borderRadius: placeholderBorderRadius,
|
|
1587
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1588
|
+
import_react_stripe_js.ExpressCheckoutElement,
|
|
1589
|
+
{
|
|
1590
|
+
onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
|
|
1591
|
+
onLoadError: () => setLoadState("load_error"),
|
|
1592
|
+
onClick: handlePayPalClick,
|
|
1593
|
+
onConfirm: handlePayPalConfirm,
|
|
1594
|
+
onCancel: () => {
|
|
1595
|
+
beforeClickRef.current = null;
|
|
1596
|
+
onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
|
|
1597
|
+
},
|
|
1598
|
+
options: {
|
|
1599
|
+
buttonType: { paypal: "paypal" },
|
|
1600
|
+
billingAddressRequired: false,
|
|
1601
|
+
phoneNumberRequired: false,
|
|
1602
|
+
shippingAddressRequired: false,
|
|
1603
|
+
paymentMethods: {
|
|
1604
|
+
applePay: "never",
|
|
1605
|
+
googlePay: "never",
|
|
1606
|
+
paypal: "auto",
|
|
1607
|
+
link: "never"
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1579
1610
|
}
|
|
1580
|
-
|
|
1611
|
+
)
|
|
1581
1612
|
}
|
|
1582
|
-
)
|
|
1613
|
+
),
|
|
1583
1614
|
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1584
1615
|
] });
|
|
1585
1616
|
}
|
|
@@ -1587,14 +1618,14 @@ function WalletButtonInner({
|
|
|
1587
1618
|
sessionId,
|
|
1588
1619
|
email,
|
|
1589
1620
|
billingApiUrl,
|
|
1590
|
-
|
|
1591
|
-
showGooglePay = true,
|
|
1621
|
+
expressMethods,
|
|
1592
1622
|
onTokenizedBody,
|
|
1593
1623
|
onErrorChange,
|
|
1594
1624
|
onButtonClick,
|
|
1595
1625
|
onDecline,
|
|
1596
1626
|
runBeforeButtonClick,
|
|
1597
|
-
onLoadStateChange
|
|
1627
|
+
onLoadStateChange,
|
|
1628
|
+
placeholderBorderRadius
|
|
1598
1629
|
}) {
|
|
1599
1630
|
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
1600
1631
|
const elements = (0, import_react_stripe_js.useElements)();
|
|
@@ -1612,10 +1643,9 @@ function WalletButtonInner({
|
|
|
1612
1643
|
const walletType = event.expressPaymentType;
|
|
1613
1644
|
let prepared = beforeClickRef.current;
|
|
1614
1645
|
beforeClickRef.current = null;
|
|
1646
|
+
const buttonMethod = walletType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1615
1647
|
if (!prepared && runBeforeButtonClick) {
|
|
1616
|
-
const beforeClick = await runBeforeButtonClick(
|
|
1617
|
-
walletType === "apple_pay" ? "apple_pay" : "google_pay"
|
|
1618
|
-
);
|
|
1648
|
+
const beforeClick = await runBeforeButtonClick(buttonMethod);
|
|
1619
1649
|
if (!beforeClick.proceed) {
|
|
1620
1650
|
event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
|
|
1621
1651
|
return;
|
|
@@ -1625,7 +1655,7 @@ function WalletButtonInner({
|
|
|
1625
1655
|
sessionId: beforeClick.sessionId
|
|
1626
1656
|
};
|
|
1627
1657
|
}
|
|
1628
|
-
const method =
|
|
1658
|
+
const method = buttonMethod;
|
|
1629
1659
|
const effectiveSessionId = prepared?.sessionId ?? sessionId;
|
|
1630
1660
|
const effectiveEmail = prepared?.accountPatch?.email ?? email;
|
|
1631
1661
|
try {
|
|
@@ -1695,53 +1725,655 @@ function WalletButtonInner({
|
|
|
1695
1725
|
},
|
|
1696
1726
|
[stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
|
|
1697
1727
|
);
|
|
1728
|
+
const expressMethodMap = (0, import_react8.useMemo)(() => {
|
|
1729
|
+
const allKeys = ["applePay", "googlePay", "paypal", "link", "amazonPay", "klarna"];
|
|
1730
|
+
const alwaysCapable = /* @__PURE__ */ new Set(["applePay", "googlePay"]);
|
|
1731
|
+
const enabledKeys = new Set(expressMethods.map(import_shared5.stripeExpressMethodToOptionKey));
|
|
1732
|
+
const out = {};
|
|
1733
|
+
for (const key of allKeys) {
|
|
1734
|
+
if (!enabledKeys.has(key)) {
|
|
1735
|
+
out[key] = "never";
|
|
1736
|
+
} else {
|
|
1737
|
+
out[key] = alwaysCapable.has(key) ? "always" : "auto";
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
return out;
|
|
1741
|
+
}, [expressMethods]);
|
|
1742
|
+
const availableMethodKeys = (0, import_react8.useMemo)(
|
|
1743
|
+
() => expressMethods.map(import_shared5.stripeExpressMethodToOptionKey),
|
|
1744
|
+
[expressMethods]
|
|
1745
|
+
);
|
|
1698
1746
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1699
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1700
|
-
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1748
|
+
ExpressCheckoutReadySwap,
|
|
1701
1749
|
{
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1750
|
+
state: loadState,
|
|
1751
|
+
placeholderTestId: "flopay-wallet-placeholder",
|
|
1752
|
+
borderRadius: placeholderBorderRadius,
|
|
1753
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1754
|
+
import_react_stripe_js.ExpressCheckoutElement,
|
|
1755
|
+
{
|
|
1756
|
+
onReady: (event) => {
|
|
1757
|
+
setLoadState(resolveExpressCheckoutLoadState(event, availableMethodKeys));
|
|
1758
|
+
},
|
|
1759
|
+
onLoadError: (_event) => {
|
|
1760
|
+
setLoadState("load_error");
|
|
1761
|
+
},
|
|
1762
|
+
onClick: async (event) => {
|
|
1763
|
+
lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
|
|
1764
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
|
|
1765
|
+
if (!beforeClick.proceed) {
|
|
1766
|
+
beforeClickRef.current = null;
|
|
1767
|
+
event.reject();
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
beforeClickRef.current = {
|
|
1771
|
+
accountPatch: beforeClick.accountPatch,
|
|
1772
|
+
sessionId: beforeClick.sessionId
|
|
1773
|
+
};
|
|
1774
|
+
onButtonClick?.(lastWalletMethodRef.current);
|
|
1775
|
+
event.resolve();
|
|
1776
|
+
},
|
|
1777
|
+
onConfirm: handleWalletConfirm,
|
|
1778
|
+
onCancel: () => {
|
|
1779
|
+
beforeClickRef.current = null;
|
|
1780
|
+
onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
|
|
1781
|
+
},
|
|
1782
|
+
options: {
|
|
1783
|
+
buttonType: { applePay: "plain", googlePay: "plain" },
|
|
1784
|
+
paymentMethods: expressMethodMap,
|
|
1785
|
+
layout: { maxColumns: 1, overflow: "never" }
|
|
1786
|
+
}
|
|
1715
1787
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1788
|
+
)
|
|
1789
|
+
}
|
|
1790
|
+
),
|
|
1791
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
|
|
1792
|
+
] });
|
|
1793
|
+
}
|
|
1794
|
+
function StripeMethodButton({
|
|
1795
|
+
method,
|
|
1796
|
+
themeId,
|
|
1797
|
+
submitting = false,
|
|
1798
|
+
disabled = false,
|
|
1799
|
+
highlighted = false,
|
|
1800
|
+
hasNextStep = false,
|
|
1801
|
+
onClick,
|
|
1802
|
+
backgroundColor,
|
|
1803
|
+
borderColor,
|
|
1804
|
+
textColor,
|
|
1805
|
+
borderRadius,
|
|
1806
|
+
fontFamily
|
|
1807
|
+
}) {
|
|
1808
|
+
const brand = (0, import_shared5.resolveStripeMethodBrandVariant)(method, themeId);
|
|
1809
|
+
const resolvedBackground = brand?.backgroundColor ?? backgroundColor ?? "#ffffff";
|
|
1810
|
+
const resolvedBorder = brand?.borderColor ?? borderColor ?? "#d1d5db";
|
|
1811
|
+
const resolvedTextColor = brand?.textColor ?? textColor ?? "#262833";
|
|
1812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1813
|
+
"button",
|
|
1814
|
+
{
|
|
1815
|
+
type: "button",
|
|
1816
|
+
"data-testid": `flopay-stripe-method-button-${method}`,
|
|
1817
|
+
"data-method": method,
|
|
1818
|
+
onClick: () => {
|
|
1819
|
+
if (!submitting && !disabled) onClick();
|
|
1820
|
+
},
|
|
1821
|
+
disabled: submitting || disabled,
|
|
1822
|
+
"aria-busy": submitting || void 0,
|
|
1823
|
+
style: {
|
|
1824
|
+
position: "relative",
|
|
1825
|
+
width: "100%",
|
|
1826
|
+
boxSizing: "border-box",
|
|
1827
|
+
height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT,
|
|
1828
|
+
padding: "0 1rem",
|
|
1829
|
+
backgroundColor: resolvedBackground,
|
|
1830
|
+
color: resolvedTextColor,
|
|
1831
|
+
border: `1px solid ${resolvedBorder}`,
|
|
1832
|
+
borderRadius: borderRadius ?? 8,
|
|
1833
|
+
fontSize: "0.95rem",
|
|
1834
|
+
fontWeight: 600,
|
|
1835
|
+
fontFamily,
|
|
1836
|
+
cursor: submitting || disabled ? "not-allowed" : "pointer",
|
|
1837
|
+
opacity: disabled && !submitting ? 0.55 : 1,
|
|
1838
|
+
// Submitting state pulses the whole button background, mirroring
|
|
1839
|
+
// the wallet ECE's `flopay-pulse` skeleton. This keeps the loading
|
|
1840
|
+
// affordance consistent between embedded wallets (Apple Pay,
|
|
1841
|
+
// Google Pay) and these custom APM tile buttons — same animation
|
|
1842
|
+
// curve, same duration, only the surface colour changes (grey for
|
|
1843
|
+
// the wallet skeleton vs. brand colour for an in-flight tile).
|
|
1844
|
+
animation: submitting ? "flopay-pulse 1.5s ease-in-out infinite" : void 0,
|
|
1845
|
+
display: "flex",
|
|
1846
|
+
alignItems: "center",
|
|
1847
|
+
// Always center the logo+name group. The drill-in chevron (input
|
|
1848
|
+
// methods) is absolutely positioned at the right edge below so it
|
|
1849
|
+
// doesn't pull the label off-center.
|
|
1850
|
+
justifyContent: "center",
|
|
1851
|
+
gap: 8,
|
|
1852
|
+
transition: "transform 0.1s, opacity 140ms ease-out, border-color 140ms ease-out",
|
|
1853
|
+
boxShadow: highlighted ? "0 0 0 2px rgba(74, 73, 255, 0.15)" : void 0
|
|
1854
|
+
},
|
|
1855
|
+
children: submitting ? (
|
|
1856
|
+
// Pulse-skeleton parity with the wallet ECE: no spinner, just the
|
|
1857
|
+
// status text on top of the pulsing background. Keeps the loading
|
|
1858
|
+
// affordance shape-equivalent across both kinds of tile.
|
|
1859
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { margin: "0 auto" }, children: `Connecting to ${(0, import_shared5.getStripeMethodDisplayName)(method)}\u2026` })
|
|
1860
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1861
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1862
|
+
"span",
|
|
1863
|
+
{
|
|
1864
|
+
style: {
|
|
1865
|
+
display: "inline-flex",
|
|
1866
|
+
alignItems: "center",
|
|
1867
|
+
// Real vendored logos are self-contained brand cards, so they
|
|
1868
|
+
// get an 8px gap from the label. The generated placeholder
|
|
1869
|
+
// monogram reads as part of the label (the tile's first letter),
|
|
1870
|
+
// so it sits flush (0px) against the name.
|
|
1871
|
+
gap: (0, import_shared5.hasVendoredStripeMethodLogo)(method) ? 8 : 0
|
|
1872
|
+
},
|
|
1873
|
+
children: [
|
|
1874
|
+
brand?.logoSvg && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1875
|
+
"span",
|
|
1876
|
+
{
|
|
1877
|
+
"aria-hidden": "true",
|
|
1878
|
+
style: {
|
|
1879
|
+
// 3:2 box matching the vendored datatrans logos' 120×80
|
|
1880
|
+
// viewBox. Each logo ships with its own white rounded-rect
|
|
1881
|
+
// background baked in, so the mark stays legible on any
|
|
1882
|
+
// brand-coloured tile without an extra chip wrapper here.
|
|
1883
|
+
width: 30,
|
|
1884
|
+
height: 20,
|
|
1885
|
+
flexShrink: 0,
|
|
1886
|
+
display: "inline-flex",
|
|
1887
|
+
borderRadius: 3,
|
|
1888
|
+
overflow: "hidden"
|
|
1889
|
+
},
|
|
1890
|
+
dangerouslySetInnerHTML: { __html: brand.logoSvg }
|
|
1891
|
+
}
|
|
1892
|
+
),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: (0, import_shared5.getStripeMethodDisplayName)(method) })
|
|
1894
|
+
]
|
|
1895
|
+
}
|
|
1896
|
+
),
|
|
1897
|
+
hasNextStep && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1898
|
+
"svg",
|
|
1899
|
+
{
|
|
1900
|
+
width: "14",
|
|
1901
|
+
height: "14",
|
|
1902
|
+
viewBox: "0 0 24 24",
|
|
1903
|
+
fill: "none",
|
|
1904
|
+
stroke: resolvedTextColor,
|
|
1905
|
+
strokeWidth: "2.5",
|
|
1906
|
+
strokeLinecap: "round",
|
|
1907
|
+
strokeLinejoin: "round",
|
|
1908
|
+
style: {
|
|
1909
|
+
position: "absolute",
|
|
1910
|
+
right: "1rem",
|
|
1911
|
+
top: "50%",
|
|
1912
|
+
transform: "translateY(-50%)",
|
|
1913
|
+
flexShrink: 0,
|
|
1914
|
+
opacity: 0.7
|
|
1915
|
+
},
|
|
1916
|
+
"aria-hidden": "true",
|
|
1917
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M9 18l6-6-6-6" })
|
|
1918
|
+
}
|
|
1919
|
+
)
|
|
1920
|
+
] })
|
|
1921
|
+
}
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
function StripeMethodInlineForm({
|
|
1925
|
+
method,
|
|
1926
|
+
sessionId,
|
|
1927
|
+
email,
|
|
1928
|
+
billingName,
|
|
1929
|
+
billingApiUrl,
|
|
1930
|
+
onTokenizedBody,
|
|
1931
|
+
onErrorChange,
|
|
1932
|
+
onDecline,
|
|
1933
|
+
onCancel,
|
|
1934
|
+
runBeforeButtonClick,
|
|
1935
|
+
onButtonClick,
|
|
1936
|
+
isProcessing,
|
|
1937
|
+
submitButtonColor,
|
|
1938
|
+
submitButtonBorderRadius,
|
|
1939
|
+
submitButtonStyle
|
|
1940
|
+
}) {
|
|
1941
|
+
const stripe = (0, import_react_stripe_js.useStripe)();
|
|
1942
|
+
const elements = (0, import_react_stripe_js.useElements)();
|
|
1943
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
1944
|
+
const submittingRef = (0, import_react8.useRef)(false);
|
|
1945
|
+
const [isMethodComplete, setIsMethodComplete] = (0, import_react8.useState)(false);
|
|
1946
|
+
const [loadState, setLoadState] = (0, import_react8.useState)("loading");
|
|
1947
|
+
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
1948
|
+
const handlePay = (0, import_react8.useCallback)(async () => {
|
|
1949
|
+
if (!stripe || !elements || isProcessing || submittingRef.current || !isMethodComplete) return;
|
|
1950
|
+
submittingRef.current = true;
|
|
1951
|
+
setSubmitting(true);
|
|
1952
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("card") : { proceed: true };
|
|
1953
|
+
if (!beforeClick.proceed) {
|
|
1954
|
+
submittingRef.current = false;
|
|
1955
|
+
setSubmitting(false);
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
onButtonClick?.("card");
|
|
1959
|
+
const effectiveSessionId = beforeClick.sessionId ?? sessionId;
|
|
1960
|
+
const effectiveEmail = beforeClick.accountPatch?.email ?? email;
|
|
1961
|
+
try {
|
|
1962
|
+
onErrorChange?.(null);
|
|
1963
|
+
const submitRes = await elements.submit();
|
|
1964
|
+
if (submitRes.error) {
|
|
1965
|
+
onErrorChange?.(submitRes.error.message ?? "Payment failed.");
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
const pmRes = await stripe.createPaymentMethod({ elements });
|
|
1969
|
+
if (pmRes.error || !pmRes.paymentMethod) {
|
|
1970
|
+
onErrorChange?.(pmRes.error?.message ?? "Failed to create payment method.");
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
const paymentMethod = pmRes.paymentMethod;
|
|
1974
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
1975
|
+
throw new Error("Missing sessionId or email for payment.");
|
|
1976
|
+
}
|
|
1977
|
+
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
1978
|
+
method: "POST",
|
|
1979
|
+
headers: { "Content-Type": "application/json" },
|
|
1980
|
+
body: JSON.stringify({
|
|
1981
|
+
sessionId: effectiveSessionId,
|
|
1982
|
+
email: effectiveEmail,
|
|
1983
|
+
paymentMethodType: paymentMethod.type || method,
|
|
1984
|
+
isPaypal: false
|
|
1985
|
+
})
|
|
1986
|
+
});
|
|
1987
|
+
if (!intentResponse.ok) {
|
|
1988
|
+
const intentError = await buildFloPayApiErrorFromResponse(intentResponse, "Failed to create payment intent");
|
|
1989
|
+
onErrorChange?.(intentError.message);
|
|
1990
|
+
onDecline?.(buildDeclineEvent("card", intentError));
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
const intentJson = await intentResponse.json();
|
|
1994
|
+
const intentClientSecret = intentJson.data?.id;
|
|
1995
|
+
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
1996
|
+
if (typeof window !== "undefined") {
|
|
1997
|
+
try {
|
|
1998
|
+
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
1999
|
+
sessionId: effectiveSessionId,
|
|
2000
|
+
paymentMethodId: paymentMethod.id,
|
|
2001
|
+
paymentMethodType: paymentMethod.type ?? method,
|
|
2002
|
+
gateway: "stripe"
|
|
2003
|
+
}));
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
const { error: confirmError, paymentIntent } = await stripe.confirmPayment({
|
|
2008
|
+
clientSecret: intentClientSecret,
|
|
2009
|
+
confirmParams: {
|
|
2010
|
+
return_url: window.location.href,
|
|
2011
|
+
payment_method: paymentMethod.id
|
|
1722
2012
|
},
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
2013
|
+
redirect: "if_required"
|
|
2014
|
+
});
|
|
2015
|
+
if (confirmError) {
|
|
2016
|
+
if (typeof window !== "undefined") {
|
|
2017
|
+
try {
|
|
2018
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2019
|
+
} catch {
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
const message = confirmError.message ?? "Payment failed.";
|
|
2023
|
+
onErrorChange?.(message);
|
|
2024
|
+
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
const SUCCESSFUL_PI_STATUSES = /* @__PURE__ */ new Set(["succeeded", "requires_capture", "processing"]);
|
|
2028
|
+
const piStatus = paymentIntent?.status;
|
|
2029
|
+
if (!piStatus || !SUCCESSFUL_PI_STATUSES.has(piStatus)) {
|
|
2030
|
+
if (typeof window !== "undefined") {
|
|
2031
|
+
try {
|
|
2032
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2033
|
+
} catch {
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
2037
|
+
onErrorChange?.(message);
|
|
2038
|
+
onDecline?.(buildDeclineEvent("card", message, { code: piStatus ?? "missing_payment_intent" }));
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
if (typeof window !== "undefined") {
|
|
2042
|
+
try {
|
|
2043
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2044
|
+
} catch {
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
const confirmedPmId = typeof paymentIntent?.payment_method === "string" ? paymentIntent.payment_method : paymentIntent?.payment_method?.id;
|
|
2048
|
+
onTokenizedBody({
|
|
2049
|
+
id: confirmedPmId ?? paymentMethod.id,
|
|
2050
|
+
type: "card",
|
|
2051
|
+
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
2052
|
+
gateway: "stripe",
|
|
2053
|
+
paymentMethodType: paymentMethod.type ?? method
|
|
2054
|
+
}, {
|
|
2055
|
+
accountPatch: beforeClick.accountPatch,
|
|
2056
|
+
sessionId: effectiveSessionId
|
|
2057
|
+
});
|
|
2058
|
+
} catch (err) {
|
|
2059
|
+
onErrorChange?.(err instanceof Error ? err.message : "Payment failed. Please try again.");
|
|
2060
|
+
} finally {
|
|
2061
|
+
submittingRef.current = false;
|
|
2062
|
+
setSubmitting(false);
|
|
2063
|
+
}
|
|
2064
|
+
}, [
|
|
2065
|
+
stripe,
|
|
2066
|
+
elements,
|
|
2067
|
+
isProcessing,
|
|
2068
|
+
isMethodComplete,
|
|
2069
|
+
runBeforeButtonClick,
|
|
2070
|
+
onButtonClick,
|
|
2071
|
+
sessionId,
|
|
2072
|
+
email,
|
|
2073
|
+
baseUrl,
|
|
2074
|
+
method,
|
|
2075
|
+
onTokenizedBody,
|
|
2076
|
+
onErrorChange,
|
|
2077
|
+
onDecline
|
|
2078
|
+
]);
|
|
2079
|
+
void onCancel;
|
|
2080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-testid": `flopay-stripe-method-form-${method}`, style: { display: "flex", flexDirection: "column" }, children: [
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2082
|
+
import_react_stripe_js.PaymentElement,
|
|
2083
|
+
{
|
|
2084
|
+
onReady: () => setLoadState("ready"),
|
|
2085
|
+
onLoadError: () => setLoadState("load_error"),
|
|
2086
|
+
onChange: (event) => {
|
|
2087
|
+
const evRecord = event;
|
|
2088
|
+
setIsMethodComplete(!!evRecord.complete);
|
|
1727
2089
|
},
|
|
1728
2090
|
options: {
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
klarna: "never"
|
|
1737
|
-
},
|
|
1738
|
-
layout: { maxColumns: 1, overflow: "never" }
|
|
2091
|
+
layout: { type: "accordion", defaultCollapsed: false, radios: "never" },
|
|
2092
|
+
defaultValues: {
|
|
2093
|
+
billingDetails: {
|
|
2094
|
+
name: billingName && billingName.trim().length >= 3 ? billingName.trim() : "FloPay Customer",
|
|
2095
|
+
...email ? { email } : {}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
1739
2098
|
}
|
|
1740
2099
|
}
|
|
1741
|
-
)
|
|
1742
|
-
|
|
2100
|
+
),
|
|
2101
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2102
|
+
"button",
|
|
2103
|
+
{
|
|
2104
|
+
type: "button",
|
|
2105
|
+
"data-testid": `flopay-stripe-method-pay-${method}`,
|
|
2106
|
+
onClick: () => {
|
|
2107
|
+
void handlePay();
|
|
2108
|
+
},
|
|
2109
|
+
disabled: !isMethodComplete || submitting || isProcessing || loadState !== "ready",
|
|
2110
|
+
style: {
|
|
2111
|
+
width: "100%",
|
|
2112
|
+
marginTop: "0.75rem",
|
|
2113
|
+
padding: "0.875rem",
|
|
2114
|
+
backgroundColor: submitButtonColor,
|
|
2115
|
+
color: "white",
|
|
2116
|
+
border: "none",
|
|
2117
|
+
borderRadius: submitButtonBorderRadius,
|
|
2118
|
+
fontSize: "1rem",
|
|
2119
|
+
fontWeight: 600,
|
|
2120
|
+
cursor: !isMethodComplete || submitting || isProcessing || loadState !== "ready" ? "not-allowed" : "pointer",
|
|
2121
|
+
opacity: !isMethodComplete || submitting || isProcessing || loadState !== "ready" ? 0.5 : 1,
|
|
2122
|
+
transition: "opacity 120ms ease-out",
|
|
2123
|
+
...submitButtonStyle ?? {}
|
|
2124
|
+
},
|
|
2125
|
+
children: submitting ? "Processing\u2026" : `Pay with ${(0, import_shared5.getStripeMethodDisplayName)(method)}`
|
|
2126
|
+
}
|
|
2127
|
+
)
|
|
1743
2128
|
] });
|
|
1744
2129
|
}
|
|
2130
|
+
function StripePaymentElementInner({
|
|
2131
|
+
sessionId,
|
|
2132
|
+
email,
|
|
2133
|
+
billingName,
|
|
2134
|
+
billingApiUrl,
|
|
2135
|
+
paymentElementMethods,
|
|
2136
|
+
stripeInstance,
|
|
2137
|
+
paymentElementBaseOptions,
|
|
2138
|
+
onTokenizedBody,
|
|
2139
|
+
onErrorChange,
|
|
2140
|
+
onButtonClick,
|
|
2141
|
+
onDecline,
|
|
2142
|
+
runBeforeButtonClick,
|
|
2143
|
+
onLoadStateChange,
|
|
2144
|
+
isProcessing = false,
|
|
2145
|
+
submitButtonColor = "#4A49FF",
|
|
2146
|
+
submitButtonBorderRadius = 8,
|
|
2147
|
+
submitButtonStyle,
|
|
2148
|
+
buttonAppearance,
|
|
2149
|
+
themeId,
|
|
2150
|
+
onExpandApm,
|
|
2151
|
+
expandedApmMethod
|
|
2152
|
+
}) {
|
|
2153
|
+
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
2154
|
+
const [expandedMethod, setExpandedMethod] = (0, import_react8.useState)(null);
|
|
2155
|
+
const [submittingMethod, setSubmittingMethod] = (0, import_react8.useState)(null);
|
|
2156
|
+
const submittingRef = (0, import_react8.useRef)(false);
|
|
2157
|
+
(0, import_react8.useEffect)(() => {
|
|
2158
|
+
if (paymentElementMethods.length > 0 && stripeInstance) {
|
|
2159
|
+
onLoadStateChange?.("ready");
|
|
2160
|
+
} else if (!stripeInstance) {
|
|
2161
|
+
onLoadStateChange?.("loading");
|
|
2162
|
+
}
|
|
2163
|
+
}, [paymentElementMethods.length, stripeInstance, onLoadStateChange]);
|
|
2164
|
+
const handleAutoConfirm = (0, import_react8.useCallback)(async (method) => {
|
|
2165
|
+
if (!stripeInstance) return;
|
|
2166
|
+
if (submittingRef.current || isProcessing) return;
|
|
2167
|
+
submittingRef.current = true;
|
|
2168
|
+
setSubmittingMethod(method);
|
|
2169
|
+
const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("card") : { proceed: true };
|
|
2170
|
+
if (!beforeClick.proceed) {
|
|
2171
|
+
submittingRef.current = false;
|
|
2172
|
+
setSubmittingMethod(null);
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
onButtonClick?.("card");
|
|
2176
|
+
const effectiveSessionId = beforeClick.sessionId ?? sessionId;
|
|
2177
|
+
const effectiveEmail = beforeClick.accountPatch?.email ?? email;
|
|
2178
|
+
try {
|
|
2179
|
+
onErrorChange?.(null);
|
|
2180
|
+
if (!effectiveSessionId || !effectiveEmail) {
|
|
2181
|
+
throw new Error("Missing sessionId or email for payment.");
|
|
2182
|
+
}
|
|
2183
|
+
const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
|
|
2184
|
+
method: "POST",
|
|
2185
|
+
headers: { "Content-Type": "application/json" },
|
|
2186
|
+
body: JSON.stringify({
|
|
2187
|
+
sessionId: effectiveSessionId,
|
|
2188
|
+
email: effectiveEmail,
|
|
2189
|
+
// Wire type, not pm_xxx — backend scopes `payment_method_types`
|
|
2190
|
+
// to this single method so unrelated account-wide methods
|
|
2191
|
+
// (apple_pay without domain verification, …) don't poison PI
|
|
2192
|
+
// creation.
|
|
2193
|
+
paymentMethodType: method,
|
|
2194
|
+
isPaypal: false
|
|
2195
|
+
})
|
|
2196
|
+
});
|
|
2197
|
+
if (!intentResponse.ok) {
|
|
2198
|
+
const intentError = await buildFloPayApiErrorFromResponse(intentResponse, "Failed to create payment intent");
|
|
2199
|
+
onErrorChange?.(intentError.message);
|
|
2200
|
+
onDecline?.(buildDeclineEvent("card", intentError));
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
const intentJson = await intentResponse.json();
|
|
2204
|
+
const intentClientSecret = intentJson.data?.id;
|
|
2205
|
+
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
2206
|
+
if (typeof window !== "undefined") {
|
|
2207
|
+
try {
|
|
2208
|
+
localStorage.setItem(STRIPE_RESUME_KEY, JSON.stringify({
|
|
2209
|
+
sessionId: effectiveSessionId,
|
|
2210
|
+
paymentMethodType: method,
|
|
2211
|
+
gateway: "stripe"
|
|
2212
|
+
}));
|
|
2213
|
+
} catch {
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
const { error: confirmError, paymentIntent } = await stripeInstance.confirmPayment({
|
|
2217
|
+
clientSecret: intentClientSecret,
|
|
2218
|
+
confirmParams: {
|
|
2219
|
+
return_url: window.location.href,
|
|
2220
|
+
// Inline the method data — no Elements / PaymentElement
|
|
2221
|
+
// required. Stripe creates the PaymentMethod during confirm
|
|
2222
|
+
// and proceeds to its popup/redirect UI.
|
|
2223
|
+
payment_method_data: {
|
|
2224
|
+
type: method,
|
|
2225
|
+
billing_details: {
|
|
2226
|
+
name: billingName && billingName.trim().length >= 3 ? billingName.trim() : "FloPay Customer",
|
|
2227
|
+
...effectiveEmail ? { email: effectiveEmail } : {}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
},
|
|
2231
|
+
redirect: "if_required"
|
|
2232
|
+
});
|
|
2233
|
+
if (confirmError) {
|
|
2234
|
+
if (typeof window !== "undefined") {
|
|
2235
|
+
try {
|
|
2236
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2237
|
+
} catch {
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
const message = confirmError.message ?? "Payment failed.";
|
|
2241
|
+
onErrorChange?.(message);
|
|
2242
|
+
onDecline?.(buildDeclineEvent("card", message, { code: confirmError.code }));
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
const SUCCESSFUL_PI_STATUSES = /* @__PURE__ */ new Set(["succeeded", "requires_capture", "processing"]);
|
|
2246
|
+
const piStatus = paymentIntent?.status;
|
|
2247
|
+
if (!piStatus || !SUCCESSFUL_PI_STATUSES.has(piStatus)) {
|
|
2248
|
+
if (typeof window !== "undefined") {
|
|
2249
|
+
try {
|
|
2250
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2251
|
+
} catch {
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
2255
|
+
onErrorChange?.(message);
|
|
2256
|
+
onDecline?.(buildDeclineEvent("card", message, { code: piStatus ?? "missing_payment_intent" }));
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
if (typeof window !== "undefined") {
|
|
2260
|
+
try {
|
|
2261
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
2262
|
+
} catch {
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
const confirmedPmId = typeof paymentIntent?.payment_method === "string" ? paymentIntent.payment_method : paymentIntent?.payment_method?.id;
|
|
2266
|
+
onTokenizedBody({
|
|
2267
|
+
id: confirmedPmId ?? paymentIntent?.id,
|
|
2268
|
+
type: "card",
|
|
2269
|
+
threeDSecureActionResultTokenId: paymentIntent?.id,
|
|
2270
|
+
gateway: "stripe",
|
|
2271
|
+
paymentMethodType: method
|
|
2272
|
+
}, {
|
|
2273
|
+
accountPatch: beforeClick.accountPatch,
|
|
2274
|
+
sessionId: effectiveSessionId
|
|
2275
|
+
});
|
|
2276
|
+
} catch (err) {
|
|
2277
|
+
onErrorChange?.(err instanceof Error ? err.message : "Payment failed. Please try again.");
|
|
2278
|
+
} finally {
|
|
2279
|
+
submittingRef.current = false;
|
|
2280
|
+
setSubmittingMethod(null);
|
|
2281
|
+
}
|
|
2282
|
+
}, [
|
|
2283
|
+
stripeInstance,
|
|
2284
|
+
isProcessing,
|
|
2285
|
+
runBeforeButtonClick,
|
|
2286
|
+
onButtonClick,
|
|
2287
|
+
sessionId,
|
|
2288
|
+
email,
|
|
2289
|
+
baseUrl,
|
|
2290
|
+
billingName,
|
|
2291
|
+
onTokenizedBody,
|
|
2292
|
+
onErrorChange,
|
|
2293
|
+
onDecline
|
|
2294
|
+
]);
|
|
2295
|
+
const [localExpandedMethod, setLocalExpandedMethod] = (0, import_react8.useState)(null);
|
|
2296
|
+
const activeExpandedMethod = onExpandApm ? expandedApmMethod ?? null : localExpandedMethod;
|
|
2297
|
+
const handleMethodClick = (0, import_react8.useCallback)((method) => {
|
|
2298
|
+
if (submittingRef.current || isProcessing) return;
|
|
2299
|
+
if (activeExpandedMethod && activeExpandedMethod !== method) return;
|
|
2300
|
+
if ((0, import_shared5.needsStripeMethodExplicitConfirm)(method)) {
|
|
2301
|
+
if (onExpandApm) {
|
|
2302
|
+
onExpandApm(method);
|
|
2303
|
+
} else {
|
|
2304
|
+
setLocalExpandedMethod(method);
|
|
2305
|
+
}
|
|
2306
|
+
} else {
|
|
2307
|
+
void handleAutoConfirm(method);
|
|
2308
|
+
}
|
|
2309
|
+
}, [activeExpandedMethod, isProcessing, handleAutoConfirm, onExpandApm]);
|
|
2310
|
+
const localInlineElementsOptions = (0, import_react8.useMemo)(() => {
|
|
2311
|
+
if (!localExpandedMethod) return null;
|
|
2312
|
+
return {
|
|
2313
|
+
...paymentElementBaseOptions,
|
|
2314
|
+
paymentMethodTypes: [localExpandedMethod]
|
|
2315
|
+
};
|
|
2316
|
+
}, [localExpandedMethod, paymentElementBaseOptions]);
|
|
2317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2318
|
+
"div",
|
|
2319
|
+
{
|
|
2320
|
+
"data-testid": "flopay-stripe-payment-element-region",
|
|
2321
|
+
style: { display: "flex", flexDirection: "column", gap: "0.5rem" },
|
|
2322
|
+
children: paymentElementMethods.map((method) => {
|
|
2323
|
+
const isExpanded = expandedApmMethod === method;
|
|
2324
|
+
const isSubmittingThis = submittingMethod === method;
|
|
2325
|
+
const otherInProgress = submittingMethod !== null && submittingMethod !== method || expandedApmMethod !== null && expandedApmMethod !== void 0 && expandedApmMethod !== method;
|
|
2326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react8.default.Fragment, { children: [
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2328
|
+
StripeMethodButton,
|
|
2329
|
+
{
|
|
2330
|
+
method,
|
|
2331
|
+
themeId,
|
|
2332
|
+
submitting: isSubmittingThis,
|
|
2333
|
+
disabled: otherInProgress,
|
|
2334
|
+
highlighted: isExpanded,
|
|
2335
|
+
hasNextStep: (0, import_shared5.needsStripeMethodExplicitConfirm)(method),
|
|
2336
|
+
onClick: () => handleMethodClick(method),
|
|
2337
|
+
backgroundColor: buttonAppearance?.backgroundColor,
|
|
2338
|
+
borderColor: buttonAppearance?.borderColor,
|
|
2339
|
+
textColor: buttonAppearance?.textColor,
|
|
2340
|
+
borderRadius: buttonAppearance?.borderRadius,
|
|
2341
|
+
fontFamily: buttonAppearance?.fontFamily
|
|
2342
|
+
}
|
|
2343
|
+
),
|
|
2344
|
+
!onExpandApm && localExpandedMethod === method && localInlineElementsOptions && stripeInstance && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2345
|
+
import_react_stripe_js.Elements,
|
|
2346
|
+
{
|
|
2347
|
+
stripe: stripeInstance,
|
|
2348
|
+
options: localInlineElementsOptions,
|
|
2349
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2350
|
+
StripeMethodInlineForm,
|
|
2351
|
+
{
|
|
2352
|
+
method,
|
|
2353
|
+
sessionId,
|
|
2354
|
+
email,
|
|
2355
|
+
billingName,
|
|
2356
|
+
billingApiUrl,
|
|
2357
|
+
onTokenizedBody,
|
|
2358
|
+
onErrorChange,
|
|
2359
|
+
onDecline,
|
|
2360
|
+
onCancel: () => setLocalExpandedMethod(null),
|
|
2361
|
+
runBeforeButtonClick,
|
|
2362
|
+
onButtonClick,
|
|
2363
|
+
isProcessing,
|
|
2364
|
+
submitButtonColor,
|
|
2365
|
+
submitButtonBorderRadius,
|
|
2366
|
+
submitButtonStyle
|
|
2367
|
+
}
|
|
2368
|
+
)
|
|
2369
|
+
},
|
|
2370
|
+
method
|
|
2371
|
+
)
|
|
2372
|
+
] }, method);
|
|
2373
|
+
})
|
|
2374
|
+
}
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
1745
2377
|
function SplitCardFormInner({
|
|
1746
2378
|
sessionId,
|
|
1747
2379
|
billingApiUrl,
|
|
@@ -1764,6 +2396,8 @@ function SplitCardFormInner({
|
|
|
1764
2396
|
onFirstNameChange,
|
|
1765
2397
|
onLastNameChange,
|
|
1766
2398
|
showPayPal = true,
|
|
2399
|
+
showStripe = true,
|
|
2400
|
+
enabledPaymentMethods,
|
|
1767
2401
|
showApplePay = true,
|
|
1768
2402
|
showGooglePay = true,
|
|
1769
2403
|
layout = "default",
|
|
@@ -1823,6 +2457,7 @@ function SplitCardFormInner({
|
|
|
1823
2457
|
const avsConfig = (0, import_react8.useMemo)(() => (0, import_shared5.resolveAVSConfig)(enableAVSProp), [enableAVSProp]);
|
|
1824
2458
|
const enableAVS = avsConfig !== null;
|
|
1825
2459
|
const [viewState, setViewState] = (0, import_react8.useState)(initialCardOpen ? "card" : "buttons");
|
|
2460
|
+
const [expandedApmMethod, setExpandedApmMethod] = (0, import_react8.useState)(null);
|
|
1826
2461
|
const showCardForm = viewState === "expanding" || viewState === "card";
|
|
1827
2462
|
const TRANSITION_MS = 280;
|
|
1828
2463
|
const expandToCard = (0, import_react8.useCallback)(() => {
|
|
@@ -1833,6 +2468,18 @@ function SplitCardFormInner({
|
|
|
1833
2468
|
setViewState("collapsing");
|
|
1834
2469
|
setTimeout(() => setViewState("buttons"), TRANSITION_MS);
|
|
1835
2470
|
}, []);
|
|
2471
|
+
const expandToApm = (0, import_react8.useCallback)((method) => {
|
|
2472
|
+
setExpandedApmMethod(method);
|
|
2473
|
+
setViewState("apm-expanding");
|
|
2474
|
+
setTimeout(() => setViewState("apm-form"), TRANSITION_MS);
|
|
2475
|
+
}, []);
|
|
2476
|
+
const collapseFromApm = (0, import_react8.useCallback)(() => {
|
|
2477
|
+
setViewState("apm-collapsing");
|
|
2478
|
+
setTimeout(() => {
|
|
2479
|
+
setViewState("buttons");
|
|
2480
|
+
setExpandedApmMethod(null);
|
|
2481
|
+
}, TRANSITION_MS);
|
|
2482
|
+
}, []);
|
|
1836
2483
|
(0, import_react8.useEffect)(() => {
|
|
1837
2484
|
if (layout === "buttons" && initialCardOpen) {
|
|
1838
2485
|
setViewState("card");
|
|
@@ -1886,20 +2533,43 @@ function SplitCardFormInner({
|
|
|
1886
2533
|
return paypalFlopay.getRawProvider();
|
|
1887
2534
|
}, [paypalFlopay]);
|
|
1888
2535
|
const amountInCents = totalAmount || 100;
|
|
2536
|
+
const stripeAppearanceProp = appearance ? { appearance } : null;
|
|
2537
|
+
const paymentElementAppearance = (0, import_react8.useMemo)(() => {
|
|
2538
|
+
const base = appearance ?? {};
|
|
2539
|
+
const baseRules = base.rules ?? {};
|
|
2540
|
+
return {
|
|
2541
|
+
...base,
|
|
2542
|
+
rules: {
|
|
2543
|
+
...baseRules,
|
|
2544
|
+
".AccordionItem": {
|
|
2545
|
+
padding: "10px 14px",
|
|
2546
|
+
boxShadow: "none",
|
|
2547
|
+
...baseRules[".AccordionItem"] ?? {}
|
|
2548
|
+
},
|
|
2549
|
+
".AccordionItemContents": {
|
|
2550
|
+
padding: "6px 14px 12px",
|
|
2551
|
+
boxShadow: "none",
|
|
2552
|
+
...baseRules[".AccordionItemContents"] ?? {}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
}, [appearance]);
|
|
1889
2557
|
const walletOptions = (0, import_react8.useMemo)(() => ({
|
|
1890
2558
|
mode: "payment",
|
|
1891
2559
|
amount: amountInCents,
|
|
1892
2560
|
currency: currency.toLowerCase(),
|
|
1893
2561
|
paymentMethodCreation: "manual",
|
|
1894
|
-
captureMethod: "manual"
|
|
1895
|
-
|
|
2562
|
+
captureMethod: "manual",
|
|
2563
|
+
...stripeAppearanceProp
|
|
2564
|
+
}), [amountInCents, currency, stripeAppearanceProp]);
|
|
1896
2565
|
const paypalOptions = (0, import_react8.useMemo)(() => ({
|
|
1897
2566
|
mode: "payment",
|
|
1898
2567
|
amount: amountInCents,
|
|
1899
2568
|
currency: currency.toLowerCase(),
|
|
1900
2569
|
captureMethod: "manual",
|
|
1901
|
-
setupFutureUsage: "off_session"
|
|
1902
|
-
|
|
2570
|
+
setupFutureUsage: "off_session",
|
|
2571
|
+
...stripeAppearanceProp
|
|
2572
|
+
}), [amountInCents, currency, stripeAppearanceProp]);
|
|
1903
2573
|
const updateError = (0, import_react8.useCallback)(
|
|
1904
2574
|
(err) => {
|
|
1905
2575
|
setError(err);
|
|
@@ -1913,22 +2583,98 @@ function SplitCardFormInner({
|
|
|
1913
2583
|
},
|
|
1914
2584
|
[onDecline]
|
|
1915
2585
|
);
|
|
1916
|
-
const
|
|
2586
|
+
const directPaypalConfigured = !!directPaypal?.clientId;
|
|
2587
|
+
const hasEnabledMethodsPayload = Array.isArray(enabledPaymentMethods);
|
|
2588
|
+
const hasEnabledMethods = hasEnabledMethodsPayload && enabledPaymentMethods.length > 0;
|
|
2589
|
+
const paypalEnabled = hasEnabledMethodsPayload && enabledPaymentMethods.includes("paypal");
|
|
2590
|
+
const { expressMethods, paymentElementMethods } = (0, import_react8.useMemo)(
|
|
2591
|
+
() => (0, import_shared5.partitionStripeMethods)(enabledPaymentMethods, {
|
|
2592
|
+
excludePaypal: directPaypalConfigured
|
|
2593
|
+
}),
|
|
2594
|
+
[enabledPaymentMethods, directPaypalConfigured]
|
|
2595
|
+
);
|
|
2596
|
+
const paypalRenderedSeparately = directPaypalConfigured || !!paypalFlopay;
|
|
2597
|
+
const expressMethodsForWalletRow = (0, import_react8.useMemo)(
|
|
2598
|
+
() => paypalRenderedSeparately ? expressMethods.filter((m) => m !== "paypal") : expressMethods,
|
|
2599
|
+
[expressMethods, paypalRenderedSeparately]
|
|
2600
|
+
);
|
|
2601
|
+
const legacyExpressMethods = (0, import_react8.useMemo)(() => {
|
|
2602
|
+
const out = [];
|
|
2603
|
+
if (showApplePay) out.push("apple_pay");
|
|
2604
|
+
if (showGooglePay) out.push("google_pay");
|
|
2605
|
+
return out;
|
|
2606
|
+
}, [showApplePay, showGooglePay]);
|
|
2607
|
+
const walletExpressMethods = hasEnabledMethodsPayload ? expressMethodsForWalletRow : legacyExpressMethods;
|
|
2608
|
+
const showWallets = showStripe && walletExpressMethods.length > 0;
|
|
2609
|
+
const paymentElementMethodsForCurrency = (0, import_react8.useMemo)(
|
|
2610
|
+
() => (0, import_shared5.filterStripeMethodsByAmount)(
|
|
2611
|
+
(0, import_shared5.filterStripeMethodsByCountry)(
|
|
2612
|
+
(0, import_shared5.filterStripeMethodsByCurrency)(paymentElementMethods, currency),
|
|
2613
|
+
countryProp
|
|
2614
|
+
),
|
|
2615
|
+
currency,
|
|
2616
|
+
amountInCents
|
|
2617
|
+
),
|
|
2618
|
+
[paymentElementMethods, currency, countryProp, amountInCents]
|
|
2619
|
+
);
|
|
2620
|
+
const paymentElementBaseOptions = (0, import_react8.useMemo)(() => ({
|
|
2621
|
+
mode: "payment",
|
|
2622
|
+
amount: amountInCents,
|
|
2623
|
+
currency: currency.toLowerCase(),
|
|
2624
|
+
paymentMethodCreation: "manual",
|
|
2625
|
+
appearance: paymentElementAppearance
|
|
2626
|
+
}), [amountInCents, currency, paymentElementAppearance]);
|
|
1917
2627
|
const [paypalLoadState, setPaypalLoadState] = (0, import_react8.useState)("loading");
|
|
1918
2628
|
const [walletLoadState, setWalletLoadState] = (0, import_react8.useState)("loading");
|
|
2629
|
+
const [paymentElementLoadState, setPaymentElementLoadState] = (0, import_react8.useState)("loading");
|
|
1919
2630
|
const [directPaypalReady, setDirectPaypalReady] = (0, import_react8.useState)(false);
|
|
1920
2631
|
const [inAppBrowserDetected, setInAppBrowserDetected] = (0, import_react8.useState)();
|
|
1921
2632
|
(0, import_react8.useEffect)(() => {
|
|
1922
2633
|
setInAppBrowserDetected(isInAppBrowser());
|
|
1923
2634
|
}, []);
|
|
1924
|
-
const
|
|
1925
|
-
const
|
|
1926
|
-
const shouldShowWallets = showWallets;
|
|
2635
|
+
const shouldShowPayPal = showPayPal && (directPaypalConfigured || (hasEnabledMethodsPayload ? paypalEnabled : inAppBrowserDetected === false));
|
|
2636
|
+
const shouldShowWallets = showStripe && showWallets;
|
|
1927
2637
|
const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
|
|
1928
2638
|
const shouldRenderStripePayPal = shouldShowPayPal && !directPaypalConfigured && !!paypalStripeInstance;
|
|
1929
2639
|
const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
|
|
2640
|
+
const shouldRenderPaymentElement = showStripe && hasEnabledMethods && paymentElementMethodsForCurrency.length > 0 && !!stripeInstance;
|
|
1930
2641
|
const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
|
|
1931
2642
|
const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
|
|
2643
|
+
const shouldDisplayPaymentElementRow = shouldRenderPaymentElement && paymentElementLoadState !== "load_error";
|
|
2644
|
+
const validationFiredRef = (0, import_react8.useRef)(false);
|
|
2645
|
+
(0, import_react8.useEffect)(() => {
|
|
2646
|
+
if (validationFiredRef.current) return;
|
|
2647
|
+
if (!showStripe && !showPayPal) {
|
|
2648
|
+
validationFiredRef.current = true;
|
|
2649
|
+
const err = new import_shared6.FloPayError(
|
|
2650
|
+
"FloPay: both `showStripe` and `showPayPal` are false \u2014 nothing to render.",
|
|
2651
|
+
"validation_error"
|
|
2652
|
+
);
|
|
2653
|
+
onError?.(err);
|
|
2654
|
+
updateError(err.message);
|
|
2655
|
+
} else if (!showStripe && showPayPal && !directPaypalConfigured && !paypalStripeInstance) {
|
|
2656
|
+
validationFiredRef.current = true;
|
|
2657
|
+
const err = new import_shared6.FloPayError(
|
|
2658
|
+
"FloPay: `showStripe` is false and no PayPal gateway is configured for this session \u2014 nothing to render.",
|
|
2659
|
+
"validation_error"
|
|
2660
|
+
);
|
|
2661
|
+
onError?.(err);
|
|
2662
|
+
updateError(err.message);
|
|
2663
|
+
}
|
|
2664
|
+
}, [showStripe, showPayPal, directPaypalConfigured, paypalStripeInstance, onError, updateError]);
|
|
2665
|
+
const deprecationLoggedRef = (0, import_react8.useRef)(false);
|
|
2666
|
+
(0, import_react8.useEffect)(() => {
|
|
2667
|
+
if (deprecationLoggedRef.current) return;
|
|
2668
|
+
if (!hasEnabledMethods) return;
|
|
2669
|
+
const stale = [];
|
|
2670
|
+
if (showApplePay !== true) stale.push("showApplePay");
|
|
2671
|
+
if (showGooglePay !== true) stale.push("showGooglePay");
|
|
2672
|
+
if (stale.length === 0) return;
|
|
2673
|
+
deprecationLoggedRef.current = true;
|
|
2674
|
+
console.warn(
|
|
2675
|
+
`[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.`
|
|
2676
|
+
);
|
|
2677
|
+
}, [hasEnabledMethods, showApplePay, showGooglePay]);
|
|
1932
2678
|
const handleNameChange = (0, import_react8.useCallback)((value) => {
|
|
1933
2679
|
setFullName(value);
|
|
1934
2680
|
onFullNameChange?.(value);
|
|
@@ -2229,24 +2975,75 @@ function SplitCardFormInner({
|
|
|
2229
2975
|
}
|
|
2230
2976
|
}
|
|
2231
2977
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
2978
|
+
const stripeResumeAttemptedRef = (0, import_react8.useRef)(false);
|
|
2232
2979
|
(0, import_react8.useEffect)(() => {
|
|
2233
|
-
if (typeof window === "undefined") return;
|
|
2234
|
-
const
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2980
|
+
if (typeof window === "undefined" || stripeResumeAttemptedRef.current) return;
|
|
2981
|
+
const params = new URLSearchParams(window.location.search);
|
|
2982
|
+
const paymentIntentId = params.get("payment_intent");
|
|
2983
|
+
const clientSecret = params.get("payment_intent_client_secret");
|
|
2984
|
+
const redirectStatus = params.get("redirect_status");
|
|
2985
|
+
if (!paymentIntentId || !clientSecret) return;
|
|
2986
|
+
const readPayload = (key) => {
|
|
2987
|
+
const raw = localStorage.getItem(key);
|
|
2988
|
+
if (!raw) return null;
|
|
2989
|
+
try {
|
|
2990
|
+
return JSON.parse(raw);
|
|
2991
|
+
} catch {
|
|
2992
|
+
localStorage.removeItem(key);
|
|
2993
|
+
return null;
|
|
2245
2994
|
}
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2995
|
+
};
|
|
2996
|
+
const payload = readPayload(STRIPE_RESUME_KEY) ?? readPayload(LEGACY_WALLET_RESUME_KEY);
|
|
2997
|
+
if (payload?.sessionId && payload.sessionId !== sessionId) return;
|
|
2998
|
+
stripeResumeAttemptedRef.current = true;
|
|
2999
|
+
localStorage.removeItem(STRIPE_RESUME_KEY);
|
|
3000
|
+
localStorage.removeItem(LEGACY_WALLET_RESUME_KEY);
|
|
3001
|
+
const cleanedUrl = new URL(window.location.href);
|
|
3002
|
+
cleanedUrl.searchParams.delete("payment_intent");
|
|
3003
|
+
cleanedUrl.searchParams.delete("payment_intent_client_secret");
|
|
3004
|
+
cleanedUrl.searchParams.delete("redirect_status");
|
|
3005
|
+
window.history.replaceState({}, "", cleanedUrl.toString());
|
|
3006
|
+
const paymentMethodType = payload?.paymentMethodType ?? payload?.tokenType ?? "card";
|
|
3007
|
+
const declineMethod = "card";
|
|
3008
|
+
(async () => {
|
|
3009
|
+
const rawProvider = flopay?.getRawProvider();
|
|
3010
|
+
if (!rawProvider) {
|
|
3011
|
+
const message = "Payment is not available \u2014 please refresh and try again.";
|
|
3012
|
+
updateError(message);
|
|
3013
|
+
emitDecline(declineMethod, message);
|
|
3014
|
+
return;
|
|
3015
|
+
}
|
|
3016
|
+
if (redirectStatus === "failed") {
|
|
3017
|
+
const message = "Payment was declined. Please try again.";
|
|
3018
|
+
updateError(message);
|
|
3019
|
+
emitDecline(declineMethod, message);
|
|
3020
|
+
return;
|
|
3021
|
+
}
|
|
3022
|
+
const { paymentIntent, error: error2 } = await rawProvider.retrievePaymentIntent(clientSecret);
|
|
3023
|
+
if (error2) {
|
|
3024
|
+
const message = error2.message ?? "Failed to retrieve payment status.";
|
|
3025
|
+
updateError(message);
|
|
3026
|
+
emitDecline(declineMethod, message, { code: error2.code });
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
const piStatus = paymentIntent?.status;
|
|
3030
|
+
const successful = piStatus === "succeeded" || piStatus === "requires_capture" || piStatus === "processing";
|
|
3031
|
+
if (!paymentIntent || !successful) {
|
|
3032
|
+
const message = piStatus === "canceled" ? "Payment was canceled." : "Payment was not completed. Please try again.";
|
|
3033
|
+
updateError(message);
|
|
3034
|
+
emitDecline(declineMethod, message, { code: piStatus ?? "missing_payment_intent" });
|
|
3035
|
+
return;
|
|
3036
|
+
}
|
|
3037
|
+
const resolvedPmId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
|
|
3038
|
+
dispatchTokenizedBody({
|
|
3039
|
+
id: resolvedPmId ?? payload?.paymentMethodId ?? payload?.tokenId ?? paymentIntent.id,
|
|
3040
|
+
type: "card",
|
|
3041
|
+
threeDSecureActionResultTokenId: paymentIntent.id,
|
|
3042
|
+
gateway: payload?.gateway ?? "stripe",
|
|
3043
|
+
paymentMethodType
|
|
3044
|
+
});
|
|
3045
|
+
})();
|
|
3046
|
+
}, [sessionId, dispatchTokenizedBody, flopay, updateError, emitDecline]);
|
|
2250
3047
|
const handleSubmit = (0, import_react8.useCallback)(
|
|
2251
3048
|
async (e) => {
|
|
2252
3049
|
e.preventDefault();
|
|
@@ -2529,17 +3326,23 @@ function SplitCardFormInner({
|
|
|
2529
3326
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2530
3327
|
flex: 1,
|
|
2531
3328
|
backgroundColor: cardInputBg,
|
|
2532
|
-
|
|
3329
|
+
// Longhand only — mixing `border` shorthand with per-side
|
|
3330
|
+
// overrides triggers React's "shorthand vs longhand" warning
|
|
3331
|
+
// because render order isn't deterministic.
|
|
2533
3332
|
borderTop: "none",
|
|
2534
3333
|
borderRight: "none",
|
|
3334
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3335
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2535
3336
|
borderBottomLeftRadius: "8px",
|
|
2536
3337
|
padding: "10px"
|
|
2537
3338
|
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
|
|
2538
3339
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2539
3340
|
flex: 1,
|
|
2540
3341
|
backgroundColor: cardInputBg,
|
|
2541
|
-
border: `1px solid ${resolvedBorder}`,
|
|
2542
3342
|
borderTop: "none",
|
|
3343
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3344
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3345
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2543
3346
|
borderBottomRightRadius: "8px",
|
|
2544
3347
|
padding: "10px"
|
|
2545
3348
|
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardCvcElement, { options: stripeElementStyle }) })
|
|
@@ -2631,7 +3434,10 @@ function SplitCardFormInner({
|
|
|
2631
3434
|
(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2632
3435
|
flex: 1,
|
|
2633
3436
|
backgroundColor: cardInputBg,
|
|
2634
|
-
|
|
3437
|
+
borderTop: `1px solid ${resolvedBorder}`,
|
|
3438
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3439
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3440
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2635
3441
|
padding: "10px",
|
|
2636
3442
|
borderTopLeftRadius: "8px",
|
|
2637
3443
|
borderBottomLeftRadius: "8px",
|
|
@@ -2708,7 +3514,10 @@ function SplitCardFormInner({
|
|
|
2708
3514
|
(0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2709
3515
|
flex: avsLayoutProp === "row" ? 1 : void 0,
|
|
2710
3516
|
backgroundColor: cardInputBg,
|
|
2711
|
-
|
|
3517
|
+
borderTop: `1px solid ${resolvedBorder}`,
|
|
3518
|
+
borderRight: `1px solid ${resolvedBorder}`,
|
|
3519
|
+
borderBottom: `1px solid ${resolvedBorder}`,
|
|
3520
|
+
borderLeft: `1px solid ${resolvedBorder}`,
|
|
2712
3521
|
padding: "10px",
|
|
2713
3522
|
...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
|
|
2714
3523
|
...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
|
|
@@ -2803,11 +3612,65 @@ function SplitCardFormInner({
|
|
|
2803
3612
|
}
|
|
2804
3613
|
)
|
|
2805
3614
|
] });
|
|
3615
|
+
const gateDebugStyle = {
|
|
3616
|
+
margin: 0,
|
|
3617
|
+
padding: "6px 8px",
|
|
3618
|
+
background: "#eef2ff",
|
|
3619
|
+
border: "1px solid #c7d2fe",
|
|
3620
|
+
borderRadius: 6,
|
|
3621
|
+
color: "#111827",
|
|
3622
|
+
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
3623
|
+
whiteSpace: "pre-wrap",
|
|
3624
|
+
wordBreak: "break-word"
|
|
3625
|
+
};
|
|
3626
|
+
const renderDirectPaypalGateDebug = (testId) => {
|
|
3627
|
+
if (!debug) return null;
|
|
3628
|
+
if (!showPayPal || !directPaypalConfigured) {
|
|
3629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/DirectPayPal-debug - not enabled" });
|
|
3630
|
+
}
|
|
3631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3632
|
+
"FloPay/DirectPayPal-debug (parent gate)",
|
|
3633
|
+
` showPayPal=${showPayPal}`,
|
|
3634
|
+
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
3635
|
+
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
3636
|
+
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
3637
|
+
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
3638
|
+
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
3639
|
+
].join("\n") });
|
|
3640
|
+
};
|
|
3641
|
+
const renderStripeGateDebug = (testId) => {
|
|
3642
|
+
if (!debug) return null;
|
|
3643
|
+
if (!showStripe || !stripeInstance) {
|
|
3644
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { "data-testid": testId, style: gateDebugStyle, children: "FloPay/Stripe-debug - not enabled" });
|
|
3645
|
+
}
|
|
3646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { "data-testid": testId, style: gateDebugStyle, children: [
|
|
3647
|
+
"FloPay/Stripe-debug (parent gate)",
|
|
3648
|
+
` showStripe=${showStripe}`,
|
|
3649
|
+
` currency=${currency}`,
|
|
3650
|
+
` amountInCents=${amountInCents}`,
|
|
3651
|
+
` enabledPaymentMethods: ${JSON.stringify(enabledPaymentMethods ?? [])}`,
|
|
3652
|
+
` enabledPaymentMethodsProvided=${hasEnabledMethodsPayload}`,
|
|
3653
|
+
` hasEnabledMethods=${hasEnabledMethods}`,
|
|
3654
|
+
` expressMethods: ${JSON.stringify(expressMethods)}`,
|
|
3655
|
+
` walletExpressMethods: ${JSON.stringify(walletExpressMethods)}`,
|
|
3656
|
+
` paymentElementMethods: ${JSON.stringify(paymentElementMethods)}`,
|
|
3657
|
+
` paymentElementMethodsForCurrency: ${JSON.stringify(paymentElementMethodsForCurrency)}`,
|
|
3658
|
+
` hasStripeInstance=${!!stripeInstance}`,
|
|
3659
|
+
` shouldRenderWallets=${shouldRenderWallets}`,
|
|
3660
|
+
` shouldRenderPaymentElement=${shouldRenderPaymentElement}`
|
|
3661
|
+
].join("\n") });
|
|
3662
|
+
};
|
|
3663
|
+
const isApmView = viewState === "apm-expanding" || viewState === "apm-form" || viewState === "apm-collapsing";
|
|
3664
|
+
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;
|
|
3665
|
+
const apmInlineOptions = expandedApmMethod ? {
|
|
3666
|
+
...paymentElementBaseOptions,
|
|
3667
|
+
paymentMethodTypes: [expandedApmMethod]
|
|
3668
|
+
} : null;
|
|
2806
3669
|
if (layout === "buttons") {
|
|
2807
|
-
const isButtonsView = viewState === "buttons" || viewState === "expanding";
|
|
3670
|
+
const isButtonsView = viewState === "buttons" || viewState === "expanding" || viewState === "apm-expanding";
|
|
2808
3671
|
const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
|
|
2809
3672
|
const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
|
|
2810
|
-
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;
|
|
3673
|
+
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;
|
|
2811
3674
|
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;
|
|
2812
3675
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
2813
3676
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
@@ -2828,32 +3691,8 @@ function SplitCardFormInner({
|
|
|
2828
3691
|
...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
|
|
2829
3692
|
},
|
|
2830
3693
|
children: [
|
|
2831
|
-
debug
|
|
2832
|
-
|
|
2833
|
-
{
|
|
2834
|
-
"data-testid": "flopay-direct-paypal-gate-debug",
|
|
2835
|
-
style: {
|
|
2836
|
-
margin: 0,
|
|
2837
|
-
padding: "6px 8px",
|
|
2838
|
-
background: "#eef2ff",
|
|
2839
|
-
border: "1px solid #c7d2fe",
|
|
2840
|
-
borderRadius: 6,
|
|
2841
|
-
color: "#111827",
|
|
2842
|
-
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
2843
|
-
whiteSpace: "pre-wrap",
|
|
2844
|
-
wordBreak: "break-word"
|
|
2845
|
-
},
|
|
2846
|
-
children: [
|
|
2847
|
-
"FloPay/DirectPayPal-debug (parent gate)",
|
|
2848
|
-
` showPayPal=${showPayPal}`,
|
|
2849
|
-
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
2850
|
-
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
2851
|
-
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
2852
|
-
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
2853
|
-
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
2854
|
-
].join("\n")
|
|
2855
|
-
}
|
|
2856
|
-
),
|
|
3694
|
+
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug"),
|
|
3695
|
+
renderStripeGateDebug("flopay-stripe-gate-debug"),
|
|
2857
3696
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2858
3697
|
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2859
3698
|
"div",
|
|
@@ -2908,7 +3747,8 @@ function SplitCardFormInner({
|
|
|
2908
3747
|
onButtonClick,
|
|
2909
3748
|
onDecline,
|
|
2910
3749
|
runBeforeButtonClick,
|
|
2911
|
-
onLoadStateChange: setPaypalLoadState
|
|
3750
|
+
onLoadStateChange: setPaypalLoadState,
|
|
3751
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
2912
3752
|
}
|
|
2913
3753
|
) }),
|
|
2914
3754
|
shouldRenderWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -2917,17 +3757,48 @@ function SplitCardFormInner({
|
|
|
2917
3757
|
sessionId,
|
|
2918
3758
|
email: resolvedAccount.email,
|
|
2919
3759
|
billingApiUrl: resolvedBillingApiUrl,
|
|
2920
|
-
|
|
2921
|
-
|
|
3760
|
+
expressMethods: walletExpressMethods,
|
|
3761
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3762
|
+
onErrorChange: updateError,
|
|
3763
|
+
onButtonClick,
|
|
3764
|
+
onDecline,
|
|
3765
|
+
runBeforeButtonClick,
|
|
3766
|
+
onLoadStateChange: setWalletLoadState,
|
|
3767
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
3768
|
+
}
|
|
3769
|
+
) }) : shouldShowWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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,
|
|
3770
|
+
shouldRenderPaymentElement && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3771
|
+
StripePaymentElementInner,
|
|
3772
|
+
{
|
|
3773
|
+
sessionId,
|
|
3774
|
+
email: resolvedAccount.email,
|
|
3775
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
3776
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3777
|
+
paymentElementMethods: paymentElementMethodsForCurrency,
|
|
3778
|
+
stripeInstance,
|
|
3779
|
+
paymentElementBaseOptions,
|
|
2922
3780
|
onTokenizedBody: dispatchTokenizedBody,
|
|
2923
3781
|
onErrorChange: updateError,
|
|
2924
3782
|
onButtonClick,
|
|
2925
3783
|
onDecline,
|
|
2926
3784
|
runBeforeButtonClick,
|
|
2927
|
-
onLoadStateChange:
|
|
3785
|
+
onLoadStateChange: setPaymentElementLoadState,
|
|
3786
|
+
isProcessing: isSubmitting,
|
|
3787
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
3788
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
3789
|
+
submitButtonStyle: bStyles.submitButton,
|
|
3790
|
+
onExpandApm: expandToApm,
|
|
3791
|
+
expandedApmMethod,
|
|
3792
|
+
themeId: theme,
|
|
3793
|
+
buttonAppearance: {
|
|
3794
|
+
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
3795
|
+
borderColor: bStyles.cardInputBorder,
|
|
3796
|
+
textColor: bStyles.cardButton?.color,
|
|
3797
|
+
borderRadius: bStyles.cardButton?.borderRadius
|
|
3798
|
+
}
|
|
2928
3799
|
}
|
|
2929
|
-
)
|
|
2930
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3800
|
+
),
|
|
3801
|
+
showStripe && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2931
3802
|
"button",
|
|
2932
3803
|
{
|
|
2933
3804
|
type: "button",
|
|
@@ -2942,10 +3813,21 @@ function SplitCardFormInner({
|
|
|
2942
3813
|
style: {
|
|
2943
3814
|
width: "100%",
|
|
2944
3815
|
...cardButtonSizing,
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
3816
|
+
// `bStyles.cardButton` first — supplies the bundle's
|
|
3817
|
+
// padding / typography / border-radius — then the
|
|
3818
|
+
// primary surface overrides on top, so the card button
|
|
3819
|
+
// ends up wearing the *submit* button's colours rather
|
|
3820
|
+
// than the bundle's neutral white-tile `cardButton`
|
|
3821
|
+
// colours. Without this order flip, every non-classic
|
|
3822
|
+
// bundle's `cardButton.backgroundColor` was winning
|
|
3823
|
+
// over the primary fill we just derived above it.
|
|
3824
|
+
...bStyles.cardButton,
|
|
3825
|
+
...derivePrimaryTileStyle({
|
|
3826
|
+
themeBundle,
|
|
3827
|
+
resolvedPrimaryColor,
|
|
3828
|
+
resolvedBorderRadius,
|
|
3829
|
+
submitButtonStyle: bStyles.submitButton
|
|
3830
|
+
}),
|
|
2949
3831
|
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
2950
3832
|
fontWeight: 600,
|
|
2951
3833
|
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
@@ -2954,10 +3836,8 @@ function SplitCardFormInner({
|
|
|
2954
3836
|
justifyContent: "center",
|
|
2955
3837
|
gap: "0.625rem",
|
|
2956
3838
|
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
2957
|
-
boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
|
|
2958
3839
|
position: "relative",
|
|
2959
|
-
opacity: isSubmitting ? 0.6 : 1
|
|
2960
|
-
...bStyles.cardButton
|
|
3840
|
+
opacity: isSubmitting ? 0.6 : 1
|
|
2961
3841
|
},
|
|
2962
3842
|
onMouseDown: (e) => {
|
|
2963
3843
|
e.currentTarget.style.transform = "scale(0.985)";
|
|
@@ -2988,44 +3868,209 @@ function SplitCardFormInner({
|
|
|
2988
3868
|
]
|
|
2989
3869
|
}
|
|
2990
3870
|
),
|
|
2991
|
-
isCardView && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
3871
|
+
showStripe && isCardView && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
2992
3872
|
gridArea: "1 / 1",
|
|
2993
3873
|
...cardAnim ? { animation: cardAnim } : {},
|
|
2994
3874
|
...viewState === "collapsing" ? { pointerEvents: "none" } : {}
|
|
2995
|
-
}, children: cardFormBlock })
|
|
3875
|
+
}, children: cardFormBlock }),
|
|
3876
|
+
showStripe && isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
3877
|
+
gridArea: "1 / 1",
|
|
3878
|
+
...apmAnim ? { animation: apmAnim } : {},
|
|
3879
|
+
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
3880
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
3881
|
+
backgroundColor: cardBg,
|
|
3882
|
+
borderRadius: containerRadius,
|
|
3883
|
+
...containerOverrides,
|
|
3884
|
+
padding: containerPadding
|
|
3885
|
+
}, children: [
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
3887
|
+
display: "flex",
|
|
3888
|
+
alignItems: "center",
|
|
3889
|
+
padding: "0.75rem 0 0.625rem"
|
|
3890
|
+
}, children: [
|
|
3891
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3892
|
+
"button",
|
|
3893
|
+
{
|
|
3894
|
+
type: "button",
|
|
3895
|
+
"data-testid": "flopay-apm-back-button",
|
|
3896
|
+
onClick: collapseFromApm,
|
|
3897
|
+
style: {
|
|
3898
|
+
display: "inline-flex",
|
|
3899
|
+
alignItems: "center",
|
|
3900
|
+
gap: hideBackButtonLabel ? 0 : "0.5rem",
|
|
3901
|
+
background: "none",
|
|
3902
|
+
border: "none",
|
|
3903
|
+
cursor: "pointer",
|
|
3904
|
+
color: "#4b5563",
|
|
3905
|
+
fontSize: bStyles.backButtonFontSize ?? "0.85rem",
|
|
3906
|
+
fontWeight: 500,
|
|
3907
|
+
padding: 0,
|
|
3908
|
+
transition: "color 0.15s",
|
|
3909
|
+
flexShrink: 0,
|
|
3910
|
+
...bStyles.backButton
|
|
3911
|
+
},
|
|
3912
|
+
"aria-label": "Back to payment methods",
|
|
3913
|
+
children: [
|
|
3914
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
|
|
3915
|
+
display: "inline-flex",
|
|
3916
|
+
alignItems: "center",
|
|
3917
|
+
justifyContent: "center",
|
|
3918
|
+
width: 28,
|
|
3919
|
+
height: 28,
|
|
3920
|
+
borderRadius: "50%",
|
|
3921
|
+
backgroundColor: "#f3f4f6",
|
|
3922
|
+
transition: "background-color 0.15s",
|
|
3923
|
+
...bStyles.backButtonIcon
|
|
3924
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
3925
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
3926
|
+
]
|
|
3927
|
+
}
|
|
3928
|
+
),
|
|
3929
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
3930
|
+
flex: 1,
|
|
3931
|
+
textAlign: "center",
|
|
3932
|
+
fontWeight: 600,
|
|
3933
|
+
fontSize: bStyles.titleFontSize ?? "1.05rem",
|
|
3934
|
+
color: resolvedTitleColor,
|
|
3935
|
+
paddingRight: 80,
|
|
3936
|
+
...bStyles.title
|
|
3937
|
+
}, children: `Pay with ${(0, import_shared5.getStripeMethodDisplayName)(expandedApmMethod)}` })
|
|
3938
|
+
] }),
|
|
3939
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3940
|
+
import_react_stripe_js.Elements,
|
|
3941
|
+
{
|
|
3942
|
+
stripe: stripeInstance,
|
|
3943
|
+
options: apmInlineOptions,
|
|
3944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3945
|
+
StripeMethodInlineForm,
|
|
3946
|
+
{
|
|
3947
|
+
method: expandedApmMethod,
|
|
3948
|
+
sessionId,
|
|
3949
|
+
email: resolvedAccount.email,
|
|
3950
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
3951
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
3952
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
3953
|
+
onErrorChange: updateError,
|
|
3954
|
+
onDecline,
|
|
3955
|
+
onCancel: collapseFromApm,
|
|
3956
|
+
runBeforeButtonClick,
|
|
3957
|
+
onButtonClick,
|
|
3958
|
+
isProcessing: isSubmitting,
|
|
3959
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
3960
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
3961
|
+
submitButtonStyle: bStyles.submitButton
|
|
3962
|
+
}
|
|
3963
|
+
)
|
|
3964
|
+
},
|
|
3965
|
+
expandedApmMethod
|
|
3966
|
+
)
|
|
3967
|
+
] }) })
|
|
2996
3968
|
] })
|
|
2997
3969
|
] });
|
|
2998
3970
|
}
|
|
3971
|
+
if (isApmView && expandedApmMethod && apmInlineOptions && stripeInstance && showStripe) {
|
|
3972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
3973
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
3974
|
+
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
3975
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
3976
|
+
...apmAnim ? { animation: apmAnim } : {},
|
|
3977
|
+
...viewState === "apm-collapsing" ? { pointerEvents: "none" } : {}
|
|
3978
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
3979
|
+
backgroundColor: cardBg,
|
|
3980
|
+
borderRadius: containerRadius,
|
|
3981
|
+
...containerOverrides,
|
|
3982
|
+
padding: containerPadding
|
|
3983
|
+
}, children: [
|
|
3984
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
3985
|
+
display: "flex",
|
|
3986
|
+
alignItems: "center",
|
|
3987
|
+
padding: "0.75rem 0 0.625rem"
|
|
3988
|
+
}, children: [
|
|
3989
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3990
|
+
"button",
|
|
3991
|
+
{
|
|
3992
|
+
type: "button",
|
|
3993
|
+
"data-testid": "flopay-apm-back-button-default",
|
|
3994
|
+
onClick: collapseFromApm,
|
|
3995
|
+
style: {
|
|
3996
|
+
display: "inline-flex",
|
|
3997
|
+
alignItems: "center",
|
|
3998
|
+
gap: hideBackButtonLabel ? 0 : "0.5rem",
|
|
3999
|
+
background: "none",
|
|
4000
|
+
border: "none",
|
|
4001
|
+
cursor: "pointer",
|
|
4002
|
+
color: "#4b5563",
|
|
4003
|
+
fontSize: bStyles.backButtonFontSize ?? "0.85rem",
|
|
4004
|
+
fontWeight: 500,
|
|
4005
|
+
padding: 0,
|
|
4006
|
+
transition: "color 0.15s",
|
|
4007
|
+
flexShrink: 0,
|
|
4008
|
+
...bStyles.backButton
|
|
4009
|
+
},
|
|
4010
|
+
"aria-label": "Back to payment methods",
|
|
4011
|
+
children: [
|
|
4012
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
|
|
4013
|
+
display: "inline-flex",
|
|
4014
|
+
alignItems: "center",
|
|
4015
|
+
justifyContent: "center",
|
|
4016
|
+
width: 28,
|
|
4017
|
+
height: 28,
|
|
4018
|
+
borderRadius: "50%",
|
|
4019
|
+
backgroundColor: "#f3f4f6",
|
|
4020
|
+
transition: "background-color 0.15s",
|
|
4021
|
+
...bStyles.backButtonIcon
|
|
4022
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
4023
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
|
|
4024
|
+
]
|
|
4025
|
+
}
|
|
4026
|
+
),
|
|
4027
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
|
|
4028
|
+
flex: 1,
|
|
4029
|
+
textAlign: "center",
|
|
4030
|
+
fontWeight: 600,
|
|
4031
|
+
fontSize: bStyles.titleFontSize ?? "1.05rem",
|
|
4032
|
+
color: resolvedTitleColor,
|
|
4033
|
+
paddingRight: 80,
|
|
4034
|
+
...bStyles.title
|
|
4035
|
+
}, children: `Pay with ${(0, import_shared5.getStripeMethodDisplayName)(expandedApmMethod)}` })
|
|
4036
|
+
] }),
|
|
4037
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4038
|
+
import_react_stripe_js.Elements,
|
|
4039
|
+
{
|
|
4040
|
+
stripe: stripeInstance,
|
|
4041
|
+
options: apmInlineOptions,
|
|
4042
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4043
|
+
StripeMethodInlineForm,
|
|
4044
|
+
{
|
|
4045
|
+
method: expandedApmMethod,
|
|
4046
|
+
sessionId,
|
|
4047
|
+
email: resolvedAccount.email,
|
|
4048
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
4049
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
4050
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
4051
|
+
onErrorChange: updateError,
|
|
4052
|
+
onDecline,
|
|
4053
|
+
onCancel: collapseFromApm,
|
|
4054
|
+
runBeforeButtonClick,
|
|
4055
|
+
onButtonClick,
|
|
4056
|
+
isProcessing: isSubmitting,
|
|
4057
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
4058
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4059
|
+
submitButtonStyle: bStyles.submitButton
|
|
4060
|
+
}
|
|
4061
|
+
)
|
|
4062
|
+
},
|
|
4063
|
+
expandedApmMethod
|
|
4064
|
+
)
|
|
4065
|
+
] }) })
|
|
4066
|
+
] });
|
|
4067
|
+
}
|
|
2999
4068
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
|
|
3000
4069
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
|
|
3001
4070
|
overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
|
|
3002
4071
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
3003
|
-
debug
|
|
3004
|
-
|
|
3005
|
-
{
|
|
3006
|
-
"data-testid": "flopay-direct-paypal-gate-debug-default",
|
|
3007
|
-
style: {
|
|
3008
|
-
margin: 0,
|
|
3009
|
-
padding: "6px 8px",
|
|
3010
|
-
background: "#eef2ff",
|
|
3011
|
-
border: "1px solid #c7d2fe",
|
|
3012
|
-
borderRadius: 6,
|
|
3013
|
-
color: "#111827",
|
|
3014
|
-
font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
3015
|
-
whiteSpace: "pre-wrap",
|
|
3016
|
-
wordBreak: "break-word"
|
|
3017
|
-
},
|
|
3018
|
-
children: [
|
|
3019
|
-
"FloPay/DirectPayPal-debug (parent gate)",
|
|
3020
|
-
` showPayPal=${showPayPal}`,
|
|
3021
|
-
` directPaypalConfigured=${directPaypalConfigured}`,
|
|
3022
|
-
` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
|
|
3023
|
-
` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
|
|
3024
|
-
` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
|
|
3025
|
-
` hasPaypalStripeInstance=${!!paypalStripeInstance}`
|
|
3026
|
-
].join("\n")
|
|
3027
|
-
}
|
|
3028
|
-
),
|
|
4072
|
+
renderDirectPaypalGateDebug("flopay-direct-paypal-gate-debug-default"),
|
|
4073
|
+
renderStripeGateDebug("flopay-stripe-gate-debug-default"),
|
|
3029
4074
|
shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
3030
4075
|
paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3031
4076
|
"div",
|
|
@@ -3080,7 +4125,8 @@ function SplitCardFormInner({
|
|
|
3080
4125
|
onButtonClick,
|
|
3081
4126
|
onDecline,
|
|
3082
4127
|
runBeforeButtonClick,
|
|
3083
|
-
onLoadStateChange: setPaypalLoadState
|
|
4128
|
+
onLoadStateChange: setPaypalLoadState,
|
|
4129
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
3084
4130
|
}
|
|
3085
4131
|
) }),
|
|
3086
4132
|
shouldRenderWallets && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -3089,18 +4135,49 @@ function SplitCardFormInner({
|
|
|
3089
4135
|
sessionId,
|
|
3090
4136
|
email: resolvedAccount.email,
|
|
3091
4137
|
billingApiUrl: resolvedBillingApiUrl,
|
|
3092
|
-
|
|
3093
|
-
|
|
4138
|
+
expressMethods: walletExpressMethods,
|
|
4139
|
+
onTokenizedBody: dispatchTokenizedBody,
|
|
4140
|
+
onErrorChange: updateError,
|
|
4141
|
+
onButtonClick,
|
|
4142
|
+
onDecline,
|
|
4143
|
+
runBeforeButtonClick,
|
|
4144
|
+
onLoadStateChange: setWalletLoadState,
|
|
4145
|
+
placeholderBorderRadius: bStyles.cardButton?.borderRadius ?? resolvedBorderRadius
|
|
4146
|
+
}
|
|
4147
|
+
) }),
|
|
4148
|
+
shouldRenderPaymentElement && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4149
|
+
StripePaymentElementInner,
|
|
4150
|
+
{
|
|
4151
|
+
sessionId,
|
|
4152
|
+
email: resolvedAccount.email,
|
|
4153
|
+
billingName: [resolvedAccount.firstName, resolvedAccount.lastName].filter(Boolean).join(" ").trim() || void 0,
|
|
4154
|
+
billingApiUrl: resolvedBillingApiUrl,
|
|
4155
|
+
paymentElementMethods: paymentElementMethodsForCurrency,
|
|
4156
|
+
stripeInstance,
|
|
4157
|
+
paymentElementBaseOptions,
|
|
3094
4158
|
onTokenizedBody: dispatchTokenizedBody,
|
|
3095
4159
|
onErrorChange: updateError,
|
|
3096
4160
|
onButtonClick,
|
|
3097
4161
|
onDecline,
|
|
3098
4162
|
runBeforeButtonClick,
|
|
3099
|
-
onLoadStateChange:
|
|
4163
|
+
onLoadStateChange: setPaymentElementLoadState,
|
|
4164
|
+
isProcessing: isSubmitting,
|
|
4165
|
+
submitButtonColor: resolvedPrimaryColor,
|
|
4166
|
+
submitButtonBorderRadius: resolvedBorderRadius,
|
|
4167
|
+
submitButtonStyle: bStyles.submitButton,
|
|
4168
|
+
themeId: theme,
|
|
4169
|
+
onExpandApm: expandToApm,
|
|
4170
|
+
expandedApmMethod,
|
|
4171
|
+
buttonAppearance: {
|
|
4172
|
+
backgroundColor: bStyles.cardButton?.backgroundColor,
|
|
4173
|
+
borderColor: bStyles.cardInputBorder,
|
|
4174
|
+
textColor: bStyles.cardButton?.color,
|
|
4175
|
+
borderRadius: bStyles.cardButton?.borderRadius
|
|
4176
|
+
}
|
|
3100
4177
|
}
|
|
3101
|
-
)
|
|
4178
|
+
)
|
|
3102
4179
|
] }),
|
|
3103
|
-
(shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
4180
|
+
showStripe && (shouldDisplayWalletRow || shouldDisplayPayPalRow || shouldDisplayPaymentElementRow) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
|
|
3104
4181
|
display: "flex",
|
|
3105
4182
|
alignItems: "center",
|
|
3106
4183
|
gap: "0.75rem",
|
|
@@ -3112,7 +4189,7 @@ function SplitCardFormInner({
|
|
|
3112
4189
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "or pay with card" }),
|
|
3113
4190
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
|
|
3114
4191
|
] }),
|
|
3115
|
-
cardFormBlock
|
|
4192
|
+
showStripe && cardFormBlock
|
|
3116
4193
|
] });
|
|
3117
4194
|
}
|
|
3118
4195
|
|
|
@@ -3645,6 +4722,7 @@ function hasInlineSessionPatchData(patch) {
|
|
|
3645
4722
|
}
|
|
3646
4723
|
function FloPayCheckout({
|
|
3647
4724
|
sessionId: sessionIdProp,
|
|
4725
|
+
nonce: nonceProp,
|
|
3648
4726
|
createSession: createSessionParams,
|
|
3649
4727
|
billingApiUrl,
|
|
3650
4728
|
appearance: appearanceOverride,
|
|
@@ -3658,6 +4736,7 @@ function FloPayCheckout({
|
|
|
3658
4736
|
onCountryChange,
|
|
3659
4737
|
onZipChange,
|
|
3660
4738
|
showPayPal = true,
|
|
4739
|
+
showStripe = true,
|
|
3661
4740
|
showApplePay = true,
|
|
3662
4741
|
showGooglePay = true,
|
|
3663
4742
|
debug = false,
|
|
@@ -4004,6 +5083,14 @@ function FloPayCheckout({
|
|
|
4004
5083
|
},
|
|
4005
5084
|
successUrl: params?.successUrl,
|
|
4006
5085
|
cancelUrl: params?.cancelUrl,
|
|
5086
|
+
// Unified products[] is the post-#760 wire shape. Must be included or
|
|
5087
|
+
// carts that only set `products` (no legacy items/subscriptions) all
|
|
5088
|
+
// hash to the same key — the bootstrap effect's `createSessionHash`
|
|
5089
|
+
// dep then never changes when products change, the session-id cache
|
|
5090
|
+
// hits the wrong session, and the backend's enabledPaymentMethods
|
|
5091
|
+
// result for the *previous* cart sticks until a fresh page-load with
|
|
5092
|
+
// the session cache cleared.
|
|
5093
|
+
p: params?.products?.map((x) => `${x.type ?? ""}:${x.code ?? x.providerItemId ?? x.providerPlanId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
4007
5094
|
i: params?.items?.map((x) => `${x.code ?? x.providerItemId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
4008
5095
|
s: params?.subscriptions?.map((x) => `${x.code ?? x.providerPlanId ?? ""}:${x.totalAmount ?? ""}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
4009
5096
|
couponCodes: params?.couponCodes,
|
|
@@ -4230,7 +5317,7 @@ function FloPayCheckout({
|
|
|
4230
5317
|
async function init() {
|
|
4231
5318
|
try {
|
|
4232
5319
|
const api = new import_js4.PaymentAPI(resolvedBillingUrl);
|
|
4233
|
-
const result = await api.getUnifiedCheckoutSession(activeSessionId);
|
|
5320
|
+
const result = await api.getUnifiedCheckoutSession(activeSessionId, nonceProp);
|
|
4234
5321
|
if (cancelled) return;
|
|
4235
5322
|
setUnified(result);
|
|
4236
5323
|
const sess = result.data.session ?? null;
|
|
@@ -4317,6 +5404,7 @@ function FloPayCheckout({
|
|
|
4317
5404
|
createSessionHash,
|
|
4318
5405
|
effectiveCreateSessionMode,
|
|
4319
5406
|
initSessionDependency,
|
|
5407
|
+
nonceProp,
|
|
4320
5408
|
runSavedPaymentFlow
|
|
4321
5409
|
]);
|
|
4322
5410
|
const handleConfirmCheckout = (0, import_react9.useCallback)(async () => {
|
|
@@ -4390,17 +5478,18 @@ function FloPayCheckout({
|
|
|
4390
5478
|
] });
|
|
4391
5479
|
}
|
|
4392
5480
|
if (layout === "buttons") {
|
|
5481
|
+
const bundleRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
4393
5482
|
const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
4394
5483
|
height: h,
|
|
4395
|
-
borderRadius:
|
|
5484
|
+
borderRadius: bundleRadius,
|
|
4396
5485
|
background: "#e5e7eb",
|
|
4397
5486
|
animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
|
|
4398
5487
|
} });
|
|
4399
5488
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4400
5489
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4401
5490
|
showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4402
|
-
(showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4403
|
-
skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5491
|
+
showStripe && (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5492
|
+
showStripe && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4404
5493
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
|
|
4405
5494
|
] }),
|
|
4406
5495
|
modeOverlay
|
|
@@ -4445,6 +5534,7 @@ function FloPayCheckout({
|
|
|
4445
5534
|
{
|
|
4446
5535
|
onButtonClick,
|
|
4447
5536
|
showPayPal,
|
|
5537
|
+
showStripe,
|
|
4448
5538
|
showApplePay,
|
|
4449
5539
|
showGooglePay,
|
|
4450
5540
|
theme,
|
|
@@ -4589,6 +5679,8 @@ function FloPayCheckout({
|
|
|
4589
5679
|
onErrorChange: setModeError,
|
|
4590
5680
|
onFullNameChange,
|
|
4591
5681
|
showPayPal,
|
|
5682
|
+
showStripe,
|
|
5683
|
+
enabledPaymentMethods: unified?.data.stripe?.enabledPaymentMethods,
|
|
4592
5684
|
showApplePay,
|
|
4593
5685
|
showGooglePay,
|
|
4594
5686
|
layout,
|
|
@@ -4653,6 +5745,7 @@ function InterimButtonsView({
|
|
|
4653
5745
|
cardOpen,
|
|
4654
5746
|
errorMessage,
|
|
4655
5747
|
showPayPal,
|
|
5748
|
+
showStripe = true,
|
|
4656
5749
|
showApplePay,
|
|
4657
5750
|
showGooglePay,
|
|
4658
5751
|
theme,
|
|
@@ -4684,9 +5777,10 @@ function InterimButtonsView({
|
|
|
4684
5777
|
title: { ...base.title, ...stylesOverride.title }
|
|
4685
5778
|
};
|
|
4686
5779
|
}, [themeBundle, buttonsTheme, stylesOverride]);
|
|
5780
|
+
const skeletonRadius = themeBundle?.buttonsLayout?.cardButton?.borderRadius ?? themeBundle?.appearance.variables?.borderRadius ?? 8;
|
|
4687
5781
|
const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
4688
5782
|
height: h,
|
|
4689
|
-
borderRadius:
|
|
5783
|
+
borderRadius: skeletonRadius,
|
|
4690
5784
|
background: "#e5e7eb",
|
|
4691
5785
|
animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
|
|
4692
5786
|
} });
|
|
@@ -4757,8 +5851,28 @@ function InterimButtonsView({
|
|
|
4757
5851
|
] }),
|
|
4758
5852
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4759
5853
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex" }, children: [
|
|
4760
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
4761
|
-
|
|
5854
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
5855
|
+
flex: 1,
|
|
5856
|
+
backgroundColor: inputBg,
|
|
5857
|
+
borderTop: "none",
|
|
5858
|
+
borderRight: "none",
|
|
5859
|
+
borderBottom: `1px solid ${inputBorder}`,
|
|
5860
|
+
borderLeft: `1px solid ${inputBorder}`,
|
|
5861
|
+
borderBottomLeftRadius: 8,
|
|
5862
|
+
padding: 12,
|
|
5863
|
+
height: 45
|
|
5864
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
5865
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
5866
|
+
flex: 1,
|
|
5867
|
+
backgroundColor: inputBg,
|
|
5868
|
+
borderTop: "none",
|
|
5869
|
+
borderRight: `1px solid ${inputBorder}`,
|
|
5870
|
+
borderBottom: `1px solid ${inputBorder}`,
|
|
5871
|
+
borderLeft: `1px solid ${inputBorder}`,
|
|
5872
|
+
borderBottomRightRadius: 8,
|
|
5873
|
+
padding: 12,
|
|
5874
|
+
height: 45
|
|
5875
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
|
|
4762
5876
|
] }),
|
|
4763
5877
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
|
|
4764
5878
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
@@ -4782,8 +5896,8 @@ function InterimButtonsView({
|
|
|
4782
5896
|
}
|
|
4783
5897
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4784
5898
|
showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4785
|
-
(showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
4786
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5899
|
+
showStripe && (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
|
|
5900
|
+
showStripe && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4787
5901
|
"button",
|
|
4788
5902
|
{
|
|
4789
5903
|
type: "button",
|
|
@@ -4852,7 +5966,7 @@ var import_js5 = require("@flopay/js");
|
|
|
4852
5966
|
var import_shared9 = require("@flopay/shared");
|
|
4853
5967
|
var import_react10 = require("react");
|
|
4854
5968
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4855
|
-
var
|
|
5969
|
+
var WALLET_RESUME_KEY = "flopay_wallet_resume";
|
|
4856
5970
|
var CheckoutForm = (0, import_react10.forwardRef)(
|
|
4857
5971
|
function CheckoutForm2(props, ref) {
|
|
4858
5972
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
|
|
@@ -4978,7 +6092,7 @@ function CheckoutFormInner({
|
|
|
4978
6092
|
onDecline?.(buildDeclineEvent("paypal", message));
|
|
4979
6093
|
return;
|
|
4980
6094
|
}
|
|
4981
|
-
localStorage.setItem(
|
|
6095
|
+
localStorage.setItem(WALLET_RESUME_KEY, JSON.stringify({
|
|
4982
6096
|
sessionId,
|
|
4983
6097
|
paymentIntentId: "",
|
|
4984
6098
|
tokenType: "card",
|
|
@@ -5054,12 +6168,12 @@ function CheckoutFormInner({
|
|
|
5054
6168
|
}), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
|
|
5055
6169
|
(0, import_react10.useEffect)(() => {
|
|
5056
6170
|
if (typeof window === "undefined") return;
|
|
5057
|
-
const stored = localStorage.getItem(
|
|
6171
|
+
const stored = localStorage.getItem(WALLET_RESUME_KEY);
|
|
5058
6172
|
if (!stored) return;
|
|
5059
6173
|
try {
|
|
5060
6174
|
const payload = JSON.parse(stored);
|
|
5061
6175
|
if (payload.sessionId === sessionId) {
|
|
5062
|
-
localStorage.removeItem(
|
|
6176
|
+
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
5063
6177
|
dispatchTokenizedBody({
|
|
5064
6178
|
id: payload.tokenId,
|
|
5065
6179
|
type: payload.tokenType,
|
|
@@ -5067,7 +6181,7 @@ function CheckoutFormInner({
|
|
|
5067
6181
|
});
|
|
5068
6182
|
}
|
|
5069
6183
|
} catch {
|
|
5070
|
-
localStorage.removeItem(
|
|
6184
|
+
localStorage.removeItem(WALLET_RESUME_KEY);
|
|
5071
6185
|
}
|
|
5072
6186
|
}, [sessionId, dispatchTokenizedBody]);
|
|
5073
6187
|
const handleSubmit = (0, import_react10.useCallback)(
|
|
@@ -5412,10 +6526,12 @@ function resolveCreateSessionDraft(props) {
|
|
|
5412
6526
|
if (!props.clientId || !props.account || !props.successUrl || !props.cancelUrl) {
|
|
5413
6527
|
return null;
|
|
5414
6528
|
}
|
|
6529
|
+
const hasProducts = props.products != null;
|
|
5415
6530
|
return {
|
|
5416
6531
|
clientId: props.clientId,
|
|
5417
|
-
|
|
5418
|
-
|
|
6532
|
+
products: props.products,
|
|
6533
|
+
items: hasProducts ? void 0 : props.items,
|
|
6534
|
+
subscriptions: hasProducts ? void 0 : props.subscriptions,
|
|
5419
6535
|
account: props.account,
|
|
5420
6536
|
successUrl: props.successUrl,
|
|
5421
6537
|
cancelUrl: props.cancelUrl,
|
|
@@ -5433,6 +6549,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5433
6549
|
paymentMethodId: _deprecatedPaymentMethodId,
|
|
5434
6550
|
checkoutMethod: _deprecatedCheckoutMethod,
|
|
5435
6551
|
clientId,
|
|
6552
|
+
products,
|
|
5436
6553
|
items,
|
|
5437
6554
|
subscriptions,
|
|
5438
6555
|
account,
|
|
@@ -5463,6 +6580,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5463
6580
|
() => resolveCreateSessionDraft({
|
|
5464
6581
|
createSession,
|
|
5465
6582
|
clientId,
|
|
6583
|
+
products,
|
|
5466
6584
|
items,
|
|
5467
6585
|
subscriptions,
|
|
5468
6586
|
account,
|
|
@@ -5478,6 +6596,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5478
6596
|
clientId,
|
|
5479
6597
|
couponCodes,
|
|
5480
6598
|
createSession,
|
|
6599
|
+
products,
|
|
5481
6600
|
items,
|
|
5482
6601
|
subscriptions,
|
|
5483
6602
|
successUrl,
|
|
@@ -5766,10 +6885,20 @@ function FloPayAutomaticPaymentButton({
|
|
|
5766
6885
|
style: {
|
|
5767
6886
|
width: "100%",
|
|
5768
6887
|
...cardButtonSizing,
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
6888
|
+
// `bStyles.cardButton` first so the bundle's padding / typography
|
|
6889
|
+
// / radius / shadow come through, then `derivePrimaryTileStyle`
|
|
6890
|
+
// on top so the auto-pay button carries the *submit* button's
|
|
6891
|
+
// background and text colours — making it visually identical to
|
|
6892
|
+
// the "Confirm Payment" / "Pay with X" actions it stands in for.
|
|
6893
|
+
// Inline `style` consumer override stays at the end so explicit
|
|
6894
|
+
// per-button overrides still win.
|
|
6895
|
+
...bStyles.cardButton,
|
|
6896
|
+
...derivePrimaryTileStyle({
|
|
6897
|
+
themeBundle,
|
|
6898
|
+
resolvedPrimaryColor: themeBundle?.appearance.variables?.colorPrimary ?? "#4A49FF",
|
|
6899
|
+
resolvedBorderRadius: themeBundle?.appearance.variables?.borderRadius ?? "8px",
|
|
6900
|
+
submitButtonStyle: bStyles.submitButton
|
|
6901
|
+
}),
|
|
5773
6902
|
fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
|
|
5774
6903
|
fontWeight: 600,
|
|
5775
6904
|
cursor: disabled || isProcessing ? "not-allowed" : "pointer",
|
|
@@ -5777,11 +6906,9 @@ function FloPayAutomaticPaymentButton({
|
|
|
5777
6906
|
alignItems: "center",
|
|
5778
6907
|
justifyContent: "center",
|
|
5779
6908
|
gap: "0.625rem",
|
|
5780
|
-
boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
|
|
5781
6909
|
transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
|
|
5782
6910
|
position: "relative",
|
|
5783
6911
|
opacity: disabled || isProcessing ? 0.6 : 1,
|
|
5784
|
-
...bStyles.cardButton,
|
|
5785
6912
|
...style
|
|
5786
6913
|
},
|
|
5787
6914
|
onMouseDown: (e) => {
|