@solvapay/react 1.2.1 → 1.3.0-preview-cb8ad16e16ce8f8f357bd7f2e7068d85159df587
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/CHANGELOG.md +11 -0
- package/dist/adapters/auth0.cjs +60 -0
- package/dist/adapters/auth0.d.cts +16 -0
- package/dist/adapters/auth0.d.ts +16 -0
- package/dist/adapters/auth0.js +15 -0
- package/dist/adapters/session-auth.cjs +49 -0
- package/dist/adapters/session-auth.d.cts +20 -0
- package/dist/adapters/session-auth.d.ts +20 -0
- package/dist/adapters/session-auth.js +6 -0
- package/dist/{chunk-XRNCDI2T.js → chunk-3UR4QQ5P.js} +1 -1
- package/dist/chunk-JTW665JR.js +25 -0
- package/dist/{chunk-Y2UAJG67.js → chunk-ORMHGGOU.js} +244 -73
- package/dist/{chunk-MYD6KTR2.js → chunk-WGDHMTDO.js} +1 -1
- package/dist/{index-DPoqku6R.d.cts → index-BwwdMBdt.d.ts} +20 -5
- package/dist/{index-Cs-QqpkJ.d.ts → index-kXLvp7EU.d.cts} +20 -5
- package/dist/index.cjs +294 -106
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +8 -3
- package/dist/mcp/index.cjs +328 -70
- package/dist/mcp/index.d.cts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +131 -34
- package/dist/mcp/styles.css +39 -0
- package/dist/primitives/index.cjs +207 -38
- package/dist/primitives/index.d.cts +22 -5
- package/dist/primitives/index.d.ts +22 -5
- package/dist/primitives/index.js +6 -2
- package/dist/{shared-DpS2yEah.d.cts → shared-BNZAIWkU.d.cts} +196 -7
- package/dist/{shared-CXRbrNFw.d.ts → shared-lIhc8DS3.d.ts} +196 -7
- package/dist/styles.css +25 -0
- package/package.json +12 -7
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,7 @@ __export(index_exports, {
|
|
|
61
61
|
confirmPayment: () => confirmPayment,
|
|
62
62
|
createAnonymousAuthAdapter: () => createAnonymousAuthAdapter,
|
|
63
63
|
createHttpTransport: () => createHttpTransport,
|
|
64
|
+
createSessionAuthAdapter: () => createSessionAuthAdapter,
|
|
64
65
|
defaultAuthAdapter: () => defaultAuthAdapter,
|
|
65
66
|
deriveVariant: () => deriveVariant,
|
|
66
67
|
enCopy: () => enCopy,
|
|
@@ -263,6 +264,17 @@ async function buildRequestHeaders(config) {
|
|
|
263
264
|
return { headers, userId };
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// src/utils/readErrorMessage.ts
|
|
268
|
+
async function readErrorMessage(res, fallbackPrefix) {
|
|
269
|
+
let serverMessage;
|
|
270
|
+
try {
|
|
271
|
+
const data = await res.clone().json();
|
|
272
|
+
serverMessage = data?.error;
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
275
|
+
return serverMessage || `${fallbackPrefix}: ${res.statusText || res.status}`;
|
|
276
|
+
}
|
|
277
|
+
|
|
266
278
|
// src/transport/http.ts
|
|
267
279
|
async function request(config, url, opts) {
|
|
268
280
|
const { headers } = await buildRequestHeaders(config);
|
|
@@ -273,13 +285,8 @@ async function request(config, url, opts) {
|
|
|
273
285
|
}
|
|
274
286
|
const res = await fetchFn(url, init);
|
|
275
287
|
if (!res.ok) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const data = await res.clone().json();
|
|
279
|
-
serverMessage = data?.error;
|
|
280
|
-
} catch {
|
|
281
|
-
}
|
|
282
|
-
const error = new Error(serverMessage || `${opts.errorPrefix}: ${res.statusText || res.status}`);
|
|
288
|
+
const message = await readErrorMessage(res, opts.errorPrefix);
|
|
289
|
+
const error = new Error(message);
|
|
283
290
|
config?.onError?.(error, opts.onErrorContext);
|
|
284
291
|
throw error;
|
|
285
292
|
}
|
|
@@ -319,6 +326,7 @@ function createHttpTransport(config) {
|
|
|
319
326
|
const body = {};
|
|
320
327
|
if (params.planRef) body.planRef = params.planRef;
|
|
321
328
|
if (params.productRef) body.productRef = params.productRef;
|
|
329
|
+
if (params.currency) body.currency = params.currency;
|
|
322
330
|
if (params.customer && (params.customer.name || params.customer.email)) {
|
|
323
331
|
body.customer = params.customer;
|
|
324
332
|
}
|
|
@@ -551,6 +559,7 @@ var enCopy = {
|
|
|
551
559
|
currentBadge: "Current",
|
|
552
560
|
popularBadge: "Popular",
|
|
553
561
|
freeBadge: "Free",
|
|
562
|
+
usageRateLabel: "Usage-based",
|
|
554
563
|
perIntervalShort: "/{interval}",
|
|
555
564
|
continueButton: "Continue",
|
|
556
565
|
backButton: "\u2190 Back to plans",
|
|
@@ -1426,7 +1435,7 @@ var MissingProductRefError = class extends SolvaPayError {
|
|
|
1426
1435
|
};
|
|
1427
1436
|
|
|
1428
1437
|
// src/hooks/useCheckout.ts
|
|
1429
|
-
var
|
|
1438
|
+
var import_react7 = require("react");
|
|
1430
1439
|
var import_stripe_js = require("@stripe/stripe-js");
|
|
1431
1440
|
|
|
1432
1441
|
// src/hooks/useSolvaPay.ts
|
|
@@ -1441,6 +1450,18 @@ function useSolvaPay() {
|
|
|
1441
1450
|
return context;
|
|
1442
1451
|
}
|
|
1443
1452
|
|
|
1453
|
+
// src/components/PlanSelectionContext.tsx
|
|
1454
|
+
var import_react6 = require("react");
|
|
1455
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1456
|
+
var PlanSelectionContext = (0, import_react6.createContext)(null);
|
|
1457
|
+
var PlanSelectionProvider = ({
|
|
1458
|
+
value,
|
|
1459
|
+
children
|
|
1460
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlanSelectionContext.Provider, { value, children });
|
|
1461
|
+
function usePlanSelection() {
|
|
1462
|
+
return (0, import_react6.useContext)(PlanSelectionContext);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1444
1465
|
// src/hooks/useCheckout.ts
|
|
1445
1466
|
var stripePromiseCache = /* @__PURE__ */ new Map();
|
|
1446
1467
|
function getStripeCacheKey(publishableKey, accountId) {
|
|
@@ -1453,7 +1474,11 @@ async function resolvePlanRef(productRef, config) {
|
|
|
1453
1474
|
const { headers } = await buildRequestHeaders(config);
|
|
1454
1475
|
const res = await fetchFn(url, { method: "GET", headers });
|
|
1455
1476
|
if (!res.ok) {
|
|
1456
|
-
|
|
1477
|
+
const message = await readErrorMessage(
|
|
1478
|
+
res,
|
|
1479
|
+
`Failed to fetch plans for product "${productRef}"`
|
|
1480
|
+
);
|
|
1481
|
+
throw new Error(message);
|
|
1457
1482
|
}
|
|
1458
1483
|
const data = await res.json();
|
|
1459
1484
|
const allPlans = data.plans ?? [];
|
|
@@ -1475,15 +1500,16 @@ async function resolvePlanRef(productRef, config) {
|
|
|
1475
1500
|
);
|
|
1476
1501
|
}
|
|
1477
1502
|
function useCheckout(options) {
|
|
1478
|
-
const { planRef, productRef, customer } = options;
|
|
1503
|
+
const { planRef, productRef, currency: currencyOverride, customer } = options;
|
|
1504
|
+
const planSelection = usePlanSelection();
|
|
1479
1505
|
const { createPayment, customerRef, updateCustomerRef, _config } = useSolvaPay();
|
|
1480
|
-
const [loading, setLoading] = (0,
|
|
1481
|
-
const [error, setError] = (0,
|
|
1482
|
-
const [stripePromise, setStripePromise] = (0,
|
|
1483
|
-
const [clientSecret, setClientSecret] = (0,
|
|
1484
|
-
const [resolvedPlanRef, setResolvedPlanRef] = (0,
|
|
1485
|
-
const isStartingRef = (0,
|
|
1486
|
-
const startCheckout = (0,
|
|
1506
|
+
const [loading, setLoading] = (0, import_react7.useState)(false);
|
|
1507
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
1508
|
+
const [stripePromise, setStripePromise] = (0, import_react7.useState)(null);
|
|
1509
|
+
const [clientSecret, setClientSecret] = (0, import_react7.useState)(null);
|
|
1510
|
+
const [resolvedPlanRef, setResolvedPlanRef] = (0, import_react7.useState)(planRef || null);
|
|
1511
|
+
const isStartingRef = (0, import_react7.useRef)(false);
|
|
1512
|
+
const startCheckout = (0, import_react7.useCallback)(async () => {
|
|
1487
1513
|
if (isStartingRef.current || loading) {
|
|
1488
1514
|
return;
|
|
1489
1515
|
}
|
|
@@ -1507,9 +1533,11 @@ function useCheckout(options) {
|
|
|
1507
1533
|
if (!effectivePlanRef) {
|
|
1508
1534
|
throw new Error("Could not determine plan reference for checkout");
|
|
1509
1535
|
}
|
|
1536
|
+
const selectedCurrency = currencyOverride ?? planSelection?.selectedCurrency ?? void 0;
|
|
1510
1537
|
const result = await createPayment({
|
|
1511
1538
|
planRef: effectivePlanRef,
|
|
1512
1539
|
productRef,
|
|
1540
|
+
...selectedCurrency && { currency: selectedCurrency },
|
|
1513
1541
|
customer
|
|
1514
1542
|
});
|
|
1515
1543
|
if (!result || typeof result !== "object") {
|
|
@@ -1543,8 +1571,18 @@ function useCheckout(options) {
|
|
|
1543
1571
|
setLoading(false);
|
|
1544
1572
|
isStartingRef.current = false;
|
|
1545
1573
|
}
|
|
1546
|
-
}, [
|
|
1547
|
-
|
|
1574
|
+
}, [
|
|
1575
|
+
planRef,
|
|
1576
|
+
productRef,
|
|
1577
|
+
currencyOverride,
|
|
1578
|
+
planSelection?.selectedCurrency,
|
|
1579
|
+
customer,
|
|
1580
|
+
createPayment,
|
|
1581
|
+
updateCustomerRef,
|
|
1582
|
+
loading,
|
|
1583
|
+
_config
|
|
1584
|
+
]);
|
|
1585
|
+
const reset = (0, import_react7.useCallback)(() => {
|
|
1548
1586
|
isStartingRef.current = false;
|
|
1549
1587
|
setLoading(false);
|
|
1550
1588
|
setError(null);
|
|
@@ -1584,10 +1622,10 @@ function useCustomer() {
|
|
|
1584
1622
|
}
|
|
1585
1623
|
|
|
1586
1624
|
// src/hooks/usePlan.ts
|
|
1587
|
-
var
|
|
1625
|
+
var import_react9 = require("react");
|
|
1588
1626
|
|
|
1589
1627
|
// src/hooks/usePlans.ts
|
|
1590
|
-
var
|
|
1628
|
+
var import_react8 = require("react");
|
|
1591
1629
|
var plansCache = /* @__PURE__ */ new Map();
|
|
1592
1630
|
var CACHE_DURATION2 = 5 * 60 * 1e3;
|
|
1593
1631
|
function processPlans(raw, filter, sortBy) {
|
|
@@ -1617,21 +1655,21 @@ function usePlans(options) {
|
|
|
1617
1655
|
initialPlanRef,
|
|
1618
1656
|
selectionReady = true
|
|
1619
1657
|
} = options;
|
|
1620
|
-
const solvaContext = (0,
|
|
1658
|
+
const solvaContext = (0, import_react8.useContext)(SolvaPayContext);
|
|
1621
1659
|
const config = solvaContext?._config;
|
|
1622
|
-
const effectiveFetcher = (0,
|
|
1660
|
+
const effectiveFetcher = (0, import_react8.useMemo)(
|
|
1623
1661
|
() => fetcher ?? ((ref) => defaultListPlans(ref, config)),
|
|
1624
1662
|
[fetcher, config]
|
|
1625
1663
|
);
|
|
1626
|
-
const fetcherRef = (0,
|
|
1627
|
-
const filterRef = (0,
|
|
1628
|
-
const sortByRef = (0,
|
|
1629
|
-
const autoSelectFirstPaidRef = (0,
|
|
1630
|
-
const initialPlanRefRef = (0,
|
|
1631
|
-
const selectionReadyRef = (0,
|
|
1632
|
-
const hasAppliedInitialRef = (0,
|
|
1633
|
-
const userHasSelectedRef = (0,
|
|
1634
|
-
const [selectedPlanIndex, setSelectedPlanIndexState] = (0,
|
|
1664
|
+
const fetcherRef = (0, import_react8.useRef)(effectiveFetcher);
|
|
1665
|
+
const filterRef = (0, import_react8.useRef)(filter);
|
|
1666
|
+
const sortByRef = (0, import_react8.useRef)(sortBy);
|
|
1667
|
+
const autoSelectFirstPaidRef = (0, import_react8.useRef)(autoSelectFirstPaid);
|
|
1668
|
+
const initialPlanRefRef = (0, import_react8.useRef)(initialPlanRef);
|
|
1669
|
+
const selectionReadyRef = (0, import_react8.useRef)(selectionReady);
|
|
1670
|
+
const hasAppliedInitialRef = (0, import_react8.useRef)(false);
|
|
1671
|
+
const userHasSelectedRef = (0, import_react8.useRef)(false);
|
|
1672
|
+
const [selectedPlanIndex, setSelectedPlanIndexState] = (0, import_react8.useState)(() => {
|
|
1635
1673
|
if (!selectionReady || !productRef) return 0;
|
|
1636
1674
|
const cached = plansCache.get(productRef);
|
|
1637
1675
|
if (!cached || Date.now() - cached.timestamp >= CACHE_DURATION2 || cached.plans.length === 0) {
|
|
@@ -1643,7 +1681,7 @@ function usePlans(options) {
|
|
|
1643
1681
|
hasAppliedInitialRef.current = true;
|
|
1644
1682
|
return idx;
|
|
1645
1683
|
});
|
|
1646
|
-
const [plans, setPlans] = (0,
|
|
1684
|
+
const [plans, setPlans] = (0, import_react8.useState)(() => {
|
|
1647
1685
|
if (!productRef) return [];
|
|
1648
1686
|
const cached = plansCache.get(productRef);
|
|
1649
1687
|
if (!cached || Date.now() - cached.timestamp >= CACHE_DURATION2 || cached.plans.length === 0) {
|
|
@@ -1651,31 +1689,31 @@ function usePlans(options) {
|
|
|
1651
1689
|
}
|
|
1652
1690
|
return processPlans(cached.plans, filter, sortBy);
|
|
1653
1691
|
});
|
|
1654
|
-
const [loading, setLoading] = (0,
|
|
1655
|
-
const [error, setError] = (0,
|
|
1656
|
-
(0,
|
|
1692
|
+
const [loading, setLoading] = (0, import_react8.useState)(() => plans.length === 0);
|
|
1693
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1694
|
+
(0, import_react8.useEffect)(() => {
|
|
1657
1695
|
fetcherRef.current = effectiveFetcher;
|
|
1658
1696
|
}, [effectiveFetcher]);
|
|
1659
|
-
(0,
|
|
1697
|
+
(0, import_react8.useEffect)(() => {
|
|
1660
1698
|
filterRef.current = filter;
|
|
1661
1699
|
}, [filter]);
|
|
1662
|
-
(0,
|
|
1700
|
+
(0, import_react8.useEffect)(() => {
|
|
1663
1701
|
sortByRef.current = sortBy;
|
|
1664
1702
|
}, [sortBy]);
|
|
1665
|
-
(0,
|
|
1703
|
+
(0, import_react8.useEffect)(() => {
|
|
1666
1704
|
autoSelectFirstPaidRef.current = autoSelectFirstPaid;
|
|
1667
1705
|
}, [autoSelectFirstPaid]);
|
|
1668
|
-
(0,
|
|
1706
|
+
(0, import_react8.useEffect)(() => {
|
|
1669
1707
|
initialPlanRefRef.current = initialPlanRef;
|
|
1670
1708
|
}, [initialPlanRef]);
|
|
1671
|
-
(0,
|
|
1709
|
+
(0, import_react8.useEffect)(() => {
|
|
1672
1710
|
selectionReadyRef.current = selectionReady;
|
|
1673
1711
|
}, [selectionReady]);
|
|
1674
|
-
const setSelectedPlanIndex = (0,
|
|
1712
|
+
const setSelectedPlanIndex = (0, import_react8.useCallback)((index) => {
|
|
1675
1713
|
userHasSelectedRef.current = true;
|
|
1676
1714
|
setSelectedPlanIndexState(index);
|
|
1677
1715
|
}, []);
|
|
1678
|
-
const applyInitialSelection = (0,
|
|
1716
|
+
const applyInitialSelection = (0, import_react8.useCallback)((processedPlans) => {
|
|
1679
1717
|
if (hasAppliedInitialRef.current || userHasSelectedRef.current) return;
|
|
1680
1718
|
if (!selectionReadyRef.current || processedPlans.length === 0) return;
|
|
1681
1719
|
hasAppliedInitialRef.current = true;
|
|
@@ -1686,7 +1724,7 @@ function usePlans(options) {
|
|
|
1686
1724
|
);
|
|
1687
1725
|
setSelectedPlanIndexState(idx);
|
|
1688
1726
|
}, []);
|
|
1689
|
-
const fetchPlans = (0,
|
|
1727
|
+
const fetchPlans = (0, import_react8.useCallback)(
|
|
1690
1728
|
async (force = false) => {
|
|
1691
1729
|
if (!productRef) {
|
|
1692
1730
|
setError(new Error("Product reference not configured"));
|
|
@@ -1749,16 +1787,16 @@ function usePlans(options) {
|
|
|
1749
1787
|
},
|
|
1750
1788
|
[productRef, applyInitialSelection]
|
|
1751
1789
|
);
|
|
1752
|
-
(0,
|
|
1790
|
+
(0, import_react8.useEffect)(() => {
|
|
1753
1791
|
fetchPlans();
|
|
1754
1792
|
}, [fetchPlans]);
|
|
1755
|
-
(0,
|
|
1793
|
+
(0, import_react8.useEffect)(() => {
|
|
1756
1794
|
if (hasAppliedInitialRef.current || userHasSelectedRef.current) return;
|
|
1757
1795
|
if (!selectionReady || plans.length === 0) return;
|
|
1758
1796
|
applyInitialSelection(plans);
|
|
1759
1797
|
}, [selectionReady, plans, applyInitialSelection]);
|
|
1760
|
-
const selectedPlan = (0,
|
|
1761
|
-
const selectPlan = (0,
|
|
1798
|
+
const selectedPlan = (0, import_react8.useMemo)(() => plans[selectedPlanIndex] || null, [plans, selectedPlanIndex]);
|
|
1799
|
+
const selectPlan = (0, import_react8.useCallback)(
|
|
1762
1800
|
(planRef) => {
|
|
1763
1801
|
const index = plans.findIndex((p) => p.reference === planRef);
|
|
1764
1802
|
if (index >= 0) {
|
|
@@ -1792,7 +1830,8 @@ async function defaultListPlans(productRef, config) {
|
|
|
1792
1830
|
const { headers } = await buildRequestHeaders(config);
|
|
1793
1831
|
const res = await fetchFn(url, { method: "GET", headers });
|
|
1794
1832
|
if (!res.ok) {
|
|
1795
|
-
const
|
|
1833
|
+
const message = await readErrorMessage(res, "Failed to fetch plans");
|
|
1834
|
+
const error = new Error(message);
|
|
1796
1835
|
config?.onError?.(error, "listPlans");
|
|
1797
1836
|
throw error;
|
|
1798
1837
|
}
|
|
@@ -1804,22 +1843,22 @@ async function defaultListPlans(productRef, config) {
|
|
|
1804
1843
|
function usePlan(options) {
|
|
1805
1844
|
const { planRef, productRef } = options;
|
|
1806
1845
|
const { _config } = useSolvaPay();
|
|
1807
|
-
const findPlan = (0,
|
|
1846
|
+
const findPlan = (0, import_react9.useCallback)(
|
|
1808
1847
|
(plans) => {
|
|
1809
1848
|
if (!planRef) return null;
|
|
1810
1849
|
return plans.find((p) => p.reference === planRef) || null;
|
|
1811
1850
|
},
|
|
1812
1851
|
[planRef]
|
|
1813
1852
|
);
|
|
1814
|
-
const [plan, setPlan] = (0,
|
|
1853
|
+
const [plan, setPlan] = (0, import_react9.useState)(() => {
|
|
1815
1854
|
if (!planRef || !productRef) return null;
|
|
1816
1855
|
const cached = plansCache.get(productRef);
|
|
1817
1856
|
if (!cached || Date.now() - cached.timestamp >= CACHE_DURATION2) return null;
|
|
1818
1857
|
return findPlan(cached.plans);
|
|
1819
1858
|
});
|
|
1820
|
-
const [loading, setLoading] = (0,
|
|
1821
|
-
const [error, setError] = (0,
|
|
1822
|
-
const load = (0,
|
|
1859
|
+
const [loading, setLoading] = (0, import_react9.useState)(() => !!(planRef && !plan));
|
|
1860
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
1861
|
+
const load = (0, import_react9.useCallback)(
|
|
1823
1862
|
async (force = false) => {
|
|
1824
1863
|
if (!planRef) {
|
|
1825
1864
|
setPlan(null);
|
|
@@ -1886,7 +1925,7 @@ function usePlan(options) {
|
|
|
1886
1925
|
},
|
|
1887
1926
|
[planRef, productRef, _config, findPlan]
|
|
1888
1927
|
);
|
|
1889
|
-
(0,
|
|
1928
|
+
(0, import_react9.useEffect)(() => {
|
|
1890
1929
|
load();
|
|
1891
1930
|
}, [load]);
|
|
1892
1931
|
return {
|
|
@@ -1898,7 +1937,7 @@ function usePlan(options) {
|
|
|
1898
1937
|
}
|
|
1899
1938
|
|
|
1900
1939
|
// src/hooks/useProduct.ts
|
|
1901
|
-
var
|
|
1940
|
+
var import_react10 = require("react");
|
|
1902
1941
|
|
|
1903
1942
|
// src/transport/cache-key.ts
|
|
1904
1943
|
var transportIds = /* @__PURE__ */ new WeakMap();
|
|
@@ -1934,16 +1973,16 @@ async function fetchProduct(productRef, config) {
|
|
|
1934
1973
|
function useProduct(productRef) {
|
|
1935
1974
|
const { _config } = useSolvaPay();
|
|
1936
1975
|
const cacheKey2 = productRef ? cacheKeyFor(_config, productRef) : "";
|
|
1937
|
-
const [product, setProduct] = (0,
|
|
1976
|
+
const [product, setProduct] = (0, import_react10.useState)(
|
|
1938
1977
|
() => productRef ? productCache.get(cacheKey2)?.product ?? null : null
|
|
1939
1978
|
);
|
|
1940
|
-
const [loading, setLoading] = (0,
|
|
1979
|
+
const [loading, setLoading] = (0, import_react10.useState)(() => {
|
|
1941
1980
|
if (!productRef) return false;
|
|
1942
1981
|
const cached = productCache.get(cacheKey2);
|
|
1943
1982
|
return !cached || !cached.product && !cached.promise;
|
|
1944
1983
|
});
|
|
1945
|
-
const [error, setError] = (0,
|
|
1946
|
-
const load = (0,
|
|
1984
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1985
|
+
const load = (0, import_react10.useCallback)(
|
|
1947
1986
|
async (force = false) => {
|
|
1948
1987
|
if (!productRef) {
|
|
1949
1988
|
setProduct(null);
|
|
@@ -2004,7 +2043,7 @@ function useProduct(productRef) {
|
|
|
2004
2043
|
},
|
|
2005
2044
|
[productRef, _config]
|
|
2006
2045
|
);
|
|
2007
|
-
(0,
|
|
2046
|
+
(0, import_react10.useEffect)(() => {
|
|
2008
2047
|
load();
|
|
2009
2048
|
}, [load]);
|
|
2010
2049
|
return {
|
|
@@ -2016,14 +2055,14 @@ function useProduct(productRef) {
|
|
|
2016
2055
|
}
|
|
2017
2056
|
|
|
2018
2057
|
// src/hooks/useActivation.ts
|
|
2019
|
-
var
|
|
2058
|
+
var import_react11 = require("react");
|
|
2020
2059
|
function useActivation() {
|
|
2021
2060
|
const { activatePlan } = useSolvaPay();
|
|
2022
2061
|
const copy = useCopy();
|
|
2023
|
-
const [state, setState] = (0,
|
|
2024
|
-
const [error, setError] = (0,
|
|
2025
|
-
const [result, setResult] = (0,
|
|
2026
|
-
const activate = (0,
|
|
2062
|
+
const [state, setState] = (0, import_react11.useState)("idle");
|
|
2063
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
2064
|
+
const [result, setResult] = (0, import_react11.useState)(null);
|
|
2065
|
+
const activate = (0, import_react11.useCallback)(
|
|
2027
2066
|
async (params) => {
|
|
2028
2067
|
setState("activating");
|
|
2029
2068
|
setError(null);
|
|
@@ -2058,7 +2097,7 @@ function useActivation() {
|
|
|
2058
2097
|
},
|
|
2059
2098
|
[activatePlan, copy]
|
|
2060
2099
|
);
|
|
2061
|
-
const reset = (0,
|
|
2100
|
+
const reset = (0, import_react11.useCallback)(() => {
|
|
2062
2101
|
setState("idle");
|
|
2063
2102
|
setError(null);
|
|
2064
2103
|
setResult(null);
|
|
@@ -2066,18 +2105,6 @@ function useActivation() {
|
|
|
2066
2105
|
return { activate, state, error, result, reset };
|
|
2067
2106
|
}
|
|
2068
2107
|
|
|
2069
|
-
// src/components/PlanSelectionContext.tsx
|
|
2070
|
-
var import_react11 = require("react");
|
|
2071
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2072
|
-
var PlanSelectionContext = (0, import_react11.createContext)(null);
|
|
2073
|
-
var PlanSelectionProvider = ({
|
|
2074
|
-
value,
|
|
2075
|
-
children
|
|
2076
|
-
}) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlanSelectionContext.Provider, { value, children });
|
|
2077
|
-
function usePlanSelection() {
|
|
2078
|
-
return (0, import_react11.useContext)(PlanSelectionContext);
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
2108
|
// src/components/PaymentFormContext.tsx
|
|
2082
2109
|
var import_react12 = require("react");
|
|
2083
2110
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
@@ -2126,7 +2153,7 @@ function toMajorUnits(amountMinor, currency) {
|
|
|
2126
2153
|
return fractionDigits === 0 ? amountMinor : amountMinor / 100;
|
|
2127
2154
|
}
|
|
2128
2155
|
function formatPrice(amountMinor, currency, opts = {}) {
|
|
2129
|
-
const { locale, interval, intervalCount = 1, free = "Free" } = opts;
|
|
2156
|
+
const { locale, interval, intervalCount = 1, free = "Free", currencyDisplay } = opts;
|
|
2130
2157
|
if (amountMinor === 0 && free !== "") {
|
|
2131
2158
|
return free;
|
|
2132
2159
|
}
|
|
@@ -2135,12 +2162,16 @@ function formatPrice(amountMinor, currency, opts = {}) {
|
|
|
2135
2162
|
const isWhole = amountMinor % minorPerMajor === 0;
|
|
2136
2163
|
const fractionDigits = isWhole ? 0 : naturalFractionDigits;
|
|
2137
2164
|
const major = toMajorUnits(amountMinor, currency);
|
|
2138
|
-
const
|
|
2165
|
+
const formatterOptions = {
|
|
2139
2166
|
style: "currency",
|
|
2140
2167
|
currency: currency.toUpperCase(),
|
|
2141
2168
|
minimumFractionDigits: fractionDigits,
|
|
2142
2169
|
maximumFractionDigits: fractionDigits
|
|
2143
|
-
}
|
|
2170
|
+
};
|
|
2171
|
+
if (currencyDisplay) {
|
|
2172
|
+
formatterOptions.currencyDisplay = currencyDisplay;
|
|
2173
|
+
}
|
|
2174
|
+
const formatter = new Intl.NumberFormat(locale, formatterOptions);
|
|
2144
2175
|
const formatted = formatter.format(major);
|
|
2145
2176
|
if (!interval) return formatted;
|
|
2146
2177
|
const suffix = intervalCount > 1 ? `${intervalCount} ${interval}s` : interval;
|
|
@@ -4376,6 +4407,28 @@ function isPaygPlan(plan) {
|
|
|
4376
4407
|
return type === "usage-based" || type === "hybrid";
|
|
4377
4408
|
}
|
|
4378
4409
|
|
|
4410
|
+
// src/utils/planPricing.ts
|
|
4411
|
+
function getPlanPricingOptions(plan) {
|
|
4412
|
+
if (plan.pricingOptions && plan.pricingOptions.length > 0) {
|
|
4413
|
+
return plan.pricingOptions;
|
|
4414
|
+
}
|
|
4415
|
+
return [
|
|
4416
|
+
{
|
|
4417
|
+
currency: plan.currency ?? "USD",
|
|
4418
|
+
price: plan.price ?? 0,
|
|
4419
|
+
default: true
|
|
4420
|
+
}
|
|
4421
|
+
];
|
|
4422
|
+
}
|
|
4423
|
+
function resolvePlanPricingOption(plan, currency) {
|
|
4424
|
+
const options = getPlanPricingOptions(plan);
|
|
4425
|
+
if (currency) {
|
|
4426
|
+
const match = options.find((option) => option.currency.toUpperCase() === currency.toUpperCase());
|
|
4427
|
+
if (match) return match;
|
|
4428
|
+
}
|
|
4429
|
+
return options.find((option) => option.default) ?? options[0];
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4379
4432
|
// src/primitives/PlanSelector.tsx
|
|
4380
4433
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
4381
4434
|
var PlanSelectorContext = (0, import_react26.createContext)(null);
|
|
@@ -4456,6 +4509,23 @@ var Root6 = (0, import_react26.forwardRef)(function PlanSelectorRoot(props, forw
|
|
|
4456
4509
|
setSelectedPlanIndex(-1);
|
|
4457
4510
|
}, [setSelectedPlanIndex]);
|
|
4458
4511
|
const selectedPlanRef = selectedPlan?.reference ?? null;
|
|
4512
|
+
const [preferredCurrency, setPreferredCurrencyState] = (0, import_react26.useState)(null);
|
|
4513
|
+
const [selectedCurrencies, setSelectedCurrencies] = (0, import_react26.useState)({});
|
|
4514
|
+
const getSelectedOption = (0, import_react26.useCallback)(
|
|
4515
|
+
(plan) => resolvePlanPricingOption(
|
|
4516
|
+
plan,
|
|
4517
|
+
selectedCurrencies[plan.reference] ?? preferredCurrency ?? null
|
|
4518
|
+
),
|
|
4519
|
+
[selectedCurrencies, preferredCurrency]
|
|
4520
|
+
);
|
|
4521
|
+
const setPreferredCurrency = (0, import_react26.useCallback)((currency) => {
|
|
4522
|
+
setPreferredCurrencyState(currency.toUpperCase());
|
|
4523
|
+
setSelectedCurrencies({});
|
|
4524
|
+
}, []);
|
|
4525
|
+
const setPlanCurrency = (0, import_react26.useCallback)((planRef, currency) => {
|
|
4526
|
+
setSelectedCurrencies((current) => ({ ...current, [planRef]: currency }));
|
|
4527
|
+
}, []);
|
|
4528
|
+
const selectedCurrency = selectedPlan ? getSelectedOption(selectedPlan).currency : null;
|
|
4459
4529
|
const autoCurrentAppliedKeyRef = (0, import_react26.useRef)(null);
|
|
4460
4530
|
(0, import_react26.useEffect)(() => {
|
|
4461
4531
|
if (autoCurrentAppliedKeyRef.current === productRef) return;
|
|
@@ -4485,7 +4555,12 @@ var Root6 = (0, import_react26.forwardRef)(function PlanSelectorRoot(props, forw
|
|
|
4485
4555
|
isFree,
|
|
4486
4556
|
isPopular,
|
|
4487
4557
|
select,
|
|
4488
|
-
clearSelection
|
|
4558
|
+
clearSelection,
|
|
4559
|
+
preferredCurrency,
|
|
4560
|
+
setPreferredCurrency,
|
|
4561
|
+
selectedCurrencies,
|
|
4562
|
+
setPlanCurrency,
|
|
4563
|
+
getSelectedOption
|
|
4489
4564
|
}),
|
|
4490
4565
|
[
|
|
4491
4566
|
plans,
|
|
@@ -4499,7 +4574,12 @@ var Root6 = (0, import_react26.forwardRef)(function PlanSelectorRoot(props, forw
|
|
|
4499
4574
|
isFree,
|
|
4500
4575
|
isPopular,
|
|
4501
4576
|
select,
|
|
4502
|
-
clearSelection
|
|
4577
|
+
clearSelection,
|
|
4578
|
+
preferredCurrency,
|
|
4579
|
+
setPreferredCurrency,
|
|
4580
|
+
selectedCurrencies,
|
|
4581
|
+
setPlanCurrency,
|
|
4582
|
+
getSelectedOption
|
|
4503
4583
|
]
|
|
4504
4584
|
);
|
|
4505
4585
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
@@ -4511,6 +4591,12 @@ var Root6 = (0, import_react26.forwardRef)(function PlanSelectorRoot(props, forw
|
|
|
4511
4591
|
setSelectedPlanRef: (ref) => {
|
|
4512
4592
|
if (ref) select(ref);
|
|
4513
4593
|
},
|
|
4594
|
+
selectedCurrency,
|
|
4595
|
+
setSelectedCurrency: (currency) => {
|
|
4596
|
+
if (currency) {
|
|
4597
|
+
setPreferredCurrency(currency);
|
|
4598
|
+
}
|
|
4599
|
+
},
|
|
4514
4600
|
plans,
|
|
4515
4601
|
loading,
|
|
4516
4602
|
error
|
|
@@ -4535,14 +4621,19 @@ var Grid = (0, import_react26.forwardRef)(function PlanSelectorGrid({ children,
|
|
|
4535
4621
|
const isPaygCurrent = isCurrent && isPaygPlan(plan);
|
|
4536
4622
|
const disabled = isFree || isCurrent && !isPaygCurrent;
|
|
4537
4623
|
const state = isCurrent && !isPaygCurrent ? "current" : selected ? "selected" : isCurrent ? "current" : isFree ? "disabled" : "idle";
|
|
4624
|
+
const pricingOptions = getPlanPricingOptions(plan);
|
|
4625
|
+
const selectedOption = ctx.getSelectedOption(plan);
|
|
4538
4626
|
const cardCtx = {
|
|
4539
4627
|
plan,
|
|
4628
|
+
selectedOption,
|
|
4629
|
+
pricingOptions,
|
|
4540
4630
|
state,
|
|
4541
4631
|
isCurrent,
|
|
4542
4632
|
isFree,
|
|
4543
4633
|
isPopular,
|
|
4544
4634
|
disabled,
|
|
4545
|
-
select: () => ctx.select(plan.reference)
|
|
4635
|
+
select: () => ctx.select(plan.reference),
|
|
4636
|
+
setCurrency: (currency) => ctx.setPlanCurrency(plan.reference, currency)
|
|
4546
4637
|
};
|
|
4547
4638
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CardContext.Provider, { value: cardCtx, children }, plan.reference);
|
|
4548
4639
|
}) });
|
|
@@ -4594,26 +4685,20 @@ var CardPrice = (0, import_react26.forwardRef)(function PlanSelectorCardPrice({
|
|
|
4594
4685
|
const formatted = (0, import_react26.useMemo)(() => {
|
|
4595
4686
|
if (card.isFree) return copy.planSelector.freeBadge;
|
|
4596
4687
|
if (card.plan.type === "usage-based") {
|
|
4597
|
-
|
|
4598
|
-
const perCallMinor = Math.max(1, Math.round(1 / creditsPerUnit));
|
|
4599
|
-
const rate = formatPrice(perCallMinor, card.plan.currency ?? "usd", {
|
|
4600
|
-
locale,
|
|
4601
|
-
free: ""
|
|
4602
|
-
});
|
|
4603
|
-
return `${rate} / call`;
|
|
4688
|
+
return copy.planSelector.usageRateLabel;
|
|
4604
4689
|
}
|
|
4605
|
-
return formatPrice(card.
|
|
4690
|
+
return formatPrice(card.selectedOption.price ?? 0, card.selectedOption.currency ?? "usd", {
|
|
4606
4691
|
locale,
|
|
4607
4692
|
free: copy.interval.free
|
|
4608
4693
|
});
|
|
4609
4694
|
}, [
|
|
4610
4695
|
card.isFree,
|
|
4611
4696
|
card.plan.type,
|
|
4612
|
-
card.
|
|
4613
|
-
card.
|
|
4614
|
-
card.plan.creditsPerUnit,
|
|
4697
|
+
card.selectedOption.price,
|
|
4698
|
+
card.selectedOption.currency,
|
|
4615
4699
|
locale,
|
|
4616
4700
|
copy.planSelector.freeBadge,
|
|
4701
|
+
copy.planSelector.usageRateLabel,
|
|
4617
4702
|
copy.interval.free
|
|
4618
4703
|
]);
|
|
4619
4704
|
const Comp = asChild ? Slot : "span";
|
|
@@ -4638,6 +4723,57 @@ function normalizeBillingCycle(cycle) {
|
|
|
4638
4723
|
if (lc === "daily" || lc === "day") return "day";
|
|
4639
4724
|
return cycle;
|
|
4640
4725
|
}
|
|
4726
|
+
var CurrencySwitcher = (0, import_react26.forwardRef)(function PlanSelectorCurrencySwitcher({ children, onChange, className, ...rest }, forwardedRef) {
|
|
4727
|
+
const ctx = usePlanSelectorContext("CurrencySwitcher");
|
|
4728
|
+
const availableCurrencies = (0, import_react26.useMemo)(() => {
|
|
4729
|
+
const currencies = /* @__PURE__ */ new Set();
|
|
4730
|
+
for (const plan of ctx.plans) {
|
|
4731
|
+
const options = getPlanPricingOptions(plan);
|
|
4732
|
+
if (options.length <= 1) continue;
|
|
4733
|
+
for (const option of options) {
|
|
4734
|
+
currencies.add(option.currency.toUpperCase());
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
return [...currencies].sort();
|
|
4738
|
+
}, [ctx.plans]);
|
|
4739
|
+
if (availableCurrencies.length < 2) return null;
|
|
4740
|
+
const effectiveCurrency = ctx.preferredCurrency ?? (ctx.selectedPlan ? ctx.getSelectedOption(ctx.selectedPlan).currency.toUpperCase() : null) ?? availableCurrencies[0];
|
|
4741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4742
|
+
"select",
|
|
4743
|
+
{
|
|
4744
|
+
ref: forwardedRef,
|
|
4745
|
+
"data-solvapay-plan-selector-currency-switcher": "",
|
|
4746
|
+
className,
|
|
4747
|
+
value: effectiveCurrency,
|
|
4748
|
+
onChange: (event) => {
|
|
4749
|
+
ctx.setPreferredCurrency(event.target.value);
|
|
4750
|
+
onChange?.(event);
|
|
4751
|
+
},
|
|
4752
|
+
...rest,
|
|
4753
|
+
children: children ?? availableCurrencies.map((currency) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: currency, children: currency }, currency))
|
|
4754
|
+
}
|
|
4755
|
+
);
|
|
4756
|
+
});
|
|
4757
|
+
var CardCurrency = (0, import_react26.forwardRef)(
|
|
4758
|
+
function PlanSelectorCardCurrency({ children, onChange, ...rest }, forwardedRef) {
|
|
4759
|
+
const card = useCardContext("CardCurrency");
|
|
4760
|
+
if (card.pricingOptions.length <= 1) return null;
|
|
4761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4762
|
+
"select",
|
|
4763
|
+
{
|
|
4764
|
+
ref: forwardedRef,
|
|
4765
|
+
"data-solvapay-plan-selector-card-currency": "",
|
|
4766
|
+
value: card.selectedOption.currency,
|
|
4767
|
+
onChange: (event) => {
|
|
4768
|
+
card.setCurrency(event.target.value);
|
|
4769
|
+
onChange?.(event);
|
|
4770
|
+
},
|
|
4771
|
+
...rest,
|
|
4772
|
+
children: children ?? card.pricingOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: option.currency, children: option.currency }, option.currency))
|
|
4773
|
+
}
|
|
4774
|
+
);
|
|
4775
|
+
}
|
|
4776
|
+
);
|
|
4641
4777
|
var CardBadge = (0, import_react26.forwardRef)(function PlanSelectorCardBadge({ asChild, children, ...rest }, forwardedRef) {
|
|
4642
4778
|
const card = useCardContext("CardBadge");
|
|
4643
4779
|
const copy = useCopy();
|
|
@@ -4683,6 +4819,8 @@ var PlanSelector = {
|
|
|
4683
4819
|
CardName,
|
|
4684
4820
|
CardPrice,
|
|
4685
4821
|
CardInterval,
|
|
4822
|
+
CurrencySwitcher,
|
|
4823
|
+
CardCurrency,
|
|
4686
4824
|
CardBadge,
|
|
4687
4825
|
Loading: Loading4,
|
|
4688
4826
|
Error: ErrorSlot4
|
|
@@ -4695,6 +4833,7 @@ function usePlanSelector() {
|
|
|
4695
4833
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4696
4834
|
var DefaultTree2 = () => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4697
4835
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PlanSelector.Heading, { className: "solvapay-plan-selector-heading" }),
|
|
4836
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PlanSelector.CurrencySwitcher, { className: "solvapay-plan-selector-currency-switcher" }),
|
|
4698
4837
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PlanSelector.Grid, { className: "solvapay-plan-selector-grid", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(PlanSelector.Card, { className: "solvapay-plan-selector-card", children: [
|
|
4699
4838
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PlanSelector.CardBadge, { className: "solvapay-plan-selector-card-badge" }),
|
|
4700
4839
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PlanSelector.CardName, { className: "solvapay-plan-selector-card-name" }),
|
|
@@ -6921,21 +7060,21 @@ function buildDefaultCheckoutPlanFilter(allPlans) {
|
|
|
6921
7060
|
return true;
|
|
6922
7061
|
};
|
|
6923
7062
|
}
|
|
6924
|
-
function formatContinueLabel(plan, locale) {
|
|
7063
|
+
function formatContinueLabel(plan, locale, pricingOption) {
|
|
6925
7064
|
if (!plan) return "Continue";
|
|
6926
7065
|
if (isPayg(plan)) {
|
|
6927
7066
|
return `Continue with ${plan.name ?? "Pay as you go"}`;
|
|
6928
7067
|
}
|
|
6929
|
-
const
|
|
6930
|
-
const
|
|
7068
|
+
const option = pricingOption ?? resolvePlanPricingOption(plan, null);
|
|
7069
|
+
const currency = option.currency.toUpperCase();
|
|
7070
|
+
const priceLabel = formatPrice(option.price ?? 0, currency, { locale });
|
|
6931
7071
|
const cycle = plan.billingCycle ? `/${shortCycle(plan.billingCycle)}` : "";
|
|
6932
7072
|
return `Continue with ${plan.name ?? "Plan"} \u2014 ${priceLabel}${cycle}`;
|
|
6933
7073
|
}
|
|
6934
7074
|
function formatPaygRate(plan, locale) {
|
|
6935
|
-
const currency = (plan.currency ?? "USD").toUpperCase();
|
|
6936
7075
|
const creditsPerUnit = plan.creditsPerUnit ?? 1;
|
|
6937
|
-
const
|
|
6938
|
-
return `${
|
|
7076
|
+
const creditLabel = creditsPerUnit === 1 ? "credit" : "credits";
|
|
7077
|
+
return `${creditsPerUnit.toLocaleString(locale)} ${creditLabel} / call`;
|
|
6939
7078
|
}
|
|
6940
7079
|
function inferIncludedCredits(plan) {
|
|
6941
7080
|
const price = plan.price ?? 0;
|
|
@@ -6970,14 +7109,31 @@ function useCheckoutFlow(opts) {
|
|
|
6970
7109
|
onPurchaseSuccessRef.current = opts.onPurchaseSuccess;
|
|
6971
7110
|
onErrorRef.current = opts.onError;
|
|
6972
7111
|
const planCtx = usePlanSelector();
|
|
7112
|
+
const planSelection = usePlanSelection();
|
|
6973
7113
|
const transport = useTransport();
|
|
6974
7114
|
const locale = useLocale();
|
|
6975
7115
|
const balance = useBalance();
|
|
6976
7116
|
const { creditsPerMinorUnit, displayExchangeRate, adjustBalance } = balance;
|
|
6977
7117
|
const { refetchPurchase } = useSolvaPay();
|
|
6978
7118
|
const { merchant } = useMerchant();
|
|
6979
|
-
const
|
|
7119
|
+
const [topupCurrencyOverride, setTopupCurrencyOverride] = (0, import_react44.useState)(null);
|
|
7120
|
+
const topupCurrencies = (0, import_react44.useMemo)(() => {
|
|
7121
|
+
const fromMerchant = (merchant?.supportedTopupCurrencies ?? []).map((code) => code.toUpperCase()).filter(Boolean);
|
|
7122
|
+
const fallback = opts.topupCurrency?.toUpperCase() ?? merchant?.defaultCurrency?.toUpperCase() ?? null;
|
|
7123
|
+
const list = fromMerchant.length > 0 ? fromMerchant : fallback ? [fallback] : [];
|
|
7124
|
+
return Array.from(new Set(list));
|
|
7125
|
+
}, [merchant?.supportedTopupCurrencies, merchant?.defaultCurrency, opts.topupCurrency]);
|
|
7126
|
+
const resolvedDefaultTopupCurrency = opts.topupCurrency?.toUpperCase() ?? merchant?.defaultCurrency?.toUpperCase() ?? null;
|
|
7127
|
+
const planPickerCurrency = planCtx.preferredCurrency?.toUpperCase() ?? null;
|
|
7128
|
+
const topupCurrency = (topupCurrencyOverride && topupCurrencies.includes(topupCurrencyOverride) ? topupCurrencyOverride : null) ?? (planPickerCurrency && topupCurrencies.includes(planPickerCurrency) ? planPickerCurrency : null) ?? resolvedDefaultTopupCurrency;
|
|
6980
7129
|
const topupCurrencyReady = topupCurrency != null;
|
|
7130
|
+
const setTopupCurrency = (0, import_react44.useCallback)(
|
|
7131
|
+
(code) => {
|
|
7132
|
+
const normalized = code.toUpperCase();
|
|
7133
|
+
setTopupCurrencyOverride(normalized);
|
|
7134
|
+
},
|
|
7135
|
+
[]
|
|
7136
|
+
);
|
|
6981
7137
|
const [step, setStep] = (0, import_react44.useState)(initialStep);
|
|
6982
7138
|
const [status, setStatus] = (0, import_react44.useState)("idle");
|
|
6983
7139
|
const [selectedAmountMinor, setSelectedAmountMinor] = (0, import_react44.useState)(initialAmountMinor);
|
|
@@ -7075,19 +7231,23 @@ function useCheckoutFlow(opts) {
|
|
|
7075
7231
|
);
|
|
7076
7232
|
const recordRecurringSuccess = (0, import_react44.useCallback)(() => {
|
|
7077
7233
|
if (!selectedPlanShape) return;
|
|
7078
|
-
const
|
|
7234
|
+
const pricingOption = selectedPlan ? resolvePlanPricingOption(selectedPlan, planSelection?.selectedCurrency) : {
|
|
7235
|
+
currency: selectedPlanShape.currency ?? "USD",
|
|
7236
|
+
price: selectedPlanShape.price ?? 0
|
|
7237
|
+
};
|
|
7238
|
+
const currency = pricingOption.currency.toUpperCase();
|
|
7079
7239
|
const meta = {
|
|
7080
7240
|
branch: "recurring",
|
|
7081
7241
|
plan: selectedPlanShape,
|
|
7082
7242
|
creditsIncluded: inferIncludedCredits(selectedPlanShape),
|
|
7083
|
-
chargedTodayMinor:
|
|
7243
|
+
chargedTodayMinor: pricingOption.price ?? 0,
|
|
7084
7244
|
currency,
|
|
7085
7245
|
nextRenewalLabel: null
|
|
7086
7246
|
};
|
|
7087
7247
|
setSuccessMeta(meta);
|
|
7088
7248
|
setStep("success");
|
|
7089
7249
|
onPurchaseSuccessRef.current?.(meta);
|
|
7090
|
-
}, [selectedPlanShape]);
|
|
7250
|
+
}, [selectedPlanShape, selectedPlan, planSelection?.selectedCurrency]);
|
|
7091
7251
|
const advance = (0, import_react44.useCallback)(async () => {
|
|
7092
7252
|
if (step === "plan") {
|
|
7093
7253
|
await advanceFromPlan();
|
|
@@ -7133,6 +7293,7 @@ function useCheckoutFlow(opts) {
|
|
|
7133
7293
|
setSuccessMeta(null);
|
|
7134
7294
|
setError(null);
|
|
7135
7295
|
setStatus("idle");
|
|
7296
|
+
setTopupCurrencyOverride(null);
|
|
7136
7297
|
}, []);
|
|
7137
7298
|
const retry = (0, import_react44.useCallback)(async () => {
|
|
7138
7299
|
if (status !== "error") return;
|
|
@@ -7162,6 +7323,8 @@ function useCheckoutFlow(opts) {
|
|
|
7162
7323
|
branch,
|
|
7163
7324
|
topupCurrency,
|
|
7164
7325
|
topupCurrencyReady,
|
|
7326
|
+
topupCurrencies,
|
|
7327
|
+
setTopupCurrency,
|
|
7165
7328
|
canGoBack,
|
|
7166
7329
|
selectPlan,
|
|
7167
7330
|
selectAmount,
|
|
@@ -7182,6 +7345,8 @@ function useCheckoutFlow(opts) {
|
|
|
7182
7345
|
branch,
|
|
7183
7346
|
topupCurrency,
|
|
7184
7347
|
topupCurrencyReady,
|
|
7348
|
+
topupCurrencies,
|
|
7349
|
+
setTopupCurrency,
|
|
7185
7350
|
canGoBack,
|
|
7186
7351
|
selectPlan,
|
|
7187
7352
|
selectAmount,
|
|
@@ -8029,6 +8194,28 @@ var CheckoutSteps = {
|
|
|
8029
8194
|
Success
|
|
8030
8195
|
};
|
|
8031
8196
|
|
|
8197
|
+
// src/adapters/session-auth.ts
|
|
8198
|
+
var DEFAULT_SENTINEL = "session-authenticated";
|
|
8199
|
+
async function resolveValue(value) {
|
|
8200
|
+
return value;
|
|
8201
|
+
}
|
|
8202
|
+
function createSessionAuthAdapter(options) {
|
|
8203
|
+
const sentinel = options.sentinelToken ?? DEFAULT_SENTINEL;
|
|
8204
|
+
return {
|
|
8205
|
+
async getToken() {
|
|
8206
|
+
if (options.getToken) {
|
|
8207
|
+
return resolveValue(options.getToken());
|
|
8208
|
+
}
|
|
8209
|
+
const userId = await resolveValue(options.getUserId());
|
|
8210
|
+
return userId ? sentinel : null;
|
|
8211
|
+
},
|
|
8212
|
+
async getUserId() {
|
|
8213
|
+
return resolveValue(options.getUserId());
|
|
8214
|
+
},
|
|
8215
|
+
subscribe: options.subscribe
|
|
8216
|
+
};
|
|
8217
|
+
}
|
|
8218
|
+
|
|
8032
8219
|
// src/transport/types.ts
|
|
8033
8220
|
var UnsupportedTransportMethodError = class extends Error {
|
|
8034
8221
|
method;
|
|
@@ -8071,6 +8258,7 @@ var UnsupportedTransportMethodError = class extends Error {
|
|
|
8071
8258
|
confirmPayment,
|
|
8072
8259
|
createAnonymousAuthAdapter,
|
|
8073
8260
|
createHttpTransport,
|
|
8261
|
+
createSessionAuthAdapter,
|
|
8074
8262
|
defaultAuthAdapter,
|
|
8075
8263
|
deriveVariant,
|
|
8076
8264
|
enCopy,
|