@solvapay/react 2.1.1 → 2.2.0-preview-e3e546693c002c32f128d83bf6c5fe76ac182a79
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 +23 -2
- package/dist/UsageMeter-BhxNHeRM.d.ts +74 -0
- package/dist/UsageMeter-rga6cyfB.d.cts +74 -0
- package/dist/chunk-FWT62B56.js +316 -0
- package/dist/{chunk-LL6AYSTC.js → chunk-VTGYZIE2.js} +1734 -688
- package/dist/{chunk-HQH6KSXJ.js → chunk-X65JBC2A.js} +419 -810
- package/dist/{index-CBWGkBqF.d.ts → index-BJGjKUtC.d.cts} +46 -39
- package/dist/{index-SylJb9Rh.d.cts → index-PsjS_d7V.d.ts} +46 -39
- package/dist/index.cjs +2284 -1580
- package/dist/index.d.cts +110 -25
- package/dist/index.d.ts +110 -25
- package/dist/index.js +388 -46
- package/dist/mcp/index.cjs +6537 -3396
- package/dist/mcp/index.d.cts +637 -158
- package/dist/mcp/index.d.ts +637 -158
- package/dist/mcp/index.js +3421 -1004
- package/dist/mcp/styles.css +1422 -500
- package/dist/primitives/index.cjs +1635 -1031
- package/dist/primitives/index.d.cts +19 -76
- package/dist/primitives/index.d.ts +19 -76
- package/dist/primitives/index.js +3 -3
- package/dist/styles.css +60 -10
- package/dist/{shared-CUl6mTC1.d.ts → useUsage-CMqxEF9d.d.ts} +387 -53
- package/dist/{shared-D0hmT1qU.d.cts → useUsage-CTgRBvFK.d.cts} +387 -53
- package/package.json +5 -5
- package/dist/chunk-QXNNMNCV.js +0 -579
|
@@ -152,7 +152,8 @@ var DEFAULT_ROUTES = {
|
|
|
152
152
|
getPaymentMethod: "/api/payment-method",
|
|
153
153
|
autoRecharge: "/api/auto-recharge",
|
|
154
154
|
getUsage: "/api/usage",
|
|
155
|
-
getLimits: "/api/limits"
|
|
155
|
+
getLimits: "/api/limits",
|
|
156
|
+
getHistory: "/api/history"
|
|
156
157
|
};
|
|
157
158
|
function routeFor(config, key) {
|
|
158
159
|
const configured = config?.api?.[key];
|
|
@@ -322,8 +323,22 @@ function createHttpTransport(config) {
|
|
|
322
323
|
overage: data.overage,
|
|
323
324
|
needsTopUp: data.needsTopUp,
|
|
324
325
|
needsUpgrade: data.needsUpgrade,
|
|
325
|
-
upgraded: data.upgraded
|
|
326
|
+
upgraded: data.upgraded,
|
|
327
|
+
...data.used !== void 0 ? { used: data.used } : {},
|
|
328
|
+
...data.limit !== void 0 ? { limit: data.limit } : {}
|
|
326
329
|
};
|
|
330
|
+
},
|
|
331
|
+
getHistory: async (params = {}) => {
|
|
332
|
+
const base = routeFor(config, "getHistory");
|
|
333
|
+
const search = new URLSearchParams();
|
|
334
|
+
if (params.productRef) search.set("productRef", params.productRef);
|
|
335
|
+
if (params.limit !== void 0) search.set("limit", String(params.limit));
|
|
336
|
+
const qs = search.toString();
|
|
337
|
+
return request(config, qs ? `${base}?${qs}` : base, {
|
|
338
|
+
method: "GET",
|
|
339
|
+
onErrorContext: "getHistory",
|
|
340
|
+
errorPrefix: "Failed to load history"
|
|
341
|
+
});
|
|
327
342
|
}
|
|
328
343
|
};
|
|
329
344
|
}
|
|
@@ -467,7 +482,7 @@ var enCopy = {
|
|
|
467
482
|
invalidThreshold: "Enter a valid balance threshold.",
|
|
468
483
|
thresholdTooLow: "Balance threshold must be greater than zero.",
|
|
469
484
|
minTopupAmount: "Top-up amount must be at least {amount}.",
|
|
470
|
-
|
|
485
|
+
deepDrawdownExplainer: "If your balance has fallen well below the threshold, we add a multiple of this amount in one charge.",
|
|
471
486
|
invalidMaxMonthlySpend: "Maximum monthly spend must be a positive amount.",
|
|
472
487
|
maxMonthlySpendBelowTopup: "Maximum monthly spend must be at least your top-up amount ({amount}).",
|
|
473
488
|
maxMonthlySpendLabel: "Maximum monthly spend (optional)",
|
|
@@ -483,6 +498,24 @@ var enCopy = {
|
|
|
483
498
|
taxDisclosure: "Plus applicable tax.",
|
|
484
499
|
statusFailed: "Payment failed \u2014 update your card to resume"
|
|
485
500
|
},
|
|
501
|
+
autoRechargeView: {
|
|
502
|
+
heading: "Auto-recharge",
|
|
503
|
+
description: "Tops your balance up automatically so calls do not fail. Nothing is charged today.",
|
|
504
|
+
thresholdLabel: "When balance falls below",
|
|
505
|
+
topupLabel: "Add each time",
|
|
506
|
+
maxMonthlySpendLabel: "Maximum monthly spend",
|
|
507
|
+
maxMonthlySpendPlaceholder: "No limit",
|
|
508
|
+
explainer: "Each recharge adds about {credits} credits, plus applicable tax. If your balance has fallen well below the threshold we add a multiple of this amount in one charge. Leave the spend limit blank for unlimited recharges.",
|
|
509
|
+
explainerNoEstimate: "Each recharge includes applicable tax. If your balance has fallen well below the threshold we add a multiple of this amount in one charge. Leave the spend limit blank for unlimited recharges.",
|
|
510
|
+
footerCaption: "Recharges use the payment method on your account. First charge happens when your balance drops below {threshold}.",
|
|
511
|
+
cancel: "Cancel",
|
|
512
|
+
turnOn: "Turn on auto-recharge",
|
|
513
|
+
save: "Save changes",
|
|
514
|
+
turnOff: "Turn off auto-recharge",
|
|
515
|
+
statusOn: "On",
|
|
516
|
+
back: "Back to account",
|
|
517
|
+
setupUnexpected: "Your saved card is no longer reusable. Add a card from checkout, then try again."
|
|
518
|
+
},
|
|
486
519
|
activationFlow: {
|
|
487
520
|
heading: "Confirm your plan",
|
|
488
521
|
activateButton: "Activate",
|
|
@@ -526,6 +559,9 @@ var enCopy = {
|
|
|
526
559
|
expiresOn: "Expires {date}",
|
|
527
560
|
validIndefinitely: "Valid indefinitely",
|
|
528
561
|
startedOn: "Started {date}",
|
|
562
|
+
priceFieldLabel: "Price",
|
|
563
|
+
rateFieldLabel: "Rate",
|
|
564
|
+
balanceFieldLabel: "Balance",
|
|
529
565
|
paymentMethod: "{brand} \u2022\u2022\u2022\u2022 {last4}",
|
|
530
566
|
paymentMethodExpires: "expires {month}/{year}",
|
|
531
567
|
noPaymentMethod: "No payment method on file",
|
|
@@ -545,7 +581,65 @@ var enCopy = {
|
|
|
545
581
|
noPlanTitle: "Pick a plan",
|
|
546
582
|
noPlanBody: "Choose a free, pay-as-you-go, or paid plan to start using this MCP server.",
|
|
547
583
|
seePlansButton: "See plans",
|
|
548
|
-
|
|
584
|
+
seePlans: "See plans \u2192",
|
|
585
|
+
pickPlanButton: "Pick a plan",
|
|
586
|
+
upgradeButton: "Upgrade",
|
|
587
|
+
changePlanButton: "Change plan",
|
|
588
|
+
needMoreAllowance: "Need more than {total} {unit} a {interval}?",
|
|
589
|
+
upgradePaygCaption: "Pay as you go starts without payment and uses your credits.",
|
|
590
|
+
noPlanStatus: "No plan",
|
|
591
|
+
choosePlanCaption: "Choose a plan to start using it. Calls fail until one is active.",
|
|
592
|
+
plansEyebrow: "Plans",
|
|
593
|
+
carryOnEyebrow: "Carry on with",
|
|
594
|
+
plansStartCaption: "Free and Pay as you go start immediately. Paid plans take payment first.",
|
|
595
|
+
activatePlanButton: "Activate",
|
|
596
|
+
switchPlanButton: "Switch",
|
|
597
|
+
activatingPlanButton: "Activating\u2026",
|
|
598
|
+
usedUpTitle: "Your {plan} {unit} are used up",
|
|
599
|
+
usedUpBody: "Calls fail until the limit resets on {date}, in {days} days. Choose a paid plan to carry on now.",
|
|
600
|
+
usedUpBodyNoDate: "Calls fail until you choose a paid plan.",
|
|
601
|
+
antiTrapCredits: "You have {credits} credits. {plan} does not spend them, so adding funds will not restore calls.",
|
|
602
|
+
waitUntilReset: "Or wait until {date} and keep the {plan} plan. Nothing is charged automatically.",
|
|
603
|
+
notStartedStatus: "Not started",
|
|
604
|
+
readyToClaim: "{total} free {unit} a {interval}, ready to claim",
|
|
605
|
+
noCardCaption: "No card, no charge. You can change plan later.",
|
|
606
|
+
startFreePlan: "Start free plan",
|
|
607
|
+
stillWorking: "Calls are still working.",
|
|
608
|
+
seeHigherLimit: "See plans with a higher limit \u2192",
|
|
609
|
+
usedOfAllowance: "{used} of {total} {unit}",
|
|
610
|
+
activeUntil: "Active until {date}",
|
|
611
|
+
cancelledPlanLine: "{plan} \xB7 cancelled {date}",
|
|
612
|
+
daysLeftTitle: "{days} days left on this plan",
|
|
613
|
+
cancelledBody: "Calls keep working until {date}, then stop. You will not be charged again.",
|
|
614
|
+
reactivatePlan: "Reactivate {plan}",
|
|
615
|
+
creditBalance: "Credit balance",
|
|
616
|
+
addFunds: "Add funds",
|
|
617
|
+
autoRechargeOn: "Auto-recharge on",
|
|
618
|
+
autoRechargeOff: "Auto-recharge off",
|
|
619
|
+
turnOn: "Turn on \u2192",
|
|
620
|
+
manage: "Manage \u2192",
|
|
621
|
+
autoRechargeOffCaption: "Calls fail the moment the balance runs out.",
|
|
622
|
+
autoRechargeOffFixCaption: "Turning it on stops this happening again.",
|
|
623
|
+
callsFailingCaption: "The plan is active, but calls fail until you add credits.",
|
|
624
|
+
activeProducts: "Active products",
|
|
625
|
+
worksAcross: "Works across every {merchant} product.",
|
|
626
|
+
soldBy: "Sold by {merchant}",
|
|
627
|
+
fullHistory: "Full history",
|
|
628
|
+
fullAccount: "Full account",
|
|
629
|
+
creditActivityEyebrow: "Credit activity",
|
|
630
|
+
chargesEyebrow: "Charges for this product",
|
|
631
|
+
creditActivityCaption: "Every credit event on your account, newest first, including other products and top-ups. Credits are shared, so the balance only makes sense account-wide.",
|
|
632
|
+
creditActivityEmpty: "No credit activity yet.",
|
|
633
|
+
creditActivityFailed: "Couldn't load credit activity.",
|
|
634
|
+
chargesEmpty: "No charges yet.",
|
|
635
|
+
chargesFailed: "Couldn't load charges.",
|
|
636
|
+
eventColumn: "Event",
|
|
637
|
+
whenColumn: "When",
|
|
638
|
+
creditsColumn: "Credits",
|
|
639
|
+
balanceColumn: "Balance",
|
|
640
|
+
chargeColumn: "Charge",
|
|
641
|
+
dateColumn: "Date",
|
|
642
|
+
amountColumn: "Amount"
|
|
549
643
|
},
|
|
550
644
|
customerPortal: {
|
|
551
645
|
launchButton: "Manage account",
|
|
@@ -624,7 +718,30 @@ var enCopy = {
|
|
|
624
718
|
atLimit: "You've reached your usage limit.",
|
|
625
719
|
topUpCta: "Add credits",
|
|
626
720
|
upgradeCta: "Upgrade plan",
|
|
627
|
-
refreshCta: "Refresh"
|
|
721
|
+
refreshCta: "Refresh",
|
|
722
|
+
remainingEyebrow: "Remaining",
|
|
723
|
+
renewsEyebrow: "Renews",
|
|
724
|
+
resetsEyebrow: "Resets",
|
|
725
|
+
creditsEyebrow: "Credits",
|
|
726
|
+
usedEyebrow: "Used",
|
|
727
|
+
remainingCalls: "{remaining} {unit}",
|
|
728
|
+
remainingOfTotal: "{remaining} of {total} {unit}",
|
|
729
|
+
ofTotalThisPeriod: "Of {total} this period.",
|
|
730
|
+
usedOfTotalPercent: "{used} of {total} {unit} used, {percent}%.",
|
|
731
|
+
warningThresholdHint: "A warning shows at 80%, and calls stop at 100%.",
|
|
732
|
+
lastCallHint: "One remaining {unit} is the difference between working and blocked.",
|
|
733
|
+
afterFirstCall: "After your first call",
|
|
734
|
+
inDays: "In {days} days.",
|
|
735
|
+
notKnownYet: "Not known yet",
|
|
736
|
+
creditsNotUsed: "Not used",
|
|
737
|
+
creditsUntouched: "Balance is untouched.",
|
|
738
|
+
creditsDoNotSpend: "This plan does not spend your balance.",
|
|
739
|
+
rateConfirmedAtCheckout: "Rate confirmed at checkout",
|
|
740
|
+
fromCreditsPerCall: "from {credits} credits per call",
|
|
741
|
+
creditsPerCall: "{credits} credits per call",
|
|
742
|
+
callsFailing: "Calls failing",
|
|
743
|
+
overAllowance: "Over the allowance",
|
|
744
|
+
limitReached: "{plan} limit reached"
|
|
628
745
|
}
|
|
629
746
|
};
|
|
630
747
|
|
|
@@ -1435,6 +1552,45 @@ function useLocale() {
|
|
|
1435
1552
|
return useCopyContext().locale;
|
|
1436
1553
|
}
|
|
1437
1554
|
|
|
1555
|
+
// src/hooks/useExternalLink.tsx
|
|
1556
|
+
import { createContext as createContext3, useCallback as useCallback2, useContext as useContext2 } from "react";
|
|
1557
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1558
|
+
var ExternalLinkContext = createContext3(null);
|
|
1559
|
+
function ExternalLinkProvider({ opener, children }) {
|
|
1560
|
+
return /* @__PURE__ */ jsx4(ExternalLinkContext.Provider, { value: opener, children });
|
|
1561
|
+
}
|
|
1562
|
+
function useOpenExternal() {
|
|
1563
|
+
const opener = useContext2(ExternalLinkContext);
|
|
1564
|
+
return useCallback2(
|
|
1565
|
+
async (url) => {
|
|
1566
|
+
if (opener?.canOpen()) return opener.open(url);
|
|
1567
|
+
if (typeof window !== "undefined") {
|
|
1568
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1569
|
+
}
|
|
1570
|
+
return true;
|
|
1571
|
+
},
|
|
1572
|
+
[opener]
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
function useExternalLinkClick() {
|
|
1576
|
+
const opener = useContext2(ExternalLinkContext);
|
|
1577
|
+
return useCallback2(
|
|
1578
|
+
(event) => {
|
|
1579
|
+
if (event.defaultPrevented) return;
|
|
1580
|
+
if (!opener?.canOpen()) return;
|
|
1581
|
+
const href = event.currentTarget.href;
|
|
1582
|
+
if (!href) return;
|
|
1583
|
+
event.preventDefault();
|
|
1584
|
+
void opener.open(href).then((opened) => {
|
|
1585
|
+
if (!opened) {
|
|
1586
|
+
console.warn(`[solvapay] host declined to open ${href}`);
|
|
1587
|
+
}
|
|
1588
|
+
});
|
|
1589
|
+
},
|
|
1590
|
+
[opener]
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1438
1594
|
// src/primitives/LegalFooter.tsx
|
|
1439
1595
|
import { forwardRef } from "react";
|
|
1440
1596
|
|
|
@@ -1444,7 +1600,7 @@ var SOLVAPAY_PRIVACY_URL = "https://solvapay.com/legal/privacy";
|
|
|
1444
1600
|
var SOLVAPAY_WEBSITE_URL = "https://solvapay.com";
|
|
1445
1601
|
|
|
1446
1602
|
// src/primitives/LegalFooter.tsx
|
|
1447
|
-
import { Fragment as Fragment2, jsx as
|
|
1603
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
1448
1604
|
var LegalFooter = forwardRef(
|
|
1449
1605
|
function LegalFooter2({
|
|
1450
1606
|
attribution = "provided",
|
|
@@ -1455,39 +1611,43 @@ var LegalFooter = forwardRef(
|
|
|
1455
1611
|
...rest
|
|
1456
1612
|
}, forwardedRef) {
|
|
1457
1613
|
const copy = useCopy();
|
|
1614
|
+
const handleExternalClick = useExternalLinkClick();
|
|
1458
1615
|
const attributionLabel = attribution === "provided" ? copy.legalFooter.providedBy : attribution === "powered" ? copy.legalFooter.poweredBy : null;
|
|
1459
1616
|
const Comp = asChild ? Slot : "div";
|
|
1460
|
-
return /* @__PURE__ */
|
|
1617
|
+
return /* @__PURE__ */ jsx5(Comp, { ref: forwardedRef, "data-solvapay-legal-footer": "", ...rest, children: children ?? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1461
1618
|
/* @__PURE__ */ jsxs("div", { "data-solvapay-legal-footer-links": "", children: [
|
|
1462
|
-
/* @__PURE__ */
|
|
1619
|
+
/* @__PURE__ */ jsx5(
|
|
1463
1620
|
"a",
|
|
1464
1621
|
{
|
|
1465
1622
|
"data-solvapay-legal-footer-link": "",
|
|
1466
1623
|
href: termsUrl,
|
|
1467
1624
|
target: "_blank",
|
|
1468
1625
|
rel: "noopener noreferrer",
|
|
1626
|
+
onClick: handleExternalClick,
|
|
1469
1627
|
children: copy.legalFooter.terms
|
|
1470
1628
|
}
|
|
1471
1629
|
),
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
1630
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: " \xB7 " }),
|
|
1631
|
+
/* @__PURE__ */ jsx5(
|
|
1474
1632
|
"a",
|
|
1475
1633
|
{
|
|
1476
1634
|
"data-solvapay-legal-footer-link": "",
|
|
1477
1635
|
href: privacyUrl,
|
|
1478
1636
|
target: "_blank",
|
|
1479
1637
|
rel: "noopener noreferrer",
|
|
1638
|
+
onClick: handleExternalClick,
|
|
1480
1639
|
children: copy.legalFooter.privacy
|
|
1481
1640
|
}
|
|
1482
1641
|
)
|
|
1483
1642
|
] }),
|
|
1484
|
-
attributionLabel ? /* @__PURE__ */
|
|
1643
|
+
attributionLabel ? /* @__PURE__ */ jsx5(
|
|
1485
1644
|
"a",
|
|
1486
1645
|
{
|
|
1487
1646
|
"data-solvapay-legal-footer-attribution": "",
|
|
1488
1647
|
href: SOLVAPAY_WEBSITE_URL,
|
|
1489
1648
|
target: "_blank",
|
|
1490
1649
|
rel: "noopener noreferrer",
|
|
1650
|
+
onClick: handleExternalClick,
|
|
1491
1651
|
children: attributionLabel
|
|
1492
1652
|
}
|
|
1493
1653
|
) : null
|
|
@@ -1496,9 +1656,9 @@ var LegalFooter = forwardRef(
|
|
|
1496
1656
|
);
|
|
1497
1657
|
|
|
1498
1658
|
// src/hooks/useSolvaPay.ts
|
|
1499
|
-
import { useContext as
|
|
1659
|
+
import { useContext as useContext3 } from "react";
|
|
1500
1660
|
function useSolvaPay() {
|
|
1501
|
-
const context =
|
|
1661
|
+
const context = useContext3(SolvaPayContext);
|
|
1502
1662
|
if (!context) {
|
|
1503
1663
|
throw new Error(
|
|
1504
1664
|
"useSolvaPay must be used within a SolvaPayProvider. Wrap your component tree with <SolvaPayProvider> to use this hook."
|
|
@@ -1508,19 +1668,19 @@ function useSolvaPay() {
|
|
|
1508
1668
|
}
|
|
1509
1669
|
|
|
1510
1670
|
// src/hooks/useCheckout.ts
|
|
1511
|
-
import { useState as useState2, useCallback as
|
|
1671
|
+
import { useState as useState2, useCallback as useCallback3, useRef as useRef2 } from "react";
|
|
1512
1672
|
import { loadStripe } from "@stripe/stripe-js";
|
|
1513
1673
|
|
|
1514
1674
|
// src/components/PlanSelectionContext.tsx
|
|
1515
|
-
import { createContext as
|
|
1516
|
-
import { jsx as
|
|
1517
|
-
var PlanSelectionContext =
|
|
1675
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
1676
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1677
|
+
var PlanSelectionContext = createContext4(null);
|
|
1518
1678
|
var PlanSelectionProvider = ({
|
|
1519
1679
|
value,
|
|
1520
1680
|
children
|
|
1521
|
-
}) => /* @__PURE__ */
|
|
1681
|
+
}) => /* @__PURE__ */ jsx6(PlanSelectionContext.Provider, { value, children });
|
|
1522
1682
|
function usePlanSelection() {
|
|
1523
|
-
return
|
|
1683
|
+
return useContext4(PlanSelectionContext);
|
|
1524
1684
|
}
|
|
1525
1685
|
|
|
1526
1686
|
// src/hooks/useCheckout.ts
|
|
@@ -1571,7 +1731,7 @@ function useCheckout(options) {
|
|
|
1571
1731
|
const [processorPaymentId, setProcessorPaymentId] = useState2(null);
|
|
1572
1732
|
const [resolvedPlanRef, setResolvedPlanRef] = useState2(planRef || null);
|
|
1573
1733
|
const isStartingRef = useRef2(false);
|
|
1574
|
-
const startCheckout =
|
|
1734
|
+
const startCheckout = useCallback3(async () => {
|
|
1575
1735
|
if (isStartingRef.current || loading) {
|
|
1576
1736
|
return;
|
|
1577
1737
|
}
|
|
@@ -1647,7 +1807,7 @@ function useCheckout(options) {
|
|
|
1647
1807
|
loading,
|
|
1648
1808
|
_config
|
|
1649
1809
|
]);
|
|
1650
|
-
const reset =
|
|
1810
|
+
const reset = useCallback3(() => {
|
|
1651
1811
|
isStartingRef.current = false;
|
|
1652
1812
|
setLoading(false);
|
|
1653
1813
|
setError(null);
|
|
@@ -1689,7 +1849,7 @@ function useCustomer() {
|
|
|
1689
1849
|
}
|
|
1690
1850
|
|
|
1691
1851
|
// src/hooks/usePlans.ts
|
|
1692
|
-
import { useContext as
|
|
1852
|
+
import { useContext as useContext5, useState as useState3, useEffect as useEffect2, useCallback as useCallback4, useMemo as useMemo3, useRef as useRef3 } from "react";
|
|
1693
1853
|
|
|
1694
1854
|
// src/transport/list-plans.ts
|
|
1695
1855
|
async function defaultListPlans(productRef, config) {
|
|
@@ -1742,7 +1902,7 @@ function usePlans(options) {
|
|
|
1742
1902
|
initialPlanRef,
|
|
1743
1903
|
selectionReady = true
|
|
1744
1904
|
} = options;
|
|
1745
|
-
const solvaContext =
|
|
1905
|
+
const solvaContext = useContext5(SolvaPayContext);
|
|
1746
1906
|
const config = solvaContext?._config;
|
|
1747
1907
|
const effectiveFetcher = useMemo3(
|
|
1748
1908
|
() => fetcher ?? ((ref) => defaultListPlans(ref, config)),
|
|
@@ -1796,11 +1956,11 @@ function usePlans(options) {
|
|
|
1796
1956
|
useEffect2(() => {
|
|
1797
1957
|
selectionReadyRef.current = selectionReady;
|
|
1798
1958
|
}, [selectionReady]);
|
|
1799
|
-
const setSelectedPlanIndex =
|
|
1959
|
+
const setSelectedPlanIndex = useCallback4((index) => {
|
|
1800
1960
|
userHasSelectedRef.current = true;
|
|
1801
1961
|
setSelectedPlanIndexState(index);
|
|
1802
1962
|
}, []);
|
|
1803
|
-
const applyInitialSelection =
|
|
1963
|
+
const applyInitialSelection = useCallback4((processedPlans) => {
|
|
1804
1964
|
if (hasAppliedInitialRef.current || userHasSelectedRef.current) return;
|
|
1805
1965
|
if (!selectionReadyRef.current || processedPlans.length === 0) return;
|
|
1806
1966
|
hasAppliedInitialRef.current = true;
|
|
@@ -1811,7 +1971,7 @@ function usePlans(options) {
|
|
|
1811
1971
|
);
|
|
1812
1972
|
setSelectedPlanIndexState(idx);
|
|
1813
1973
|
}, []);
|
|
1814
|
-
const fetchPlans =
|
|
1974
|
+
const fetchPlans = useCallback4(
|
|
1815
1975
|
async (force = false) => {
|
|
1816
1976
|
if (!productRef) {
|
|
1817
1977
|
setError(new Error("Product reference not configured"));
|
|
@@ -1883,7 +2043,7 @@ function usePlans(options) {
|
|
|
1883
2043
|
applyInitialSelection(plans);
|
|
1884
2044
|
}, [selectionReady, plans, applyInitialSelection]);
|
|
1885
2045
|
const selectedPlan = useMemo3(() => plans[selectedPlanIndex] || null, [plans, selectedPlanIndex]);
|
|
1886
|
-
const selectPlan =
|
|
2046
|
+
const selectPlan = useCallback4(
|
|
1887
2047
|
(planRef) => {
|
|
1888
2048
|
const index = plans.findIndex((p) => p.reference === planRef);
|
|
1889
2049
|
if (index >= 0) {
|
|
@@ -1906,11 +2066,11 @@ function usePlans(options) {
|
|
|
1906
2066
|
}
|
|
1907
2067
|
|
|
1908
2068
|
// src/hooks/usePlan.ts
|
|
1909
|
-
import { useCallback as
|
|
2069
|
+
import { useCallback as useCallback5, useEffect as useEffect3, useState as useState4 } from "react";
|
|
1910
2070
|
function usePlan(options) {
|
|
1911
2071
|
const { planRef, productRef } = options;
|
|
1912
2072
|
const { _config } = useSolvaPay();
|
|
1913
|
-
const findPlan =
|
|
2073
|
+
const findPlan = useCallback5(
|
|
1914
2074
|
(plans) => {
|
|
1915
2075
|
if (!planRef) return null;
|
|
1916
2076
|
return plans.find((p) => p.reference === planRef) || null;
|
|
@@ -1925,7 +2085,7 @@ function usePlan(options) {
|
|
|
1925
2085
|
});
|
|
1926
2086
|
const [loading, setLoading] = useState4(() => !!(planRef && !plan));
|
|
1927
2087
|
const [error, setError] = useState4(null);
|
|
1928
|
-
const load =
|
|
2088
|
+
const load = useCallback5(
|
|
1929
2089
|
async (force = false) => {
|
|
1930
2090
|
if (!planRef) {
|
|
1931
2091
|
setPlan(null);
|
|
@@ -2004,7 +2164,7 @@ function usePlan(options) {
|
|
|
2004
2164
|
}
|
|
2005
2165
|
|
|
2006
2166
|
// src/hooks/useProduct.ts
|
|
2007
|
-
import { useCallback as
|
|
2167
|
+
import { useCallback as useCallback6, useEffect as useEffect4, useState as useState5 } from "react";
|
|
2008
2168
|
var productCache = /* @__PURE__ */ new Map();
|
|
2009
2169
|
var CACHE_DURATION4 = 5 * 60 * 1e3;
|
|
2010
2170
|
function cacheKeyFor(config, productRef) {
|
|
@@ -2027,7 +2187,7 @@ function useProduct(productRef) {
|
|
|
2027
2187
|
return !cached || !cached.product && !cached.promise;
|
|
2028
2188
|
});
|
|
2029
2189
|
const [error, setError] = useState5(null);
|
|
2030
|
-
const load =
|
|
2190
|
+
const load = useCallback6(
|
|
2031
2191
|
async (force = false) => {
|
|
2032
2192
|
if (!productRef) {
|
|
2033
2193
|
setProduct(null);
|
|
@@ -2100,14 +2260,14 @@ function useProduct(productRef) {
|
|
|
2100
2260
|
}
|
|
2101
2261
|
|
|
2102
2262
|
// src/hooks/useActivation.ts
|
|
2103
|
-
import { useState as useState6, useCallback as
|
|
2263
|
+
import { useState as useState6, useCallback as useCallback7 } from "react";
|
|
2104
2264
|
function useActivation() {
|
|
2105
2265
|
const { activatePlan } = useSolvaPay();
|
|
2106
2266
|
const copy = useCopy();
|
|
2107
2267
|
const [state, setState] = useState6("idle");
|
|
2108
2268
|
const [error, setError] = useState6(null);
|
|
2109
2269
|
const [result, setResult] = useState6(null);
|
|
2110
|
-
const activate =
|
|
2270
|
+
const activate = useCallback7(
|
|
2111
2271
|
async (params) => {
|
|
2112
2272
|
setState("activating");
|
|
2113
2273
|
setError(null);
|
|
@@ -2119,30 +2279,32 @@ function useActivation() {
|
|
|
2119
2279
|
case "activated":
|
|
2120
2280
|
case "already_active":
|
|
2121
2281
|
setState("activated");
|
|
2122
|
-
|
|
2282
|
+
return "activated";
|
|
2123
2283
|
case "topup_required":
|
|
2124
2284
|
setState("topup_required");
|
|
2125
|
-
|
|
2285
|
+
return "topup_required";
|
|
2126
2286
|
case "payment_required":
|
|
2127
2287
|
setError(copy.activation.paymentRequired);
|
|
2128
2288
|
setState("payment_required");
|
|
2129
|
-
|
|
2289
|
+
return "payment_required";
|
|
2130
2290
|
case "invalid":
|
|
2131
2291
|
setError(data.message || copy.activation.invalidConfiguration);
|
|
2132
2292
|
setState("error");
|
|
2133
|
-
|
|
2293
|
+
return "error";
|
|
2134
2294
|
default:
|
|
2135
2295
|
setError(copy.activation.unexpectedResponse);
|
|
2136
2296
|
setState("error");
|
|
2297
|
+
return "error";
|
|
2137
2298
|
}
|
|
2138
2299
|
} catch (err) {
|
|
2139
2300
|
setError(err instanceof Error ? err.message : copy.activation.failed);
|
|
2140
2301
|
setState("error");
|
|
2302
|
+
return "error";
|
|
2141
2303
|
}
|
|
2142
2304
|
},
|
|
2143
2305
|
[activatePlan, copy]
|
|
2144
2306
|
);
|
|
2145
|
-
const reset =
|
|
2307
|
+
const reset = useCallback7(() => {
|
|
2146
2308
|
setState("idle");
|
|
2147
2309
|
setError(null);
|
|
2148
2310
|
setResult(null);
|
|
@@ -2151,11 +2313,11 @@ function useActivation() {
|
|
|
2151
2313
|
}
|
|
2152
2314
|
|
|
2153
2315
|
// src/components/PaymentFormContext.tsx
|
|
2154
|
-
import { createContext as
|
|
2155
|
-
import { jsx as
|
|
2156
|
-
var PaymentFormContext =
|
|
2316
|
+
import { createContext as createContext5, useContext as useContext6 } from "react";
|
|
2317
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2318
|
+
var PaymentFormContext = createContext5(null);
|
|
2157
2319
|
function usePaymentForm() {
|
|
2158
|
-
const ctx =
|
|
2320
|
+
const ctx = useContext6(PaymentFormContext);
|
|
2159
2321
|
if (!ctx) {
|
|
2160
2322
|
throw new Error(
|
|
2161
2323
|
"PaymentForm subcomponents must be used inside a <PaymentForm>. Wrap the slots with <PaymentForm planRef=... productRef=...>."
|
|
@@ -2163,7 +2325,7 @@ function usePaymentForm() {
|
|
|
2163
2325
|
}
|
|
2164
2326
|
return ctx;
|
|
2165
2327
|
}
|
|
2166
|
-
var PaymentFormProvider = ({ value, children }) => /* @__PURE__ */
|
|
2328
|
+
var PaymentFormProvider = ({ value, children }) => /* @__PURE__ */ jsx7(PaymentFormContext.Provider, { value, children });
|
|
2167
2329
|
|
|
2168
2330
|
// src/utils/format.ts
|
|
2169
2331
|
var ZERO_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
|
|
@@ -2230,7 +2392,7 @@ function interpolate(template, vars) {
|
|
|
2230
2392
|
}
|
|
2231
2393
|
|
|
2232
2394
|
// src/primitives/CheckoutSummary.tsx
|
|
2233
|
-
import { createContext as
|
|
2395
|
+
import { createContext as createContext6, forwardRef as forwardRef3, useContext as useContext7, useMemo as useMemo4 } from "react";
|
|
2234
2396
|
|
|
2235
2397
|
// src/components/businessCheckoutParts.tsx
|
|
2236
2398
|
import { forwardRef as forwardRef2 } from "react";
|
|
@@ -2238,11 +2400,17 @@ import {
|
|
|
2238
2400
|
BUSINESS_COUNTRY_OPTIONS,
|
|
2239
2401
|
SUPPORTED_BUSINESS_COUNTRIES,
|
|
2240
2402
|
validateBusinessDetails,
|
|
2403
|
+
getPostalCodeFieldLabel,
|
|
2404
|
+
getPostalCodePlaceholder,
|
|
2405
|
+
getStateFieldLabel,
|
|
2241
2406
|
getTaxIdFieldLabel,
|
|
2242
2407
|
getTaxIdExample,
|
|
2243
|
-
getTaxIdHelperText
|
|
2408
|
+
getTaxIdHelperText,
|
|
2409
|
+
isPostalCodeRequired,
|
|
2410
|
+
isStateRequired,
|
|
2411
|
+
resolveBuyerCountry
|
|
2244
2412
|
} from "@solvapay/core";
|
|
2245
|
-
import { Fragment as Fragment3, jsx as
|
|
2413
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2246
2414
|
function mapBusinessFieldErrors(input) {
|
|
2247
2415
|
const result = validateBusinessDetails(input);
|
|
2248
2416
|
if (result.success) return {};
|
|
@@ -2256,7 +2424,7 @@ function mapBusinessFieldErrors(input) {
|
|
|
2256
2424
|
return errors;
|
|
2257
2425
|
}
|
|
2258
2426
|
function isBusinessDetailsKey(key) {
|
|
2259
|
-
return key === "isBusiness" || key === "businessName" || key === "country" || key === "customerCountry" || key === "customerName" || key === "taxId" || key === "taxIdType";
|
|
2427
|
+
return key === "isBusiness" || key === "businessName" || key === "country" || key === "customerCountry" || key === "customerName" || key === "customerState" || key === "customerPostalCode" || key === "taxId" || key === "taxIdType";
|
|
2260
2428
|
}
|
|
2261
2429
|
function attr(prefix, suffix) {
|
|
2262
2430
|
return `data-solvapay-${prefix}-${suffix}`;
|
|
@@ -2305,7 +2473,7 @@ function createBusinessDetailsParts(useCtx, prefix) {
|
|
|
2305
2473
|
const Root8 = forwardRef2(function BusinessDetailsRoot({ asChild, children, ...rest }, forwardedRef) {
|
|
2306
2474
|
useCtx("BusinessDetails");
|
|
2307
2475
|
const Comp = asChild ? Slot : "section";
|
|
2308
|
-
return /* @__PURE__ */
|
|
2476
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "business-details")]: "" }, ...rest, children });
|
|
2309
2477
|
});
|
|
2310
2478
|
const Toggle = forwardRef2(function BusinessDetailsToggle({ asChild, onChange, ...rest }, forwardedRef) {
|
|
2311
2479
|
const ctx = useCtx("BusinessDetails.Toggle");
|
|
@@ -2319,9 +2487,9 @@ function createBusinessDetailsParts(useCtx, prefix) {
|
|
|
2319
2487
|
...rest
|
|
2320
2488
|
};
|
|
2321
2489
|
if (asChild) {
|
|
2322
|
-
return /* @__PURE__ */
|
|
2490
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps });
|
|
2323
2491
|
}
|
|
2324
|
-
return /* @__PURE__ */
|
|
2492
|
+
return /* @__PURE__ */ jsx8("input", { ref: forwardedRef, ...commonProps });
|
|
2325
2493
|
});
|
|
2326
2494
|
const BusinessName = forwardRef2(
|
|
2327
2495
|
function BusinessDetailsBusinessName({ asChild, onChange, ...rest }, forwardedRef) {
|
|
@@ -2338,31 +2506,80 @@ function createBusinessDetailsParts(useCtx, prefix) {
|
|
|
2338
2506
|
...rest
|
|
2339
2507
|
};
|
|
2340
2508
|
if (asChild) {
|
|
2341
|
-
return /* @__PURE__ */
|
|
2509
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps });
|
|
2342
2510
|
}
|
|
2343
|
-
return /* @__PURE__ */
|
|
2511
|
+
return /* @__PURE__ */ jsx8("input", { ref: forwardedRef, ...commonProps });
|
|
2344
2512
|
}
|
|
2345
2513
|
);
|
|
2346
2514
|
const Country = forwardRef2(function BusinessDetailsCountry({ asChild, onChange, children, ...rest }, forwardedRef) {
|
|
2347
2515
|
const ctx = useCtx("BusinessDetails.Country");
|
|
2348
|
-
|
|
2516
|
+
const country = ctx.businessDetails.customerCountry ?? ctx.businessDetails.country ?? "";
|
|
2517
|
+
const countryError = ctx.fieldErrors.customerCountry ?? ctx.fieldErrors.country ? true : void 0;
|
|
2349
2518
|
const commonProps = {
|
|
2519
|
+
...rest,
|
|
2350
2520
|
[attr(prefix, "business-details-country")]: "",
|
|
2351
|
-
value:
|
|
2352
|
-
"aria-invalid":
|
|
2521
|
+
value: country,
|
|
2522
|
+
"aria-invalid": countryError,
|
|
2523
|
+
"aria-label": rest["aria-label"] ?? "Country",
|
|
2353
2524
|
onChange: composeEventHandlers(onChange, (e) => {
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2525
|
+
const nextCountry = e.target.value;
|
|
2526
|
+
ctx.setBusinessDetails({
|
|
2527
|
+
customerCountry: nextCountry || void 0,
|
|
2528
|
+
...ctx.businessDetails.isBusiness ? { country: nextCountry || void 0 } : {},
|
|
2529
|
+
...!isStateRequired(nextCountry) ? { customerState: void 0 } : {},
|
|
2530
|
+
...!isPostalCodeRequired(nextCountry) ? { customerPostalCode: void 0 } : {}
|
|
2531
|
+
});
|
|
2532
|
+
})
|
|
2357
2533
|
};
|
|
2358
2534
|
const defaultOptions = /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2359
|
-
/* @__PURE__ */
|
|
2360
|
-
BUSINESS_COUNTRY_OPTIONS.map(({ value, label }) => /* @__PURE__ */
|
|
2535
|
+
/* @__PURE__ */ jsx8("option", { value: "", children: "Select country" }),
|
|
2536
|
+
BUSINESS_COUNTRY_OPTIONS.map(({ value, label }) => /* @__PURE__ */ jsx8("option", { value, children: label }, value))
|
|
2361
2537
|
] });
|
|
2362
2538
|
if (asChild) {
|
|
2363
|
-
return /* @__PURE__ */
|
|
2539
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps, children: children ?? defaultOptions });
|
|
2540
|
+
}
|
|
2541
|
+
return /* @__PURE__ */ jsx8("select", { ref: forwardedRef, ...commonProps, children: children ?? defaultOptions });
|
|
2542
|
+
});
|
|
2543
|
+
const State = forwardRef2(function BusinessDetailsState({ asChild, onChange, ...rest }, forwardedRef) {
|
|
2544
|
+
const ctx = useCtx("BusinessDetails.State");
|
|
2545
|
+
const country = resolveBuyerCountry(ctx.businessDetails);
|
|
2546
|
+
if (!country || !isStateRequired(country)) return null;
|
|
2547
|
+
const commonProps = {
|
|
2548
|
+
...rest,
|
|
2549
|
+
[attr(prefix, "business-details-state")]: "",
|
|
2550
|
+
type: "text",
|
|
2551
|
+
value: ctx.businessDetails.customerState ?? "",
|
|
2552
|
+
"aria-invalid": ctx.fieldErrors.customerState ? true : void 0,
|
|
2553
|
+
"aria-label": rest["aria-label"] ?? getStateFieldLabel(country),
|
|
2554
|
+
onChange: composeEventHandlers(onChange, (e) => {
|
|
2555
|
+
ctx.setBusinessDetails({ customerState: e.target.value || void 0 });
|
|
2556
|
+
})
|
|
2557
|
+
};
|
|
2558
|
+
if (asChild) {
|
|
2559
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps });
|
|
2560
|
+
}
|
|
2561
|
+
return /* @__PURE__ */ jsx8("input", { ref: forwardedRef, ...commonProps });
|
|
2562
|
+
});
|
|
2563
|
+
const PostalCode = forwardRef2(function BusinessDetailsPostalCode({ asChild, onChange, ...rest }, forwardedRef) {
|
|
2564
|
+
const ctx = useCtx("BusinessDetails.PostalCode");
|
|
2565
|
+
const country = resolveBuyerCountry(ctx.businessDetails);
|
|
2566
|
+
if (!country || !isPostalCodeRequired(country)) return null;
|
|
2567
|
+
const commonProps = {
|
|
2568
|
+
...rest,
|
|
2569
|
+
[attr(prefix, "business-details-postal")]: "",
|
|
2570
|
+
type: "text",
|
|
2571
|
+
value: ctx.businessDetails.customerPostalCode ?? "",
|
|
2572
|
+
placeholder: rest.placeholder ?? getPostalCodePlaceholder(country),
|
|
2573
|
+
"aria-invalid": ctx.fieldErrors.customerPostalCode ? true : void 0,
|
|
2574
|
+
"aria-label": rest["aria-label"] ?? getPostalCodeFieldLabel(country),
|
|
2575
|
+
onChange: composeEventHandlers(onChange, (e) => {
|
|
2576
|
+
ctx.setBusinessDetails({ customerPostalCode: e.target.value || void 0 });
|
|
2577
|
+
})
|
|
2578
|
+
};
|
|
2579
|
+
if (asChild) {
|
|
2580
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps });
|
|
2364
2581
|
}
|
|
2365
|
-
return /* @__PURE__ */
|
|
2582
|
+
return /* @__PURE__ */ jsx8("input", { ref: forwardedRef, ...commonProps });
|
|
2366
2583
|
});
|
|
2367
2584
|
const TaxId = forwardRef2(function BusinessDetailsTaxId({ asChild, onChange, ...rest }, forwardedRef) {
|
|
2368
2585
|
const ctx = useCtx("BusinessDetails.TaxId");
|
|
@@ -2378,48 +2595,60 @@ function createBusinessDetailsParts(useCtx, prefix) {
|
|
|
2378
2595
|
...rest
|
|
2379
2596
|
};
|
|
2380
2597
|
if (asChild) {
|
|
2381
|
-
return /* @__PURE__ */
|
|
2598
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...commonProps });
|
|
2382
2599
|
}
|
|
2383
|
-
return /* @__PURE__ */
|
|
2600
|
+
return /* @__PURE__ */ jsx8("input", { ref: forwardedRef, ...commonProps });
|
|
2384
2601
|
});
|
|
2385
2602
|
const Fields = forwardRef2(function BusinessDetailsFields({ asChild, children, ...rest }, forwardedRef) {
|
|
2386
2603
|
const ctx = useCtx("BusinessDetails.Fields");
|
|
2387
|
-
const country = ctx.businessDetails
|
|
2604
|
+
const country = resolveBuyerCountry(ctx.businessDetails) ?? "";
|
|
2388
2605
|
const taxIdLabel = resolveTaxIdLabel(country);
|
|
2389
2606
|
const taxIdPlaceholder = resolveTaxIdPlaceholder(country);
|
|
2390
2607
|
const taxIdHelperText = resolveTaxIdHelperText(country);
|
|
2608
|
+
const showState = !!country && isStateRequired(country);
|
|
2609
|
+
const showPostal = !!country && isPostalCodeRequired(country);
|
|
2391
2610
|
const content = /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2611
|
+
/* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2612
|
+
/* @__PURE__ */ jsx8("span", { className: "solvapay-business-field-label", children: "Country" }),
|
|
2613
|
+
/* @__PURE__ */ jsx8(Country, {})
|
|
2614
|
+
] }),
|
|
2615
|
+
showState ? /* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2616
|
+
/* @__PURE__ */ jsx8("span", { className: "solvapay-business-field-label", children: getStateFieldLabel(country) }),
|
|
2617
|
+
/* @__PURE__ */ jsx8(State, {})
|
|
2618
|
+
] }) : null,
|
|
2619
|
+
showPostal ? /* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2620
|
+
/* @__PURE__ */ jsx8("span", { className: "solvapay-business-field-label", children: getPostalCodeFieldLabel(country) }),
|
|
2621
|
+
/* @__PURE__ */ jsx8(PostalCode, {})
|
|
2622
|
+
] }) : null,
|
|
2392
2623
|
/* @__PURE__ */ jsxs2("label", { className: "solvapay-checkout-business-toggle", children: [
|
|
2393
|
-
/* @__PURE__ */
|
|
2624
|
+
/* @__PURE__ */ jsx8(Toggle, {}),
|
|
2394
2625
|
"I'm purchasing as a business"
|
|
2395
2626
|
] }),
|
|
2396
2627
|
ctx.businessDetails.isBusiness ? /* @__PURE__ */ jsxs2("fieldset", { className: "solvapay-business-fields", children: [
|
|
2397
2628
|
/* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2398
|
-
/* @__PURE__ */
|
|
2399
|
-
/* @__PURE__ */
|
|
2400
|
-
] }),
|
|
2401
|
-
/* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2402
|
-
/* @__PURE__ */ jsx7("span", { className: "solvapay-business-field-label", children: "Country" }),
|
|
2403
|
-
/* @__PURE__ */ jsx7(Country, {})
|
|
2629
|
+
/* @__PURE__ */ jsx8("span", { className: "solvapay-business-field-label", children: "Business name" }),
|
|
2630
|
+
/* @__PURE__ */ jsx8(BusinessName, { placeholder: "Acme GmbH" })
|
|
2404
2631
|
] }),
|
|
2405
2632
|
/* @__PURE__ */ jsxs2("label", { className: "solvapay-business-field", children: [
|
|
2406
|
-
/* @__PURE__ */
|
|
2407
|
-
/* @__PURE__ */
|
|
2408
|
-
taxIdHelperText ? /* @__PURE__ */
|
|
2633
|
+
/* @__PURE__ */ jsx8("span", { className: "solvapay-business-field-label", children: taxIdLabel }),
|
|
2634
|
+
/* @__PURE__ */ jsx8(TaxId, { placeholder: taxIdPlaceholder }),
|
|
2635
|
+
taxIdHelperText ? /* @__PURE__ */ jsx8("p", { className: "solvapay-business-field-hint", children: taxIdHelperText }) : null
|
|
2409
2636
|
] })
|
|
2410
2637
|
] }) : null,
|
|
2411
2638
|
children
|
|
2412
2639
|
] });
|
|
2413
2640
|
if (asChild) {
|
|
2414
|
-
return /* @__PURE__ */
|
|
2641
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...rest, children: content });
|
|
2415
2642
|
}
|
|
2416
|
-
return /* @__PURE__ */
|
|
2643
|
+
return /* @__PURE__ */ jsx8("section", { ref: forwardedRef, ...{ [attr(prefix, "business-details-fields")]: "" }, ...rest, children: content });
|
|
2417
2644
|
});
|
|
2418
2645
|
return {
|
|
2419
2646
|
Root: Root8,
|
|
2420
2647
|
Toggle,
|
|
2421
2648
|
BusinessName,
|
|
2422
2649
|
Country,
|
|
2650
|
+
State,
|
|
2651
|
+
PostalCode,
|
|
2423
2652
|
TaxId,
|
|
2424
2653
|
Fields
|
|
2425
2654
|
};
|
|
@@ -2448,14 +2677,14 @@ function createTaxSummaryParts(useCtx, prefix) {
|
|
|
2448
2677
|
const ctx = useCtx("Summary");
|
|
2449
2678
|
if (!ctx.isBusiness) return null;
|
|
2450
2679
|
const Comp = asChild ? Slot : "section";
|
|
2451
|
-
return /* @__PURE__ */
|
|
2680
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "summary")]: "" }, ...rest, children });
|
|
2452
2681
|
});
|
|
2453
2682
|
const Subtotal = forwardRef2(function TaxSummarySubtotal({ asChild, children, ...rest }, forwardedRef) {
|
|
2454
2683
|
const ctx = useCtx("Summary.Subtotal");
|
|
2455
2684
|
const { subtotalFormatted } = useSummaryAmounts(useCtx, "Summary.Subtotal");
|
|
2456
2685
|
if (!ctx.isBusiness) return null;
|
|
2457
2686
|
const Comp = asChild ? Slot : "span";
|
|
2458
|
-
return /* @__PURE__ */
|
|
2687
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "summary-subtotal")]: "" }, ...rest, children: children ?? subtotalFormatted });
|
|
2459
2688
|
});
|
|
2460
2689
|
const Tax = forwardRef2(function TaxSummaryTax({ asChild, children, ...rest }, forwardedRef) {
|
|
2461
2690
|
const ctx = useCtx("Summary.Tax");
|
|
@@ -2467,10 +2696,10 @@ function createTaxSummaryParts(useCtx, prefix) {
|
|
|
2467
2696
|
treatment: treatment ?? "standard",
|
|
2468
2697
|
taxRate
|
|
2469
2698
|
});
|
|
2470
|
-
return /* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
2699
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "summary-tax")]: "" }, ...rest, children: children ?? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2700
|
+
/* @__PURE__ */ jsx8("span", { children: defaultLabel }),
|
|
2472
2701
|
" ",
|
|
2473
|
-
/* @__PURE__ */
|
|
2702
|
+
/* @__PURE__ */ jsx8("span", { ...{ [attr(prefix, "summary-tax-amount")]: "" }, children: taxFormatted })
|
|
2474
2703
|
] }) });
|
|
2475
2704
|
});
|
|
2476
2705
|
const Total = forwardRef2(function TaxSummaryTotal({ asChild, children, ...rest }, forwardedRef) {
|
|
@@ -2478,7 +2707,7 @@ function createTaxSummaryParts(useCtx, prefix) {
|
|
|
2478
2707
|
const { totalFormatted } = useSummaryAmounts(useCtx, "Summary.Total");
|
|
2479
2708
|
if (!ctx.isBusiness) return null;
|
|
2480
2709
|
const Comp = asChild ? Slot : "span";
|
|
2481
|
-
return /* @__PURE__ */
|
|
2710
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "summary-total")]: "" }, ...rest, children: children ?? totalFormatted });
|
|
2482
2711
|
});
|
|
2483
2712
|
const TaxNote = forwardRef2(function TaxSummaryTaxNote({ asChild, children, ...rest }, forwardedRef) {
|
|
2484
2713
|
const ctx = useCtx("Summary.TaxNote");
|
|
@@ -2488,7 +2717,7 @@ function createTaxSummaryParts(useCtx, prefix) {
|
|
|
2488
2717
|
const Comp = asChild ? Slot : "p";
|
|
2489
2718
|
const defaultNote = treatment === "reverse_charge" ? REVERSE_CHARGE_NOTE : treatment === "not_collecting" || treatment === "not_supported" ? TAX_NOT_COLLECTED_NOTE : null;
|
|
2490
2719
|
if (!defaultNote && !children) return null;
|
|
2491
|
-
return /* @__PURE__ */
|
|
2720
|
+
return /* @__PURE__ */ jsx8(Comp, { ref: forwardedRef, ...{ [attr(prefix, "summary-tax-note")]: "" }, ...rest, children: children ?? defaultNote });
|
|
2492
2721
|
});
|
|
2493
2722
|
const Rows = forwardRef2(function TaxSummaryRows({ asChild, children, ...rest }, forwardedRef) {
|
|
2494
2723
|
const ctx = useCtx("Summary.Rows");
|
|
@@ -2501,24 +2730,24 @@ function createTaxSummaryParts(useCtx, prefix) {
|
|
|
2501
2730
|
});
|
|
2502
2731
|
const content = /* @__PURE__ */ jsxs2("dl", { className: "solvapay-tax-summary-rows", children: [
|
|
2503
2732
|
/* @__PURE__ */ jsxs2("div", { className: "solvapay-tax-summary-row", children: [
|
|
2504
|
-
/* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2733
|
+
/* @__PURE__ */ jsx8("dt", { children: formatSubtotalLabel(treatment) }),
|
|
2734
|
+
/* @__PURE__ */ jsx8("dd", { children: /* @__PURE__ */ jsx8(Subtotal, {}) })
|
|
2506
2735
|
] }),
|
|
2507
2736
|
showTaxRow ? /* @__PURE__ */ jsxs2("div", { className: "solvapay-tax-summary-row", children: [
|
|
2508
|
-
/* @__PURE__ */
|
|
2509
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx8("dt", { children: vatLabel }),
|
|
2738
|
+
/* @__PURE__ */ jsx8("dd", { children: /* @__PURE__ */ jsx8("span", { ...{ [attr(prefix, "summary-tax-amount")]: "" }, children: taxFormatted }) })
|
|
2510
2739
|
] }) : null,
|
|
2511
2740
|
/* @__PURE__ */ jsxs2("div", { className: "solvapay-tax-summary-row solvapay-tax-summary-row--total", children: [
|
|
2512
|
-
/* @__PURE__ */
|
|
2513
|
-
/* @__PURE__ */
|
|
2741
|
+
/* @__PURE__ */ jsx8("dt", { children: "Total" }),
|
|
2742
|
+
/* @__PURE__ */ jsx8("dd", { children: /* @__PURE__ */ jsx8(Total, {}) })
|
|
2514
2743
|
] }),
|
|
2515
|
-
/* @__PURE__ */
|
|
2744
|
+
/* @__PURE__ */ jsx8(TaxNote, {}),
|
|
2516
2745
|
children
|
|
2517
2746
|
] });
|
|
2518
2747
|
if (asChild) {
|
|
2519
|
-
return /* @__PURE__ */
|
|
2748
|
+
return /* @__PURE__ */ jsx8(Slot, { ref: forwardedRef, ...rest, children: content });
|
|
2520
2749
|
}
|
|
2521
|
-
return /* @__PURE__ */
|
|
2750
|
+
return /* @__PURE__ */ jsx8("section", { ref: forwardedRef, ...{ [attr(prefix, "summary-rows")]: "" }, ...rest, children: content });
|
|
2522
2751
|
});
|
|
2523
2752
|
return {
|
|
2524
2753
|
Root: Root8,
|
|
@@ -2566,10 +2795,10 @@ var MissingProductRefError = class extends SolvaPayError2 {
|
|
|
2566
2795
|
};
|
|
2567
2796
|
|
|
2568
2797
|
// src/primitives/CheckoutSummary.tsx
|
|
2569
|
-
import { Fragment as Fragment4, jsx as
|
|
2570
|
-
var CheckoutSummaryContext =
|
|
2798
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2799
|
+
var CheckoutSummaryContext = createContext6(null);
|
|
2571
2800
|
function useCheckoutSummaryContext(part) {
|
|
2572
|
-
const ctx =
|
|
2801
|
+
const ctx = useContext7(CheckoutSummaryContext);
|
|
2573
2802
|
if (!ctx) {
|
|
2574
2803
|
throw new Error(
|
|
2575
2804
|
`CheckoutSummary.${part} must be rendered inside <CheckoutSummary.Root>.`
|
|
@@ -2578,7 +2807,7 @@ function useCheckoutSummaryContext(part) {
|
|
|
2578
2807
|
return ctx;
|
|
2579
2808
|
}
|
|
2580
2809
|
var Root = forwardRef3(function CheckoutSummaryRoot({ planRef, productRef, taxBreakdown = null, baseAmountMinor = 0, asChild, children, ...rest }, forwardedRef) {
|
|
2581
|
-
const solva =
|
|
2810
|
+
const solva = useContext7(SolvaPayContext);
|
|
2582
2811
|
if (!solva) throw new MissingProviderError("CheckoutSummary");
|
|
2583
2812
|
const locale = useLocale();
|
|
2584
2813
|
const copy = useCopy();
|
|
@@ -2640,35 +2869,35 @@ var Root = forwardRef3(function CheckoutSummaryRoot({ planRef, productRef, taxBr
|
|
|
2640
2869
|
]
|
|
2641
2870
|
);
|
|
2642
2871
|
const Comp = asChild ? Slot : "section";
|
|
2643
|
-
return /* @__PURE__ */
|
|
2872
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary": "", ...rest, children: /* @__PURE__ */ jsx9(CheckoutSummaryContext.Provider, { value: ctx, children }) });
|
|
2644
2873
|
});
|
|
2645
2874
|
var ProductSlot = forwardRef3(function CheckoutSummaryProduct({ asChild, children, ...rest }, forwardedRef) {
|
|
2646
2875
|
const ctx = useCheckoutSummaryContext("Product");
|
|
2647
2876
|
const name = ctx.product?.name;
|
|
2648
2877
|
if (!name) return null;
|
|
2649
2878
|
const Comp = asChild ? Slot : "span";
|
|
2650
|
-
return /* @__PURE__ */
|
|
2879
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-product": "", ...rest, children: children ?? name });
|
|
2651
2880
|
});
|
|
2652
2881
|
var PlanSlot = forwardRef3(function CheckoutSummaryPlan({ asChild, children, ...rest }, forwardedRef) {
|
|
2653
2882
|
const ctx = useCheckoutSummaryContext("Plan");
|
|
2654
2883
|
const name = ctx.plan?.name;
|
|
2655
2884
|
if (!name) return null;
|
|
2656
2885
|
const Comp = asChild ? Slot : "span";
|
|
2657
|
-
return /* @__PURE__ */
|
|
2886
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-plan": "", ...rest, children: children ?? name });
|
|
2658
2887
|
});
|
|
2659
2888
|
var TaxNoteSlot = forwardRef3(
|
|
2660
2889
|
function CheckoutSummaryTaxNote({ asChild, children, ...rest }, forwardedRef) {
|
|
2661
2890
|
const ctx = useCheckoutSummaryContext("TaxNote");
|
|
2662
2891
|
if (ctx.taxBreakdown) return null;
|
|
2663
2892
|
const Comp = asChild ? Slot : "p";
|
|
2664
|
-
return /* @__PURE__ */
|
|
2893
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-tax-note": "", ...rest, children: children ?? "Taxes calculated at checkout" });
|
|
2665
2894
|
}
|
|
2666
2895
|
);
|
|
2667
2896
|
var SubtotalSlot = forwardRef3(function CheckoutSummarySubtotal({ asChild, children, ...rest }, forwardedRef) {
|
|
2668
2897
|
const ctx = useCheckoutSummaryContext("Subtotal");
|
|
2669
2898
|
if (!ctx.taxBreakdown) return null;
|
|
2670
2899
|
const Comp = asChild ? Slot : "span";
|
|
2671
|
-
return /* @__PURE__ */
|
|
2900
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-subtotal": "", ...rest, children: children ?? ctx.subtotalFormatted });
|
|
2672
2901
|
});
|
|
2673
2902
|
var TaxSlot = forwardRef3(function CheckoutSummaryTax({ asChild, children, ...rest }, forwardedRef) {
|
|
2674
2903
|
const ctx = useCheckoutSummaryContext("Tax");
|
|
@@ -2677,17 +2906,17 @@ var TaxSlot = forwardRef3(function CheckoutSummaryTax({ asChild, children, ...re
|
|
|
2677
2906
|
if (!shouldShowTaxRow(treatment)) return null;
|
|
2678
2907
|
const Comp = asChild ? Slot : "span";
|
|
2679
2908
|
const defaultLabel = formatVatSummaryLabel({ treatment, taxRate: taxRate ?? 0 });
|
|
2680
|
-
return /* @__PURE__ */
|
|
2681
|
-
/* @__PURE__ */
|
|
2909
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-tax": "", ...rest, children: children ?? /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
2910
|
+
/* @__PURE__ */ jsx9("span", { children: defaultLabel }),
|
|
2682
2911
|
" ",
|
|
2683
|
-
/* @__PURE__ */
|
|
2912
|
+
/* @__PURE__ */ jsx9("span", { "data-solvapay-checkout-summary-tax-amount": "", children: ctx.taxFormatted })
|
|
2684
2913
|
] }) });
|
|
2685
2914
|
});
|
|
2686
2915
|
var TotalSlot = forwardRef3(function CheckoutSummaryTotal({ asChild, children, ...rest }, forwardedRef) {
|
|
2687
2916
|
const ctx = useCheckoutSummaryContext("Total");
|
|
2688
2917
|
if (!ctx.taxBreakdown) return null;
|
|
2689
2918
|
const Comp = asChild ? Slot : "span";
|
|
2690
|
-
return /* @__PURE__ */
|
|
2919
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-total": "", ...rest, children: children ?? ctx.totalFormatted });
|
|
2691
2920
|
});
|
|
2692
2921
|
var TaxTreatmentNoteSlot = forwardRef3(
|
|
2693
2922
|
function CheckoutSummaryTaxTreatmentNote({ asChild, children, ...rest }, forwardedRef) {
|
|
@@ -2697,21 +2926,21 @@ var TaxTreatmentNoteSlot = forwardRef3(
|
|
|
2697
2926
|
const Comp = asChild ? Slot : "p";
|
|
2698
2927
|
const defaultNote = treatment === "reverse_charge" ? REVERSE_CHARGE_NOTE : treatment === "not_collecting" || treatment === "not_supported" ? TAX_NOT_COLLECTED_NOTE : null;
|
|
2699
2928
|
if (!defaultNote && !children) return null;
|
|
2700
|
-
return /* @__PURE__ */
|
|
2929
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-tax-treatment-note": "", ...rest, children: children ?? defaultNote });
|
|
2701
2930
|
}
|
|
2702
2931
|
);
|
|
2703
2932
|
var PriceSlot = forwardRef3(function CheckoutSummaryPrice({ asChild, children, ...rest }, forwardedRef) {
|
|
2704
2933
|
const ctx = useCheckoutSummaryContext("Price");
|
|
2705
2934
|
if (ctx.taxBreakdown) return null;
|
|
2706
2935
|
const Comp = asChild ? Slot : "span";
|
|
2707
|
-
return /* @__PURE__ */
|
|
2936
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-price": "", ...rest, children: children ?? ctx.priceFormatted });
|
|
2708
2937
|
});
|
|
2709
2938
|
var TrialSlot = forwardRef3(
|
|
2710
2939
|
function CheckoutSummaryTrial({ asChild, children, ...rest }, forwardedRef) {
|
|
2711
2940
|
const ctx = useCheckoutSummaryContext("Trial");
|
|
2712
2941
|
if (!ctx.trialBanner || ctx.taxBreakdown) return null;
|
|
2713
2942
|
const Comp = asChild ? Slot : "p";
|
|
2714
|
-
return /* @__PURE__ */
|
|
2943
|
+
return /* @__PURE__ */ jsx9(Comp, { ref: forwardedRef, "data-solvapay-checkout-summary-trial": "", ...rest, children: children ?? ctx.trialBanner });
|
|
2715
2944
|
}
|
|
2716
2945
|
);
|
|
2717
2946
|
var CheckoutSummaryRoot2 = Root;
|
|
@@ -2741,7 +2970,7 @@ function useCheckoutSummary() {
|
|
|
2741
2970
|
}
|
|
2742
2971
|
|
|
2743
2972
|
// src/components/CheckoutSummary.tsx
|
|
2744
|
-
import { Fragment as Fragment5, jsx as
|
|
2973
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2745
2974
|
var CheckoutSummary2 = ({
|
|
2746
2975
|
planRef,
|
|
2747
2976
|
productRef,
|
|
@@ -2762,25 +2991,25 @@ var CheckoutSummary2 = ({
|
|
|
2762
2991
|
baseAmountMinor,
|
|
2763
2992
|
className: rootClass,
|
|
2764
2993
|
children: [
|
|
2765
|
-
/* @__PURE__ */
|
|
2994
|
+
/* @__PURE__ */ jsx10(CheckoutSummary.Product, { className: "solvapay-checkout-summary-product" }),
|
|
2766
2995
|
/* @__PURE__ */ jsxs4("div", { className: "solvapay-checkout-summary-row", children: [
|
|
2767
|
-
/* @__PURE__ */
|
|
2768
|
-
!hasTax && /* @__PURE__ */
|
|
2996
|
+
/* @__PURE__ */ jsx10(CheckoutSummary.Plan, { className: "solvapay-checkout-summary-plan" }),
|
|
2997
|
+
!hasTax && /* @__PURE__ */ jsx10(CheckoutSummary.Price, { className: "solvapay-checkout-summary-price" })
|
|
2769
2998
|
] }),
|
|
2770
2999
|
hasTax ? /* @__PURE__ */ jsxs4(Fragment5, { children: [
|
|
2771
3000
|
/* @__PURE__ */ jsxs4("div", { className: "solvapay-checkout-summary-row", children: [
|
|
2772
|
-
/* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
3001
|
+
/* @__PURE__ */ jsx10("span", { children: "Subtotal" }),
|
|
3002
|
+
/* @__PURE__ */ jsx10(CheckoutSummary.Subtotal, { className: "solvapay-checkout-summary-subtotal" })
|
|
2774
3003
|
] }),
|
|
2775
|
-
/* @__PURE__ */
|
|
3004
|
+
/* @__PURE__ */ jsx10("div", { className: "solvapay-checkout-summary-row", children: /* @__PURE__ */ jsx10(CheckoutSummary.Tax, { className: "solvapay-checkout-summary-tax" }) }),
|
|
2776
3005
|
/* @__PURE__ */ jsxs4("div", { className: "solvapay-checkout-summary-row", children: [
|
|
2777
|
-
/* @__PURE__ */
|
|
2778
|
-
/* @__PURE__ */
|
|
3006
|
+
/* @__PURE__ */ jsx10("span", { children: "Total" }),
|
|
3007
|
+
/* @__PURE__ */ jsx10(CheckoutSummary.Total, { className: "solvapay-checkout-summary-total" })
|
|
2779
3008
|
] }),
|
|
2780
|
-
/* @__PURE__ */
|
|
3009
|
+
/* @__PURE__ */ jsx10(CheckoutSummary.TaxTreatmentNote, { className: "solvapay-checkout-summary-tax-treatment-note" })
|
|
2781
3010
|
] }) : /* @__PURE__ */ jsxs4(Fragment5, { children: [
|
|
2782
|
-
showTrial && /* @__PURE__ */
|
|
2783
|
-
showTaxNote && /* @__PURE__ */
|
|
3011
|
+
showTrial && /* @__PURE__ */ jsx10(CheckoutSummary.Trial, { className: "solvapay-checkout-summary-trial" }),
|
|
3012
|
+
showTaxNote && /* @__PURE__ */ jsx10(CheckoutSummary.TaxNote, { className: "solvapay-checkout-summary-tax-note" })
|
|
2784
3013
|
] })
|
|
2785
3014
|
]
|
|
2786
3015
|
}
|
|
@@ -2788,7 +3017,7 @@ var CheckoutSummary2 = ({
|
|
|
2788
3017
|
};
|
|
2789
3018
|
|
|
2790
3019
|
// src/hooks/useMerchant.ts
|
|
2791
|
-
import { useCallback as
|
|
3020
|
+
import { useCallback as useCallback8, useEffect as useEffect5, useState as useState7 } from "react";
|
|
2792
3021
|
var merchantCache = /* @__PURE__ */ new Map();
|
|
2793
3022
|
var CACHE_DURATION5 = 5 * 60 * 1e3;
|
|
2794
3023
|
function cacheKeyFor2(config) {
|
|
@@ -2810,7 +3039,7 @@ function useMerchant() {
|
|
|
2810
3039
|
return !cached || !cached.merchant && !cached.promise;
|
|
2811
3040
|
});
|
|
2812
3041
|
const [error, setError] = useState7(null);
|
|
2813
|
-
const load =
|
|
3042
|
+
const load = useCallback8(
|
|
2814
3043
|
async (force = false) => {
|
|
2815
3044
|
const cached = merchantCache.get(key);
|
|
2816
3045
|
const now = Date.now();
|
|
@@ -2893,8 +3122,8 @@ function deriveVariant(plan, mode) {
|
|
|
2893
3122
|
}
|
|
2894
3123
|
|
|
2895
3124
|
// src/primitives/MandateText.tsx
|
|
2896
|
-
import { forwardRef as forwardRef4, useContext as
|
|
2897
|
-
import { jsx as
|
|
3125
|
+
import { forwardRef as forwardRef4, useContext as useContext8, useMemo as useMemo5 } from "react";
|
|
3126
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2898
3127
|
var MandateText = forwardRef4(
|
|
2899
3128
|
function MandateText2({
|
|
2900
3129
|
planRef,
|
|
@@ -2907,10 +3136,11 @@ var MandateText = forwardRef4(
|
|
|
2907
3136
|
children,
|
|
2908
3137
|
...rest
|
|
2909
3138
|
}, forwardedRef) {
|
|
2910
|
-
const solva =
|
|
3139
|
+
const solva = useContext8(SolvaPayContext);
|
|
2911
3140
|
if (!solva) throw new MissingProviderError("MandateText");
|
|
2912
3141
|
const locale = useLocale();
|
|
2913
3142
|
const copy = useCopy();
|
|
3143
|
+
const handleExternalClick = useExternalLinkClick();
|
|
2914
3144
|
const planSelection = usePlanSelection();
|
|
2915
3145
|
const resolvedPlanRef = planRef ?? planSelection?.selectedPlanRef ?? void 0;
|
|
2916
3146
|
const resolvedProductRef = productRef ?? planSelection?.productRef;
|
|
@@ -2951,19 +3181,19 @@ var MandateText = forwardRef4(
|
|
|
2951
3181
|
const text = typeof template === "function" ? template(ctx) : template;
|
|
2952
3182
|
if (!text) return null;
|
|
2953
3183
|
const Comp = asChild ? Slot : "p";
|
|
2954
|
-
return /* @__PURE__ */
|
|
3184
|
+
return /* @__PURE__ */ jsx11(
|
|
2955
3185
|
Comp,
|
|
2956
3186
|
{
|
|
2957
3187
|
ref: forwardedRef,
|
|
2958
3188
|
"data-solvapay-mandate-text": "",
|
|
2959
3189
|
"data-variant": resolvedVariant,
|
|
2960
3190
|
...rest,
|
|
2961
|
-
children: children ?? linkifyMandateText(text, ctx.merchant, copy)
|
|
3191
|
+
children: children ?? linkifyMandateText(text, ctx.merchant, copy, handleExternalClick)
|
|
2962
3192
|
}
|
|
2963
3193
|
);
|
|
2964
3194
|
}
|
|
2965
3195
|
);
|
|
2966
|
-
function linkifyMandateText(text, merchant, copy) {
|
|
3196
|
+
function linkifyMandateText(text, merchant, copy, onLinkClick) {
|
|
2967
3197
|
const entries = [
|
|
2968
3198
|
{ url: merchant.termsUrl, label: copy.legalFooter.terms },
|
|
2969
3199
|
{ url: merchant.privacyUrl, label: copy.legalFooter.privacy }
|
|
@@ -2973,13 +3203,14 @@ function linkifyMandateText(text, merchant, copy) {
|
|
|
2973
3203
|
return text.split(pattern).map((part, i) => {
|
|
2974
3204
|
const match = entries.find((e) => e.url === part);
|
|
2975
3205
|
if (!match) return part;
|
|
2976
|
-
return /* @__PURE__ */
|
|
3206
|
+
return /* @__PURE__ */ jsx11(
|
|
2977
3207
|
"a",
|
|
2978
3208
|
{
|
|
2979
3209
|
href: match.url,
|
|
2980
3210
|
target: "_blank",
|
|
2981
3211
|
rel: "noopener noreferrer",
|
|
2982
3212
|
"data-solvapay-mandate-link": "",
|
|
3213
|
+
onClick: onLinkClick,
|
|
2983
3214
|
children: match.label || match.url
|
|
2984
3215
|
},
|
|
2985
3216
|
i
|
|
@@ -2991,22 +3222,22 @@ function escapeRegExp(value) {
|
|
|
2991
3222
|
}
|
|
2992
3223
|
|
|
2993
3224
|
// src/components/Spinner.tsx
|
|
2994
|
-
import { jsx as
|
|
3225
|
+
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2995
3226
|
var SIZE_PX = { sm: 16, md: 20, lg: 24 };
|
|
2996
3227
|
var Spinner = ({ className, size = "md" }) => {
|
|
2997
|
-
const
|
|
3228
|
+
const px2 = SIZE_PX[size];
|
|
2998
3229
|
return /* @__PURE__ */ jsxs5(
|
|
2999
3230
|
"svg",
|
|
3000
3231
|
{
|
|
3001
3232
|
"data-solvapay-spinner": "",
|
|
3002
3233
|
className,
|
|
3003
|
-
width:
|
|
3004
|
-
height:
|
|
3234
|
+
width: px2,
|
|
3235
|
+
height: px2,
|
|
3005
3236
|
viewBox: "0 0 24 24",
|
|
3006
3237
|
fill: "none",
|
|
3007
3238
|
"aria-hidden": "true",
|
|
3008
3239
|
children: [
|
|
3009
|
-
/* @__PURE__ */
|
|
3240
|
+
/* @__PURE__ */ jsx12(
|
|
3010
3241
|
"circle",
|
|
3011
3242
|
{
|
|
3012
3243
|
cx: "12",
|
|
@@ -3017,7 +3248,7 @@ var Spinner = ({ className, size = "md" }) => {
|
|
|
3017
3248
|
strokeOpacity: "0.25"
|
|
3018
3249
|
}
|
|
3019
3250
|
),
|
|
3020
|
-
/* @__PURE__ */
|
|
3251
|
+
/* @__PURE__ */ jsx12(
|
|
3021
3252
|
"path",
|
|
3022
3253
|
{
|
|
3023
3254
|
fill: "currentColor",
|
|
@@ -3031,6 +3262,26 @@ var Spinner = ({ className, size = "md" }) => {
|
|
|
3031
3262
|
};
|
|
3032
3263
|
|
|
3033
3264
|
// src/utils/confirmPayment.ts
|
|
3265
|
+
function buildConfirmBillingDetails(input) {
|
|
3266
|
+
const name = input.name?.trim();
|
|
3267
|
+
const email = input.email?.trim();
|
|
3268
|
+
const country = input.country?.trim();
|
|
3269
|
+
if (!name && !email && !country) return void 0;
|
|
3270
|
+
return {
|
|
3271
|
+
...name && { name },
|
|
3272
|
+
...email && { email },
|
|
3273
|
+
...country && {
|
|
3274
|
+
address: {
|
|
3275
|
+
line1: "",
|
|
3276
|
+
line2: "",
|
|
3277
|
+
city: "",
|
|
3278
|
+
state: input.state?.trim() ?? "",
|
|
3279
|
+
postal_code: input.postalCode?.trim() ?? "",
|
|
3280
|
+
country
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3034
3285
|
async function confirmPayment(input) {
|
|
3035
3286
|
const { stripe, elements, clientSecret, returnUrl, billingDetails, copy } = input;
|
|
3036
3287
|
const mode = input.mode ?? "payment-element";
|
|
@@ -3157,14 +3408,14 @@ function resolveCta(input) {
|
|
|
3157
3408
|
}
|
|
3158
3409
|
|
|
3159
3410
|
// src/primitives/PaymentForm.tsx
|
|
3160
|
-
import
|
|
3411
|
+
import React11, {
|
|
3161
3412
|
forwardRef as forwardRef5,
|
|
3162
|
-
useCallback as
|
|
3163
|
-
useContext as
|
|
3164
|
-
useEffect as
|
|
3165
|
-
useMemo as
|
|
3413
|
+
useCallback as useCallback10,
|
|
3414
|
+
useContext as useContext9,
|
|
3415
|
+
useEffect as useEffect8,
|
|
3416
|
+
useMemo as useMemo7,
|
|
3166
3417
|
useRef as useRef5,
|
|
3167
|
-
useState as
|
|
3418
|
+
useState as useState10
|
|
3168
3419
|
} from "react";
|
|
3169
3420
|
import {
|
|
3170
3421
|
Elements,
|
|
@@ -3237,18 +3488,205 @@ function toStripeElementLocale(locale) {
|
|
|
3237
3488
|
|
|
3238
3489
|
// src/primitives/paymentElementDefaults.ts
|
|
3239
3490
|
var DEFAULT_PAYMENT_ELEMENT_OPTIONS = {
|
|
3240
|
-
wallets: { link: "never" }
|
|
3491
|
+
wallets: { link: "never" },
|
|
3492
|
+
fields: { billingDetails: { address: "never" } },
|
|
3493
|
+
layout: { type: "tabs" }
|
|
3241
3494
|
};
|
|
3242
3495
|
function withPaymentElementDefaults(options) {
|
|
3496
|
+
const defaultBilling = DEFAULT_PAYMENT_ELEMENT_OPTIONS.fields.billingDetails;
|
|
3497
|
+
const callerBilling = options?.fields?.billingDetails;
|
|
3498
|
+
const billingDetails = callerBilling && typeof callerBilling === "object" ? { ...defaultBilling, ...callerBilling } : callerBilling ?? defaultBilling;
|
|
3243
3499
|
return {
|
|
3500
|
+
...DEFAULT_PAYMENT_ELEMENT_OPTIONS,
|
|
3244
3501
|
...options,
|
|
3245
3502
|
wallets: {
|
|
3246
3503
|
...DEFAULT_PAYMENT_ELEMENT_OPTIONS.wallets,
|
|
3247
3504
|
...options?.wallets
|
|
3505
|
+
},
|
|
3506
|
+
fields: {
|
|
3507
|
+
...DEFAULT_PAYMENT_ELEMENT_OPTIONS.fields,
|
|
3508
|
+
...options?.fields,
|
|
3509
|
+
billingDetails
|
|
3248
3510
|
}
|
|
3249
3511
|
};
|
|
3250
3512
|
}
|
|
3251
3513
|
|
|
3514
|
+
// src/primitives/useStripeAppearance.ts
|
|
3515
|
+
import { useEffect as useEffect6, useLayoutEffect, useMemo as useMemo6, useState as useState8 } from "react";
|
|
3516
|
+
|
|
3517
|
+
// src/primitives/buildStripeAppearance.ts
|
|
3518
|
+
var SENTINEL_TOKEN = "--solvapay-radius";
|
|
3519
|
+
var COLOR_VARIABLES = {
|
|
3520
|
+
colorBackground: "--solvapay-surface",
|
|
3521
|
+
colorText: "--solvapay-accent",
|
|
3522
|
+
colorTextSecondary: "--solvapay-muted-foreground",
|
|
3523
|
+
colorPrimary: "--solvapay-selection",
|
|
3524
|
+
colorDanger: "--solvapay-danger"
|
|
3525
|
+
};
|
|
3526
|
+
var DIRECT_VARIABLES = {
|
|
3527
|
+
borderRadius: "--solvapay-radius",
|
|
3528
|
+
fontFamily: "--solvapay-font"
|
|
3529
|
+
};
|
|
3530
|
+
var CSS_WIDE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3531
|
+
"",
|
|
3532
|
+
"inherit",
|
|
3533
|
+
"initial",
|
|
3534
|
+
"unset",
|
|
3535
|
+
"revert",
|
|
3536
|
+
"revert-layer"
|
|
3537
|
+
]);
|
|
3538
|
+
var CONTROL_HEIGHT_RATIO = 2.5;
|
|
3539
|
+
var CONTROL_PADDING_X_RATIO = 0.75;
|
|
3540
|
+
var LINE_HEIGHT_RATIO = 1.5;
|
|
3541
|
+
var LABEL_FONT_RATIO = 0.8125;
|
|
3542
|
+
var LABEL_MARGIN_RATIO = 0.5;
|
|
3543
|
+
var ERROR_FONT_RATIO = 0.75;
|
|
3544
|
+
var ERROR_MARGIN_RATIO = 0.375;
|
|
3545
|
+
function readRootFontPx(root) {
|
|
3546
|
+
const px2 = parseFloat(getComputedStyle(root).fontSize);
|
|
3547
|
+
return Number.isFinite(px2) && px2 > 0 ? px2 : 16;
|
|
3548
|
+
}
|
|
3549
|
+
function px(value) {
|
|
3550
|
+
return `${value}px`;
|
|
3551
|
+
}
|
|
3552
|
+
function deriveControlMetrics(rootPx) {
|
|
3553
|
+
const lineHeight = LINE_HEIGHT_RATIO * rootPx;
|
|
3554
|
+
const paddingY = (CONTROL_HEIGHT_RATIO * rootPx - 2 - lineHeight) / 2;
|
|
3555
|
+
const paddingX = CONTROL_PADDING_X_RATIO * rootPx;
|
|
3556
|
+
const gridGap = CONTROL_PADDING_X_RATIO * rootPx;
|
|
3557
|
+
return {
|
|
3558
|
+
fontSize: px(rootPx),
|
|
3559
|
+
lineHeight: px(lineHeight),
|
|
3560
|
+
padding: `${px(paddingY)} ${px(paddingX)}`,
|
|
3561
|
+
labelFontSize: px(LABEL_FONT_RATIO * rootPx),
|
|
3562
|
+
labelMarginBottom: px(LABEL_MARGIN_RATIO * rootPx),
|
|
3563
|
+
errorFontSize: px(ERROR_FONT_RATIO * rootPx),
|
|
3564
|
+
errorMarginTop: px(ERROR_MARGIN_RATIO * rootPx),
|
|
3565
|
+
gridGap: px(gridGap)
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
function isUsableToken(value) {
|
|
3569
|
+
return !CSS_WIDE_KEYWORDS.has(value.trim().toLowerCase());
|
|
3570
|
+
}
|
|
3571
|
+
function readToken(style, name) {
|
|
3572
|
+
const value = style.getPropertyValue(name).trim();
|
|
3573
|
+
return isUsableToken(value) ? value : void 0;
|
|
3574
|
+
}
|
|
3575
|
+
function resolveColor(probe, raw) {
|
|
3576
|
+
probe.style.color = raw;
|
|
3577
|
+
const resolved = getComputedStyle(probe).color.trim();
|
|
3578
|
+
if (!isUsableToken(resolved)) return void 0;
|
|
3579
|
+
if (resolved.toLowerCase().includes("light-dark")) return void 0;
|
|
3580
|
+
return resolved;
|
|
3581
|
+
}
|
|
3582
|
+
function buildStripeAppearance(root) {
|
|
3583
|
+
const style = getComputedStyle(root);
|
|
3584
|
+
if (!readToken(style, SENTINEL_TOKEN)) return void 0;
|
|
3585
|
+
const probe = document.createElement("span");
|
|
3586
|
+
probe.style.cssText = "position:absolute;left:-9999px;top:0";
|
|
3587
|
+
root.appendChild(probe);
|
|
3588
|
+
const rootPx = readRootFontPx(root);
|
|
3589
|
+
const metrics = deriveControlMetrics(rootPx);
|
|
3590
|
+
const variables = {
|
|
3591
|
+
fontSizeBase: metrics.fontSize,
|
|
3592
|
+
gridRowSpacing: metrics.gridGap,
|
|
3593
|
+
gridColumnSpacing: metrics.gridGap
|
|
3594
|
+
};
|
|
3595
|
+
for (const [stripeKey, token] of Object.entries(COLOR_VARIABLES)) {
|
|
3596
|
+
const raw = readToken(style, token);
|
|
3597
|
+
if (!raw) continue;
|
|
3598
|
+
const resolved = resolveColor(probe, raw);
|
|
3599
|
+
if (!resolved) continue;
|
|
3600
|
+
variables[stripeKey] = resolved;
|
|
3601
|
+
}
|
|
3602
|
+
for (const [stripeKey, token] of Object.entries(DIRECT_VARIABLES)) {
|
|
3603
|
+
const raw = readToken(style, token);
|
|
3604
|
+
if (!raw) continue;
|
|
3605
|
+
variables[stripeKey] = raw;
|
|
3606
|
+
}
|
|
3607
|
+
const border = (() => {
|
|
3608
|
+
const raw = readToken(style, "--solvapay-border");
|
|
3609
|
+
return raw ? resolveColor(probe, raw) : void 0;
|
|
3610
|
+
})();
|
|
3611
|
+
const accent = variables.colorText;
|
|
3612
|
+
const muted = variables.colorTextSecondary;
|
|
3613
|
+
const danger = variables.colorDanger;
|
|
3614
|
+
const radius = variables.borderRadius;
|
|
3615
|
+
const surface = variables.colorBackground;
|
|
3616
|
+
const fontFamily = variables.fontFamily;
|
|
3617
|
+
probe.remove();
|
|
3618
|
+
const rules = {
|
|
3619
|
+
".Input": {
|
|
3620
|
+
fontSize: metrics.fontSize,
|
|
3621
|
+
lineHeight: metrics.lineHeight,
|
|
3622
|
+
padding: metrics.padding,
|
|
3623
|
+
boxShadow: "none",
|
|
3624
|
+
...fontFamily ? { fontFamily } : {},
|
|
3625
|
+
...border ? { border: `1px solid ${border}` } : {},
|
|
3626
|
+
...radius ? { borderRadius: radius } : {}
|
|
3627
|
+
},
|
|
3628
|
+
".Input:focus": {
|
|
3629
|
+
outline: "none",
|
|
3630
|
+
...accent ? {
|
|
3631
|
+
borderColor: accent,
|
|
3632
|
+
boxShadow: `0 0 0 1px ${accent}`
|
|
3633
|
+
} : {}
|
|
3634
|
+
},
|
|
3635
|
+
".Label": {
|
|
3636
|
+
fontSize: metrics.labelFontSize,
|
|
3637
|
+
fontWeight: "500",
|
|
3638
|
+
marginBottom: metrics.labelMarginBottom,
|
|
3639
|
+
...muted ? { color: muted } : {}
|
|
3640
|
+
},
|
|
3641
|
+
".Error": {
|
|
3642
|
+
fontSize: metrics.errorFontSize,
|
|
3643
|
+
marginTop: metrics.errorMarginTop,
|
|
3644
|
+
...danger ? { color: danger } : {}
|
|
3645
|
+
},
|
|
3646
|
+
".Tab": {
|
|
3647
|
+
...border ? { border: `1px solid ${border}` } : {}
|
|
3648
|
+
},
|
|
3649
|
+
".Tab--selected": {
|
|
3650
|
+
...surface ? { backgroundColor: surface } : {},
|
|
3651
|
+
...border ? { border: `1px solid ${border}` } : {},
|
|
3652
|
+
...accent ? { color: accent } : {}
|
|
3653
|
+
},
|
|
3654
|
+
".AccordionItem": {
|
|
3655
|
+
border: "none",
|
|
3656
|
+
padding: "0"
|
|
3657
|
+
}
|
|
3658
|
+
};
|
|
3659
|
+
return { variables, rules };
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
// src/primitives/useStripeAppearance.ts
|
|
3663
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect6;
|
|
3664
|
+
function useStripeAppearance(root, appearance) {
|
|
3665
|
+
const [themeTick, setThemeTick] = useState8(0);
|
|
3666
|
+
useIsomorphicLayoutEffect(() => {
|
|
3667
|
+
if (appearance !== void 0) return;
|
|
3668
|
+
if (!root) return;
|
|
3669
|
+
const apply = () => setThemeTick((tick) => tick + 1);
|
|
3670
|
+
const media = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : void 0;
|
|
3671
|
+
media?.addEventListener("change", apply);
|
|
3672
|
+
const observer = new MutationObserver(apply);
|
|
3673
|
+
observer.observe(document.documentElement, {
|
|
3674
|
+
attributes: true,
|
|
3675
|
+
attributeFilter: ["style"]
|
|
3676
|
+
});
|
|
3677
|
+
return () => {
|
|
3678
|
+
media?.removeEventListener("change", apply);
|
|
3679
|
+
observer.disconnect();
|
|
3680
|
+
};
|
|
3681
|
+
}, [root, appearance]);
|
|
3682
|
+
return useMemo6(() => {
|
|
3683
|
+
if (appearance === null) return void 0;
|
|
3684
|
+
if (appearance !== void 0) return appearance;
|
|
3685
|
+
if (!root) return void 0;
|
|
3686
|
+
return buildStripeAppearance(root);
|
|
3687
|
+
}, [root, appearance, themeTick]);
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3252
3690
|
// src/utils/processPaymentResult.ts
|
|
3253
3691
|
async function reconcilePayment(input) {
|
|
3254
3692
|
const { paymentIntentId, productRef, planRef, processPayment, refetchPurchase, copy } = input;
|
|
@@ -3321,8 +3759,10 @@ function normalizeOneTimePurchase(input) {
|
|
|
3321
3759
|
}
|
|
3322
3760
|
|
|
3323
3761
|
// src/hooks/useBusinessDetailsAttach.ts
|
|
3324
|
-
import { useCallback as
|
|
3762
|
+
import { useCallback as useCallback9, useEffect as useEffect7, useRef as useRef4, useState as useState9 } from "react";
|
|
3325
3763
|
import {
|
|
3764
|
+
getCustomerAddressFieldErrors,
|
|
3765
|
+
isCustomerAddressComplete,
|
|
3326
3766
|
validateBusinessDetails as validateBusinessDetails2
|
|
3327
3767
|
} from "@solvapay/core";
|
|
3328
3768
|
var defaultBusinessDetails = { isBusiness: false };
|
|
@@ -3334,32 +3774,45 @@ function useBusinessDetailsAttach(options) {
|
|
|
3334
3774
|
onTaxChange,
|
|
3335
3775
|
refreshElements
|
|
3336
3776
|
} = options;
|
|
3337
|
-
const [businessDetails, setBusinessDetailsState] =
|
|
3338
|
-
const [taxBreakdown, setTaxBreakdown] =
|
|
3339
|
-
const [businessDetailsAttached, setBusinessDetailsAttached] =
|
|
3340
|
-
const [businessDetailsAttaching, setBusinessDetailsAttaching] =
|
|
3341
|
-
const [businessDetailsError, setBusinessDetailsError] =
|
|
3342
|
-
const [fieldErrors, setFieldErrors] =
|
|
3777
|
+
const [businessDetails, setBusinessDetailsState] = useState9(defaultBusinessDetails);
|
|
3778
|
+
const [taxBreakdown, setTaxBreakdown] = useState9(null);
|
|
3779
|
+
const [businessDetailsAttached, setBusinessDetailsAttached] = useState9(false);
|
|
3780
|
+
const [businessDetailsAttaching, setBusinessDetailsAttaching] = useState9(false);
|
|
3781
|
+
const [businessDetailsError, setBusinessDetailsError] = useState9(null);
|
|
3782
|
+
const [fieldErrors, setFieldErrors] = useState9({});
|
|
3343
3783
|
const attachRequestIdRef = useRef4(0);
|
|
3344
|
-
const setBusinessDetails =
|
|
3784
|
+
const setBusinessDetails = useCallback9((patch) => {
|
|
3345
3785
|
setBusinessDetailsState((prev) => {
|
|
3346
3786
|
const next = { ...prev, ...patch };
|
|
3347
3787
|
if (patch.isBusiness === false) {
|
|
3348
|
-
return {
|
|
3788
|
+
return {
|
|
3789
|
+
isBusiness: false,
|
|
3790
|
+
...next.customerCountry && { customerCountry: next.customerCountry },
|
|
3791
|
+
...next.customerState && { customerState: next.customerState },
|
|
3792
|
+
...next.customerPostalCode && { customerPostalCode: next.customerPostalCode },
|
|
3793
|
+
...next.customerName && { customerName: next.customerName }
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
if (patch.isBusiness === true && !next.country && next.customerCountry) {
|
|
3797
|
+
return { ...next, country: next.customerCountry };
|
|
3349
3798
|
}
|
|
3350
3799
|
return next;
|
|
3351
3800
|
});
|
|
3352
3801
|
setBusinessDetailsAttached(false);
|
|
3353
3802
|
setBusinessDetailsError(null);
|
|
3354
3803
|
}, []);
|
|
3355
|
-
const runAttach =
|
|
3804
|
+
const runAttach = useCallback9(
|
|
3356
3805
|
async (input) => {
|
|
3357
3806
|
if (!processorPaymentId || !attachBusinessDetails) {
|
|
3358
3807
|
return !attachBusinessDetails;
|
|
3359
3808
|
}
|
|
3809
|
+
const addressErrors = getCustomerAddressFieldErrors(input);
|
|
3360
3810
|
const validation = validateBusinessDetails2(input);
|
|
3361
|
-
if (!validation.success) {
|
|
3362
|
-
setFieldErrors(
|
|
3811
|
+
if (!validation.success || !isCustomerAddressComplete(input)) {
|
|
3812
|
+
setFieldErrors({
|
|
3813
|
+
...mapBusinessFieldErrors(input),
|
|
3814
|
+
...addressErrors
|
|
3815
|
+
});
|
|
3363
3816
|
return false;
|
|
3364
3817
|
}
|
|
3365
3818
|
setFieldErrors({});
|
|
@@ -3394,11 +3847,15 @@ function useBusinessDetailsAttach(options) {
|
|
|
3394
3847
|
},
|
|
3395
3848
|
[processorPaymentId, attachBusinessDetails, customerRef, onTaxChange, refreshElements]
|
|
3396
3849
|
);
|
|
3397
|
-
|
|
3850
|
+
useEffect7(() => {
|
|
3398
3851
|
if (!processorPaymentId || !attachBusinessDetails) return;
|
|
3399
3852
|
const validation = validateBusinessDetails2(businessDetails);
|
|
3400
|
-
if (!validation.success) {
|
|
3401
|
-
|
|
3853
|
+
if (!validation.success || !isCustomerAddressComplete(businessDetails)) {
|
|
3854
|
+
const countrySelected = !!(businessDetails.customerCountry?.trim() || businessDetails.isBusiness && businessDetails.country?.trim());
|
|
3855
|
+
setFieldErrors({
|
|
3856
|
+
...mapBusinessFieldErrors(businessDetails),
|
|
3857
|
+
...countrySelected ? getCustomerAddressFieldErrors(businessDetails) : {}
|
|
3858
|
+
});
|
|
3402
3859
|
setBusinessDetailsAttached(false);
|
|
3403
3860
|
return;
|
|
3404
3861
|
}
|
|
@@ -3423,7 +3880,8 @@ function useBusinessDetailsAttach(options) {
|
|
|
3423
3880
|
}
|
|
3424
3881
|
|
|
3425
3882
|
// src/primitives/PaymentForm.tsx
|
|
3426
|
-
import {
|
|
3883
|
+
import { isCustomerAddressComplete as isCustomerAddressComplete2, resolveBuyerCountry as resolveBuyerCountry2 } from "@solvapay/core";
|
|
3884
|
+
import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3427
3885
|
function toSubmitVariant(variant) {
|
|
3428
3886
|
switch (variant) {
|
|
3429
3887
|
case "freeTier":
|
|
@@ -3451,9 +3909,10 @@ var Root2 = forwardRef5(
|
|
|
3451
3909
|
buttonClassName,
|
|
3452
3910
|
prefillCustomer,
|
|
3453
3911
|
requireTermsAcceptance = false,
|
|
3912
|
+
appearance,
|
|
3454
3913
|
children
|
|
3455
3914
|
} = props;
|
|
3456
|
-
const solva =
|
|
3915
|
+
const solva = useContext9(SolvaPayContext);
|
|
3457
3916
|
if (!solva) throw new MissingProviderError("PaymentForm");
|
|
3458
3917
|
const { attachBusinessDetails, customerRef } = solva;
|
|
3459
3918
|
const copy = useCopy();
|
|
@@ -3481,7 +3940,7 @@ var Root2 = forwardRef5(
|
|
|
3481
3940
|
});
|
|
3482
3941
|
const hasInitializedRef = useRef5(false);
|
|
3483
3942
|
const hasPlanOrProduct = !!(effectivePlanRef || effectiveProductRef);
|
|
3484
|
-
|
|
3943
|
+
useEffect8(() => {
|
|
3485
3944
|
if (isFreePlan) return;
|
|
3486
3945
|
if (!hasInitializedRef.current && hasPlanOrProduct && !checkoutLoading && !checkoutError && !clientSecret) {
|
|
3487
3946
|
hasInitializedRef.current = true;
|
|
@@ -3495,111 +3954,85 @@ var Root2 = forwardRef5(
|
|
|
3495
3954
|
}
|
|
3496
3955
|
}, [hasPlanOrProduct, checkoutLoading, checkoutError, clientSecret, startCheckout, isFreePlan]);
|
|
3497
3956
|
const finalReturnUrl = returnUrl || (typeof window !== "undefined" ? window.location.href : "/");
|
|
3498
|
-
const
|
|
3957
|
+
const [rootEl, setRootEl] = useState10(null);
|
|
3958
|
+
const attachRoot = useCallback10((node) => {
|
|
3959
|
+
if (!node) return;
|
|
3960
|
+
setRootEl((prev) => prev === node ? prev : node);
|
|
3961
|
+
}, []);
|
|
3962
|
+
const sectionRef = composeRefs(forwardedRef, attachRoot);
|
|
3963
|
+
const resolvedAppearance = useStripeAppearance(rootEl, appearance);
|
|
3964
|
+
const elementsOptions = useMemo7(() => {
|
|
3499
3965
|
if (!clientSecret) return void 0;
|
|
3500
|
-
return {
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
" ",
|
|
3526
|
-
checkoutError.message || copy.errors.unknownError
|
|
3527
|
-
] })
|
|
3528
|
-
}
|
|
3529
|
-
);
|
|
3530
|
-
}
|
|
3531
|
-
if (isFreePlan && resolvedPlan) {
|
|
3532
|
-
return /* @__PURE__ */ jsx12(
|
|
3533
|
-
"section",
|
|
3534
|
-
{
|
|
3535
|
-
ref: forwardedRef,
|
|
3536
|
-
className,
|
|
3537
|
-
"data-solvapay-payment-form": "",
|
|
3538
|
-
"data-state": "ready",
|
|
3539
|
-
"data-variant": "free",
|
|
3540
|
-
children: /* @__PURE__ */ jsx12(
|
|
3541
|
-
FreeInner,
|
|
3542
|
-
{
|
|
3543
|
-
planRef: effectivePlanRef,
|
|
3544
|
-
productRef: effectiveProductRef,
|
|
3545
|
-
plan: resolvedPlan,
|
|
3546
|
-
resolvedPlanRef,
|
|
3547
|
-
requireTermsAcceptance,
|
|
3548
|
-
submitButtonText,
|
|
3549
|
-
buttonClassName,
|
|
3550
|
-
onFreePlan,
|
|
3551
|
-
onResult,
|
|
3552
|
-
onError,
|
|
3553
|
-
children
|
|
3554
|
-
}
|
|
3555
|
-
)
|
|
3556
|
-
}
|
|
3557
|
-
);
|
|
3558
|
-
}
|
|
3559
|
-
if (shouldRenderElements && elementsOptions && clientSecret) {
|
|
3560
|
-
const resolvedClientSecret = clientSecret;
|
|
3561
|
-
return /* @__PURE__ */ jsx12(
|
|
3562
|
-
"section",
|
|
3563
|
-
{
|
|
3564
|
-
ref: forwardedRef,
|
|
3565
|
-
className,
|
|
3566
|
-
"data-solvapay-payment-form": "",
|
|
3567
|
-
"data-state": "ready",
|
|
3568
|
-
"data-variant": "paid",
|
|
3569
|
-
children: /* @__PURE__ */ jsx12(Elements, { stripe: stripePromise, options: elementsOptions, children: /* @__PURE__ */ jsx12(
|
|
3570
|
-
PaidInner,
|
|
3571
|
-
{
|
|
3572
|
-
planRef: effectivePlanRef,
|
|
3573
|
-
productRef: effectiveProductRef,
|
|
3574
|
-
prefillCustomer,
|
|
3575
|
-
resolvedPlanRef,
|
|
3576
|
-
plan: resolvedPlan ?? null,
|
|
3577
|
-
clientSecret: resolvedClientSecret,
|
|
3578
|
-
processorPaymentId,
|
|
3579
|
-
returnUrl: finalReturnUrl,
|
|
3580
|
-
submitButtonText,
|
|
3581
|
-
buttonClassName,
|
|
3582
|
-
requireTermsAcceptance,
|
|
3583
|
-
onSuccess,
|
|
3584
|
-
onResult,
|
|
3585
|
-
onError,
|
|
3586
|
-
onTaxChange: props.onTaxChange,
|
|
3587
|
-
attachBusinessDetails,
|
|
3588
|
-
customerRef,
|
|
3589
|
-
children
|
|
3590
|
-
}
|
|
3591
|
-
) }, resolvedClientSecret)
|
|
3592
|
-
}
|
|
3593
|
-
);
|
|
3594
|
-
}
|
|
3595
|
-
return /* @__PURE__ */ jsx12(
|
|
3966
|
+
return {
|
|
3967
|
+
clientSecret,
|
|
3968
|
+
locale: toStripeElementLocale(locale),
|
|
3969
|
+
...resolvedAppearance ? { appearance: resolvedAppearance } : {}
|
|
3970
|
+
};
|
|
3971
|
+
}, [clientSecret, locale, resolvedAppearance]);
|
|
3972
|
+
const appearanceReady = appearance !== void 0 || rootEl !== null;
|
|
3973
|
+
const shouldRenderElements = !!(stripePromise && clientSecret && appearanceReady);
|
|
3974
|
+
const dataState = !hasPlanOrProduct || checkoutError ? "error" : isFreePlan && resolvedPlan ? "ready" : shouldRenderElements ? "ready" : "loading";
|
|
3975
|
+
const dataVariant = isFreePlan && resolvedPlan ? "free" : shouldRenderElements ? "paid" : void 0;
|
|
3976
|
+
const pending = /* @__PURE__ */ jsx13(
|
|
3977
|
+
PendingInner,
|
|
3978
|
+
{
|
|
3979
|
+
planRef: effectivePlanRef,
|
|
3980
|
+
productRef: effectiveProductRef,
|
|
3981
|
+
resolvedPlanRef,
|
|
3982
|
+
plan: resolvedPlan ?? null,
|
|
3983
|
+
returnUrl: finalReturnUrl,
|
|
3984
|
+
submitButtonText,
|
|
3985
|
+
buttonClassName,
|
|
3986
|
+
error: checkoutError ? `${copy.errors.paymentInitFailed} ${checkoutError.message || copy.errors.unknownError}` : null,
|
|
3987
|
+
children
|
|
3988
|
+
}
|
|
3989
|
+
);
|
|
3990
|
+
return /* @__PURE__ */ jsx13(
|
|
3596
3991
|
"section",
|
|
3597
3992
|
{
|
|
3598
|
-
ref:
|
|
3993
|
+
ref: sectionRef,
|
|
3599
3994
|
className,
|
|
3600
3995
|
"data-solvapay-payment-form": "",
|
|
3601
|
-
"data-state":
|
|
3602
|
-
|
|
3996
|
+
"data-state": dataState,
|
|
3997
|
+
...dataVariant ? { "data-variant": dataVariant } : {},
|
|
3998
|
+
children: !hasPlanOrProduct ? /* @__PURE__ */ jsx13("p", { role: "alert", "data-solvapay-payment-form-error": "", children: copy.errors.configMissingPlanOrProduct }) : checkoutError ? pending : isFreePlan && resolvedPlan ? /* @__PURE__ */ jsx13(
|
|
3999
|
+
FreeInner,
|
|
4000
|
+
{
|
|
4001
|
+
planRef: effectivePlanRef,
|
|
4002
|
+
productRef: effectiveProductRef,
|
|
4003
|
+
plan: resolvedPlan,
|
|
4004
|
+
resolvedPlanRef,
|
|
4005
|
+
requireTermsAcceptance,
|
|
4006
|
+
submitButtonText,
|
|
4007
|
+
buttonClassName,
|
|
4008
|
+
onFreePlan,
|
|
4009
|
+
onResult,
|
|
4010
|
+
onError,
|
|
4011
|
+
children
|
|
4012
|
+
}
|
|
4013
|
+
) : shouldRenderElements && elementsOptions && clientSecret ? /* @__PURE__ */ jsx13(Elements, { stripe: stripePromise, options: elementsOptions, children: /* @__PURE__ */ jsx13(
|
|
4014
|
+
PaidInner,
|
|
4015
|
+
{
|
|
4016
|
+
planRef: effectivePlanRef,
|
|
4017
|
+
productRef: effectiveProductRef,
|
|
4018
|
+
prefillCustomer,
|
|
4019
|
+
resolvedPlanRef,
|
|
4020
|
+
plan: resolvedPlan ?? null,
|
|
4021
|
+
clientSecret,
|
|
4022
|
+
processorPaymentId,
|
|
4023
|
+
returnUrl: finalReturnUrl,
|
|
4024
|
+
submitButtonText,
|
|
4025
|
+
buttonClassName,
|
|
4026
|
+
requireTermsAcceptance,
|
|
4027
|
+
onSuccess,
|
|
4028
|
+
onResult,
|
|
4029
|
+
onError,
|
|
4030
|
+
onTaxChange: props.onTaxChange,
|
|
4031
|
+
attachBusinessDetails,
|
|
4032
|
+
customerRef,
|
|
4033
|
+
children
|
|
4034
|
+
}
|
|
4035
|
+
) }, clientSecret) : pending
|
|
3603
4036
|
}
|
|
3604
4037
|
);
|
|
3605
4038
|
}
|
|
@@ -3625,12 +4058,14 @@ var PaidInner = ({
|
|
|
3625
4058
|
children
|
|
3626
4059
|
}) => {
|
|
3627
4060
|
const stripe = useStripe();
|
|
4061
|
+
const stripeAvailable = !!stripe;
|
|
4062
|
+
const stripeRef = useRef5(stripe);
|
|
3628
4063
|
const elements = useElements();
|
|
3629
4064
|
const copy = useCopy();
|
|
3630
4065
|
const customer = useCustomer();
|
|
3631
4066
|
const { processPayment, upsertPurchase } = useSolvaPay();
|
|
3632
4067
|
const { refetch } = usePurchase();
|
|
3633
|
-
const refreshElements =
|
|
4068
|
+
const refreshElements = useCallback10(async () => {
|
|
3634
4069
|
if (elements) {
|
|
3635
4070
|
await elements.fetchUpdates();
|
|
3636
4071
|
}
|
|
@@ -3652,17 +4087,23 @@ var PaidInner = ({
|
|
|
3652
4087
|
onTaxChange,
|
|
3653
4088
|
refreshElements
|
|
3654
4089
|
});
|
|
3655
|
-
const [elementKind, setElementKind] =
|
|
4090
|
+
const [elementKind, setElementKind] = useState10(
|
|
3656
4091
|
children ? null : "payment-element"
|
|
3657
4092
|
);
|
|
3658
|
-
const [customerName, setCustomerName] =
|
|
3659
|
-
const [paymentInputComplete, setPaymentInputComplete] =
|
|
3660
|
-
const [termsAccepted, setTermsAccepted] =
|
|
3661
|
-
const [isProcessing, setIsProcessing] =
|
|
3662
|
-
const [error, setError] =
|
|
4093
|
+
const [customerName, setCustomerName] = useState10("");
|
|
4094
|
+
const [paymentInputComplete, setPaymentInputComplete] = useState10(false);
|
|
4095
|
+
const [termsAccepted, setTermsAccepted] = useState10(false);
|
|
4096
|
+
const [isProcessing, setIsProcessing] = useState10(false);
|
|
4097
|
+
const [error, setError] = useState10(null);
|
|
3663
4098
|
const returnResumeStarted = useRef5(false);
|
|
3664
|
-
|
|
3665
|
-
|
|
4099
|
+
useEffect8(() => {
|
|
4100
|
+
stripeRef.current = stripe;
|
|
4101
|
+
});
|
|
4102
|
+
useEffect8(() => {
|
|
4103
|
+
const stripeApi = stripeRef.current;
|
|
4104
|
+
if (!stripeAvailable || !stripeApi || returnResumeStarted.current || typeof window === "undefined") {
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
3666
4107
|
const returnClientSecret = readPaymentIntentClientSecret(window.location.search);
|
|
3667
4108
|
if (!returnClientSecret) return;
|
|
3668
4109
|
returnResumeStarted.current = true;
|
|
@@ -3670,7 +4111,7 @@ var PaidInner = ({
|
|
|
3670
4111
|
void (async () => {
|
|
3671
4112
|
setIsProcessing(true);
|
|
3672
4113
|
setError(null);
|
|
3673
|
-
const retrieved = await
|
|
4114
|
+
const retrieved = await stripeApi.retrievePaymentIntent(returnClientSecret);
|
|
3674
4115
|
if (cancelled) return;
|
|
3675
4116
|
stripPaymentIntentParams();
|
|
3676
4117
|
if (retrieved.error || !retrieved.paymentIntent) {
|
|
@@ -3680,7 +4121,7 @@ var PaidInner = ({
|
|
|
3680
4121
|
}
|
|
3681
4122
|
let paymentIntent = retrieved.paymentIntent;
|
|
3682
4123
|
if (paymentIntent.status === "requires_action") {
|
|
3683
|
-
const actionResult = await
|
|
4124
|
+
const actionResult = await stripeApi.handleNextAction({ clientSecret: returnClientSecret });
|
|
3684
4125
|
if (cancelled) return;
|
|
3685
4126
|
if (actionResult.error || !actionResult.paymentIntent) {
|
|
3686
4127
|
setError(copy.errors.paymentRequires3ds);
|
|
@@ -3735,7 +4176,7 @@ var PaidInner = ({
|
|
|
3735
4176
|
cancelled = true;
|
|
3736
4177
|
};
|
|
3737
4178
|
}, [
|
|
3738
|
-
|
|
4179
|
+
stripeAvailable,
|
|
3739
4180
|
copy,
|
|
3740
4181
|
productRef,
|
|
3741
4182
|
planRef,
|
|
@@ -3748,8 +4189,8 @@ var PaidInner = ({
|
|
|
3748
4189
|
onError
|
|
3749
4190
|
]);
|
|
3750
4191
|
const isReady = !!(stripe && elements);
|
|
3751
|
-
const canSubmit = isReady && !!clientSecret && !!elementKind && paymentInputComplete && (!requireTermsAcceptance || termsAccepted) && (!requiresBusinessAttach || businessDetailsAttached) && !businessDetailsAttaching && !isProcessing;
|
|
3752
|
-
const submit =
|
|
4192
|
+
const canSubmit = isReady && !!clientSecret && !!elementKind && paymentInputComplete && (!requireTermsAcceptance || termsAccepted) && (!requiresBusinessAttach || businessDetailsAttached) && isCustomerAddressComplete2(businessDetails) && !businessDetailsAttaching && !isProcessing;
|
|
4193
|
+
const submit = useCallback10(async () => {
|
|
3753
4194
|
if (!stripe || !elements || !clientSecret || !elementKind) {
|
|
3754
4195
|
const msg = !stripe || !elements ? copy.errors.stripeUnavailable : copy.errors.paymentIntentUnavailable;
|
|
3755
4196
|
setError(msg);
|
|
@@ -3776,10 +4217,13 @@ var PaidInner = ({
|
|
|
3776
4217
|
clientSecret,
|
|
3777
4218
|
mode: elementKind === "card-element" ? "card-element" : "payment-element",
|
|
3778
4219
|
returnUrl,
|
|
3779
|
-
billingDetails: {
|
|
3780
|
-
|
|
3781
|
-
email: customer.email ?? prefillCustomer?.email
|
|
3782
|
-
|
|
4220
|
+
billingDetails: buildConfirmBillingDetails({
|
|
4221
|
+
name: customerName.trim() || customer.name,
|
|
4222
|
+
email: customer.email ?? prefillCustomer?.email,
|
|
4223
|
+
country: resolveBuyerCountry2(businessDetails),
|
|
4224
|
+
state: businessDetails.customerState,
|
|
4225
|
+
postalCode: businessDetails.customerPostalCode
|
|
4226
|
+
}),
|
|
3783
4227
|
copy
|
|
3784
4228
|
});
|
|
3785
4229
|
if (result.status === "error") {
|
|
@@ -3853,7 +4297,7 @@ var PaidInner = ({
|
|
|
3853
4297
|
businessDetailsError
|
|
3854
4298
|
]);
|
|
3855
4299
|
const effectiveError = error ?? businessDetailsError;
|
|
3856
|
-
const contextValue =
|
|
4300
|
+
const contextValue = useMemo7(
|
|
3857
4301
|
() => ({
|
|
3858
4302
|
planRef,
|
|
3859
4303
|
productRef,
|
|
@@ -3922,7 +4366,7 @@ var PaidInner = ({
|
|
|
3922
4366
|
submit
|
|
3923
4367
|
]
|
|
3924
4368
|
);
|
|
3925
|
-
return /* @__PURE__ */
|
|
4369
|
+
return /* @__PURE__ */ jsx13(PaymentFormProvider, { value: contextValue, children });
|
|
3926
4370
|
};
|
|
3927
4371
|
var FreeInner = ({
|
|
3928
4372
|
planRef,
|
|
@@ -3940,10 +4384,10 @@ var FreeInner = ({
|
|
|
3940
4384
|
const copy = useCopy();
|
|
3941
4385
|
const { refetch } = usePurchase();
|
|
3942
4386
|
const { activate, state, error: activationError, result: activationResult } = useActivation();
|
|
3943
|
-
const [termsAccepted, setTermsAccepted] =
|
|
3944
|
-
const [localError, setLocalError] =
|
|
4387
|
+
const [termsAccepted, setTermsAccepted] = useState10(false);
|
|
4388
|
+
const [localError, setLocalError] = useState10(void 0);
|
|
3945
4389
|
const resultFiredRef = useRef5(false);
|
|
3946
|
-
|
|
4390
|
+
useEffect8(() => {
|
|
3947
4391
|
if (state === "activated" && activationResult && !resultFiredRef.current) {
|
|
3948
4392
|
resultFiredRef.current = true;
|
|
3949
4393
|
const res = { kind: "activated", result: activationResult };
|
|
@@ -3955,7 +4399,7 @@ var FreeInner = ({
|
|
|
3955
4399
|
}, [state, activationResult, onResult, refetch]);
|
|
3956
4400
|
const isProcessing = state === "activating";
|
|
3957
4401
|
const canSubmit = !isProcessing && (!requireTermsAcceptance || termsAccepted) && !!productRef;
|
|
3958
|
-
const submit =
|
|
4402
|
+
const submit = useCallback10(async () => {
|
|
3959
4403
|
if (!productRef) {
|
|
3960
4404
|
const msg = copy.errors.configMissingPlanOrProduct;
|
|
3961
4405
|
setLocalError(msg);
|
|
@@ -3979,7 +4423,7 @@ var FreeInner = ({
|
|
|
3979
4423
|
}
|
|
3980
4424
|
}, [productRef, plan, onFreePlan, activate, onResult, onError, copy]);
|
|
3981
4425
|
const error = localError ?? activationError;
|
|
3982
|
-
const contextValue =
|
|
4426
|
+
const contextValue = useMemo7(
|
|
3983
4427
|
() => ({
|
|
3984
4428
|
planRef,
|
|
3985
4429
|
productRef,
|
|
@@ -4034,11 +4478,77 @@ var FreeInner = ({
|
|
|
4034
4478
|
submit
|
|
4035
4479
|
]
|
|
4036
4480
|
);
|
|
4037
|
-
return /* @__PURE__ */
|
|
4481
|
+
return /* @__PURE__ */ jsx13(PaymentFormProvider, { value: contextValue, children });
|
|
4482
|
+
};
|
|
4483
|
+
var PendingInner = ({
|
|
4484
|
+
planRef,
|
|
4485
|
+
productRef,
|
|
4486
|
+
resolvedPlanRef,
|
|
4487
|
+
plan,
|
|
4488
|
+
returnUrl,
|
|
4489
|
+
submitButtonText,
|
|
4490
|
+
buttonClassName,
|
|
4491
|
+
error,
|
|
4492
|
+
children
|
|
4493
|
+
}) => {
|
|
4494
|
+
const contextValue = useMemo7(
|
|
4495
|
+
() => ({
|
|
4496
|
+
planRef,
|
|
4497
|
+
productRef,
|
|
4498
|
+
prefillCustomer: void 0,
|
|
4499
|
+
resolvedPlanRef,
|
|
4500
|
+
plan,
|
|
4501
|
+
clientSecret: null,
|
|
4502
|
+
processorPaymentId: null,
|
|
4503
|
+
stripe: null,
|
|
4504
|
+
elements: null,
|
|
4505
|
+
isProcessing: false,
|
|
4506
|
+
isReady: false,
|
|
4507
|
+
paymentInputComplete: false,
|
|
4508
|
+
termsAccepted: false,
|
|
4509
|
+
requireTermsAcceptance: false,
|
|
4510
|
+
canSubmit: false,
|
|
4511
|
+
error,
|
|
4512
|
+
elementKind: null,
|
|
4513
|
+
returnUrl,
|
|
4514
|
+
submitButtonText,
|
|
4515
|
+
buttonClassName,
|
|
4516
|
+
customerName: "",
|
|
4517
|
+
setCustomerName: () => {
|
|
4518
|
+
},
|
|
4519
|
+
businessDetails: defaultBusinessDetails,
|
|
4520
|
+
taxBreakdown: null,
|
|
4521
|
+
businessDetailsAttached: false,
|
|
4522
|
+
businessDetailsAttaching: false,
|
|
4523
|
+
businessDetailsError: null,
|
|
4524
|
+
fieldErrors: {},
|
|
4525
|
+
setBusinessDetails: () => {
|
|
4526
|
+
},
|
|
4527
|
+
setElementKind: () => {
|
|
4528
|
+
},
|
|
4529
|
+
setPaymentInputComplete: () => {
|
|
4530
|
+
},
|
|
4531
|
+
setTermsAccepted: () => {
|
|
4532
|
+
},
|
|
4533
|
+
submit: async () => {
|
|
4534
|
+
}
|
|
4535
|
+
}),
|
|
4536
|
+
[
|
|
4537
|
+
planRef,
|
|
4538
|
+
productRef,
|
|
4539
|
+
resolvedPlanRef,
|
|
4540
|
+
plan,
|
|
4541
|
+
returnUrl,
|
|
4542
|
+
submitButtonText,
|
|
4543
|
+
buttonClassName,
|
|
4544
|
+
error
|
|
4545
|
+
]
|
|
4546
|
+
);
|
|
4547
|
+
return /* @__PURE__ */ jsx13(PaymentFormProvider, { value: contextValue, children });
|
|
4038
4548
|
};
|
|
4039
4549
|
var Summary = (props) => {
|
|
4040
4550
|
const ctx = usePaymentForm();
|
|
4041
|
-
return /* @__PURE__ */
|
|
4551
|
+
return /* @__PURE__ */ jsx13(
|
|
4042
4552
|
CheckoutSummary2,
|
|
4043
4553
|
{
|
|
4044
4554
|
...props,
|
|
@@ -4051,7 +4561,7 @@ var Summary = (props) => {
|
|
|
4051
4561
|
};
|
|
4052
4562
|
var MandateTextPrimitive = (props) => {
|
|
4053
4563
|
const ctx = usePaymentForm();
|
|
4054
|
-
return /* @__PURE__ */
|
|
4564
|
+
return /* @__PURE__ */ jsx13(
|
|
4055
4565
|
MandateText,
|
|
4056
4566
|
{
|
|
4057
4567
|
...props,
|
|
@@ -4068,14 +4578,14 @@ var CustomerFields = forwardRef5(
|
|
|
4068
4578
|
const email = customer.email ?? prefillCustomer?.email;
|
|
4069
4579
|
if (!email) return null;
|
|
4070
4580
|
const Comp = asChild ? Slot : "section";
|
|
4071
|
-
return /* @__PURE__ */
|
|
4581
|
+
return /* @__PURE__ */ jsx13(Comp, { ref, "data-solvapay-payment-form-customer-fields": "", ...rest, children: children ?? /* @__PURE__ */ jsxs6(Fragment6, { children: [
|
|
4072
4582
|
email && /* @__PURE__ */ jsxs6("dl", { "data-solvapay-payment-form-customer-email": "", children: [
|
|
4073
|
-
/* @__PURE__ */
|
|
4074
|
-
/* @__PURE__ */
|
|
4583
|
+
/* @__PURE__ */ jsx13("dt", { children: copy.customer.emailLabel }),
|
|
4584
|
+
/* @__PURE__ */ jsx13("dd", { children: email })
|
|
4075
4585
|
] }),
|
|
4076
4586
|
/* @__PURE__ */ jsxs6("dl", { "data-solvapay-payment-form-customer-name": "", children: [
|
|
4077
|
-
/* @__PURE__ */
|
|
4078
|
-
/* @__PURE__ */
|
|
4587
|
+
/* @__PURE__ */ jsx13("dt", { children: copy.customer.nameLabel }),
|
|
4588
|
+
/* @__PURE__ */ jsx13("dd", { children: /* @__PURE__ */ jsx13(
|
|
4079
4589
|
"input",
|
|
4080
4590
|
{
|
|
4081
4591
|
type: "text",
|
|
@@ -4098,14 +4608,14 @@ var CustomerFields = forwardRef5(
|
|
|
4098
4608
|
var PaymentElementSlot = ({ options }) => {
|
|
4099
4609
|
const { setElementKind, setPaymentInputComplete, isReady, stripe, elements } = usePaymentForm();
|
|
4100
4610
|
const locale = useLocale();
|
|
4101
|
-
|
|
4611
|
+
useEffect8(() => {
|
|
4102
4612
|
if (stripe && elements) setElementKind("payment-element");
|
|
4103
4613
|
}, [setElementKind, stripe, elements]);
|
|
4104
4614
|
if (!stripe || !elements) return null;
|
|
4105
4615
|
if (!isReady) {
|
|
4106
|
-
return /* @__PURE__ */
|
|
4616
|
+
return /* @__PURE__ */ jsx13("output", { "data-solvapay-payment-form-loading": "", children: /* @__PURE__ */ jsx13(Spinner, { size: "sm" }) });
|
|
4107
4617
|
}
|
|
4108
|
-
return /* @__PURE__ */
|
|
4618
|
+
return /* @__PURE__ */ jsx13("section", { "data-solvapay-payment-form-payment-element": "", children: /* @__PURE__ */ jsx13(
|
|
4109
4619
|
StripePaymentElement,
|
|
4110
4620
|
{
|
|
4111
4621
|
options: withPaymentElementDefaults(options),
|
|
@@ -4116,14 +4626,14 @@ var PaymentElementSlot = ({ options }) => {
|
|
|
4116
4626
|
};
|
|
4117
4627
|
var CardElementSlot = ({ options }) => {
|
|
4118
4628
|
const { setElementKind, setPaymentInputComplete, isReady, stripe, elements } = usePaymentForm();
|
|
4119
|
-
|
|
4629
|
+
useEffect8(() => {
|
|
4120
4630
|
if (stripe && elements) setElementKind("card-element");
|
|
4121
4631
|
}, [setElementKind, stripe, elements]);
|
|
4122
4632
|
if (!stripe || !elements) return null;
|
|
4123
4633
|
if (!isReady) {
|
|
4124
|
-
return /* @__PURE__ */
|
|
4634
|
+
return /* @__PURE__ */ jsx13("output", { "data-solvapay-payment-form-loading": "", children: /* @__PURE__ */ jsx13(Spinner, { size: "sm" }) });
|
|
4125
4635
|
}
|
|
4126
|
-
return /* @__PURE__ */
|
|
4636
|
+
return /* @__PURE__ */ jsx13("section", { "data-solvapay-payment-form-card-element": "", children: /* @__PURE__ */ jsx13(StripeCardElement, { options, onChange: (e) => setPaymentInputComplete(e.complete) }) });
|
|
4127
4637
|
};
|
|
4128
4638
|
var TermsCheckbox = forwardRef5(
|
|
4129
4639
|
function PaymentFormTermsCheckbox({ asChild, label, children, ...rest }, ref) {
|
|
@@ -4131,10 +4641,10 @@ var TermsCheckbox = forwardRef5(
|
|
|
4131
4641
|
const copy = useCopy();
|
|
4132
4642
|
const id = "solvapay-terms-checkbox";
|
|
4133
4643
|
if (asChild) {
|
|
4134
|
-
return /* @__PURE__ */
|
|
4644
|
+
return /* @__PURE__ */ jsx13(Slot, { ref, "data-solvapay-payment-form-terms": "", ...rest, children });
|
|
4135
4645
|
}
|
|
4136
4646
|
return /* @__PURE__ */ jsxs6("label", { ref, htmlFor: id, "data-solvapay-payment-form-terms": "", ...rest, children: [
|
|
4137
|
-
/* @__PURE__ */
|
|
4647
|
+
/* @__PURE__ */ jsx13(
|
|
4138
4648
|
"input",
|
|
4139
4649
|
{
|
|
4140
4650
|
id,
|
|
@@ -4143,7 +4653,7 @@ var TermsCheckbox = forwardRef5(
|
|
|
4143
4653
|
onChange: (e) => setTermsAccepted(e.target.checked)
|
|
4144
4654
|
}
|
|
4145
4655
|
),
|
|
4146
|
-
/* @__PURE__ */
|
|
4656
|
+
/* @__PURE__ */ jsx13("span", { children: label ?? copy.terms.checkboxLabel })
|
|
4147
4657
|
] });
|
|
4148
4658
|
}
|
|
4149
4659
|
);
|
|
@@ -4177,8 +4687,8 @@ var SubmitButton = forwardRef5(
|
|
|
4177
4687
|
override: typeof children === "string" ? children : ctx.submitButtonText
|
|
4178
4688
|
});
|
|
4179
4689
|
const processingContent = /* @__PURE__ */ jsxs6(Fragment6, { children: [
|
|
4180
|
-
/* @__PURE__ */
|
|
4181
|
-
/* @__PURE__ */
|
|
4690
|
+
/* @__PURE__ */ jsx13(Spinner, { size: "sm" }),
|
|
4691
|
+
/* @__PURE__ */ jsx13("span", { children: copy.cta.processing })
|
|
4182
4692
|
] });
|
|
4183
4693
|
const buttonProps = {
|
|
4184
4694
|
"data-solvapay-payment-form-submit": "",
|
|
@@ -4196,30 +4706,30 @@ var SubmitButton = forwardRef5(
|
|
|
4196
4706
|
...rest
|
|
4197
4707
|
};
|
|
4198
4708
|
if (asChild) {
|
|
4199
|
-
const slotChild = ctx.isProcessing &&
|
|
4709
|
+
const slotChild = ctx.isProcessing && React11.isValidElement(children) ? React11.cloneElement(
|
|
4200
4710
|
children,
|
|
4201
4711
|
void 0,
|
|
4202
4712
|
processingContent
|
|
4203
4713
|
) : children;
|
|
4204
|
-
return /* @__PURE__ */
|
|
4714
|
+
return /* @__PURE__ */ jsx13(Slot, { ref, ...buttonProps, children: slotChild });
|
|
4205
4715
|
}
|
|
4206
4716
|
const content = ctx.isProcessing ? processingContent : children && typeof children !== "string" ? children : label;
|
|
4207
|
-
return /* @__PURE__ */
|
|
4717
|
+
return /* @__PURE__ */ jsx13("button", { ref, type: "submit", ...buttonProps, children: content });
|
|
4208
4718
|
}
|
|
4209
4719
|
);
|
|
4210
4720
|
var Loading = forwardRef5(function PaymentFormLoading({ asChild, children, ...rest }, ref) {
|
|
4211
4721
|
const ctx = usePaymentForm();
|
|
4212
4722
|
if (ctx.isReady && ctx.clientSecret) return null;
|
|
4213
4723
|
if (asChild) {
|
|
4214
|
-
return /* @__PURE__ */
|
|
4724
|
+
return /* @__PURE__ */ jsx13(Slot, { ref, "data-solvapay-payment-form-loading": "", ...rest, children: children ?? /* @__PURE__ */ jsx13(Spinner, { size: "sm" }) });
|
|
4215
4725
|
}
|
|
4216
|
-
return /* @__PURE__ */
|
|
4726
|
+
return /* @__PURE__ */ jsx13("output", { ref, "data-solvapay-payment-form-loading": "", ...rest, children: children ?? /* @__PURE__ */ jsx13(Spinner, { size: "sm" }) });
|
|
4217
4727
|
});
|
|
4218
4728
|
var ErrorSlot = forwardRef5(function PaymentFormError({ asChild, children, ...rest }, ref) {
|
|
4219
4729
|
const ctx = usePaymentForm();
|
|
4220
4730
|
if (!ctx.error) return null;
|
|
4221
4731
|
if (asChild) {
|
|
4222
|
-
return /* @__PURE__ */
|
|
4732
|
+
return /* @__PURE__ */ jsx13(
|
|
4223
4733
|
Slot,
|
|
4224
4734
|
{
|
|
4225
4735
|
ref,
|
|
@@ -4232,7 +4742,7 @@ var ErrorSlot = forwardRef5(function PaymentFormError({ asChild, children, ...re
|
|
|
4232
4742
|
}
|
|
4233
4743
|
);
|
|
4234
4744
|
}
|
|
4235
|
-
return /* @__PURE__ */
|
|
4745
|
+
return /* @__PURE__ */ jsx13(
|
|
4236
4746
|
"p",
|
|
4237
4747
|
{
|
|
4238
4748
|
ref,
|
|
@@ -4295,7 +4805,7 @@ var PaymentForm = {
|
|
|
4295
4805
|
};
|
|
4296
4806
|
|
|
4297
4807
|
// src/hooks/useTopupAmountSelector.ts
|
|
4298
|
-
import { useState as
|
|
4808
|
+
import { useState as useState11, useCallback as useCallback11, useMemo as useMemo8 } from "react";
|
|
4299
4809
|
function getQuickAmounts(currency) {
|
|
4300
4810
|
switch (currency.toUpperCase()) {
|
|
4301
4811
|
case "SEK":
|
|
@@ -4315,7 +4825,11 @@ function getQuickAmounts(currency) {
|
|
|
4315
4825
|
}
|
|
4316
4826
|
function getCurrencySymbol(currency) {
|
|
4317
4827
|
try {
|
|
4318
|
-
const parts = new Intl.NumberFormat("en", {
|
|
4828
|
+
const parts = new Intl.NumberFormat("en", {
|
|
4829
|
+
style: "currency",
|
|
4830
|
+
currency,
|
|
4831
|
+
currencyDisplay: "narrowSymbol"
|
|
4832
|
+
}).formatToParts(0);
|
|
4319
4833
|
const sym = parts.find((p) => p.type === "currency");
|
|
4320
4834
|
return sym?.value || currency;
|
|
4321
4835
|
} catch {
|
|
@@ -4327,19 +4841,19 @@ var DEFAULT_MAX = 1e5;
|
|
|
4327
4841
|
function useTopupAmountSelector(options) {
|
|
4328
4842
|
const { currency, minAmount = DEFAULT_MIN, maxAmount = DEFAULT_MAX } = options;
|
|
4329
4843
|
const copy = useCopy();
|
|
4330
|
-
const [selectedAmount, setSelectedAmount] =
|
|
4331
|
-
const [customAmount, setCustomAmountRaw] =
|
|
4332
|
-
const [error, setError] =
|
|
4333
|
-
const quickAmounts =
|
|
4334
|
-
const currencySymbol =
|
|
4335
|
-
const resolvedAmount =
|
|
4844
|
+
const [selectedAmount, setSelectedAmount] = useState11(null);
|
|
4845
|
+
const [customAmount, setCustomAmountRaw] = useState11("");
|
|
4846
|
+
const [error, setError] = useState11(null);
|
|
4847
|
+
const quickAmounts = useMemo8(() => getQuickAmounts(currency), [currency]);
|
|
4848
|
+
const currencySymbol = useMemo8(() => getCurrencySymbol(currency), [currency]);
|
|
4849
|
+
const resolvedAmount = useMemo8(() => {
|
|
4336
4850
|
if (customAmount) {
|
|
4337
4851
|
const parsed = parseFloat(customAmount);
|
|
4338
4852
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
4339
4853
|
}
|
|
4340
4854
|
return selectedAmount;
|
|
4341
4855
|
}, [selectedAmount, customAmount]);
|
|
4342
|
-
const selectQuickAmount =
|
|
4856
|
+
const selectQuickAmount = useCallback11(
|
|
4343
4857
|
(amount) => {
|
|
4344
4858
|
setSelectedAmount(amount);
|
|
4345
4859
|
setCustomAmountRaw("");
|
|
@@ -4347,7 +4861,7 @@ function useTopupAmountSelector(options) {
|
|
|
4347
4861
|
},
|
|
4348
4862
|
[]
|
|
4349
4863
|
);
|
|
4350
|
-
const setCustomAmount =
|
|
4864
|
+
const setCustomAmount = useCallback11(
|
|
4351
4865
|
(value) => {
|
|
4352
4866
|
const sanitized = value.replace(/[^0-9.]/g, "");
|
|
4353
4867
|
const dotIndex = sanitized.indexOf(".");
|
|
@@ -4358,7 +4872,7 @@ function useTopupAmountSelector(options) {
|
|
|
4358
4872
|
},
|
|
4359
4873
|
[]
|
|
4360
4874
|
);
|
|
4361
|
-
const validate =
|
|
4875
|
+
const validate = useCallback11(() => {
|
|
4362
4876
|
if (resolvedAmount == null) {
|
|
4363
4877
|
setError(copy.topup.selectOrEnterAmount);
|
|
4364
4878
|
return false;
|
|
@@ -4386,7 +4900,7 @@ function useTopupAmountSelector(options) {
|
|
|
4386
4900
|
setError(null);
|
|
4387
4901
|
return true;
|
|
4388
4902
|
}, [resolvedAmount, minAmount, maxAmount, currency, copy]);
|
|
4389
|
-
const reset =
|
|
4903
|
+
const reset = useCallback11(() => {
|
|
4390
4904
|
setSelectedAmount(null);
|
|
4391
4905
|
setCustomAmountRaw("");
|
|
4392
4906
|
setError(null);
|
|
@@ -4406,10 +4920,10 @@ function useTopupAmountSelector(options) {
|
|
|
4406
4920
|
}
|
|
4407
4921
|
|
|
4408
4922
|
// src/hooks/useBalance.ts
|
|
4409
|
-
import { useEffect as
|
|
4923
|
+
import { useEffect as useEffect9 } from "react";
|
|
4410
4924
|
function useBalance() {
|
|
4411
4925
|
const { balance } = useSolvaPay();
|
|
4412
|
-
|
|
4926
|
+
useEffect9(() => {
|
|
4413
4927
|
balance.refetch();
|
|
4414
4928
|
}, [balance.refetch]);
|
|
4415
4929
|
return balance;
|
|
@@ -4417,17 +4931,17 @@ function useBalance() {
|
|
|
4417
4931
|
|
|
4418
4932
|
// src/primitives/AmountPicker.tsx
|
|
4419
4933
|
import {
|
|
4420
|
-
createContext as
|
|
4934
|
+
createContext as createContext7,
|
|
4421
4935
|
forwardRef as forwardRef6,
|
|
4422
|
-
useCallback as
|
|
4423
|
-
useContext as
|
|
4424
|
-
useEffect as
|
|
4425
|
-
useMemo as
|
|
4936
|
+
useCallback as useCallback12,
|
|
4937
|
+
useContext as useContext10,
|
|
4938
|
+
useEffect as useEffect10,
|
|
4939
|
+
useMemo as useMemo9
|
|
4426
4940
|
} from "react";
|
|
4427
|
-
import { jsx as
|
|
4428
|
-
var AmountPickerContext =
|
|
4941
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
4942
|
+
var AmountPickerContext = createContext7(null);
|
|
4429
4943
|
function usePickerCtx(part) {
|
|
4430
|
-
const ctx =
|
|
4944
|
+
const ctx = useContext10(AmountPickerContext);
|
|
4431
4945
|
if (!ctx) {
|
|
4432
4946
|
throw new Error(`AmountPicker.${part} must be rendered inside <AmountPicker.Root>.`);
|
|
4433
4947
|
}
|
|
@@ -4444,14 +4958,14 @@ var Root3 = forwardRef6(function AmountPickerRoot({
|
|
|
4444
4958
|
children,
|
|
4445
4959
|
...rest
|
|
4446
4960
|
}, forwardedRef) {
|
|
4447
|
-
const solva =
|
|
4961
|
+
const solva = useContext10(SolvaPayContext);
|
|
4448
4962
|
if (!solva) throw new MissingProviderError("AmountPicker");
|
|
4449
4963
|
const internalSelector = useTopupAmountSelector({ currency, minAmount, maxAmount });
|
|
4450
4964
|
const selector = externalSelector ?? internalSelector;
|
|
4451
4965
|
const { creditsPerMinorUnit, displayExchangeRate } = useBalance();
|
|
4452
4966
|
const minorPerMajor = getMinorUnitsPerMajor(currency);
|
|
4453
4967
|
const resolvedAmountMinor = selector.resolvedAmount != null && selector.resolvedAmount > 0 ? Math.round(selector.resolvedAmount * minorPerMajor) : null;
|
|
4454
|
-
|
|
4968
|
+
useEffect10(() => {
|
|
4455
4969
|
if (emit === "minor") {
|
|
4456
4970
|
onChange?.(resolvedAmountMinor);
|
|
4457
4971
|
} else {
|
|
@@ -4461,7 +4975,7 @@ var Root3 = forwardRef6(function AmountPickerRoot({
|
|
|
4461
4975
|
const rate = displayExchangeRate ?? 1;
|
|
4462
4976
|
const estimatedCredits = creditsPerMinorUnit != null && creditsPerMinorUnit > 0 && resolvedAmountMinor != null ? Math.floor(resolvedAmountMinor / rate * creditsPerMinorUnit) : null;
|
|
4463
4977
|
const isApproximate = rate !== 1;
|
|
4464
|
-
const ctx =
|
|
4978
|
+
const ctx = useMemo9(
|
|
4465
4979
|
() => ({
|
|
4466
4980
|
...selector,
|
|
4467
4981
|
currency,
|
|
@@ -4484,7 +4998,7 @@ var Root3 = forwardRef6(function AmountPickerRoot({
|
|
|
4484
4998
|
]
|
|
4485
4999
|
);
|
|
4486
5000
|
const Comp = asChild ? Slot : "div";
|
|
4487
|
-
return /* @__PURE__ */
|
|
5001
|
+
return /* @__PURE__ */ jsx14(AmountPickerContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx14(Comp, { ref: forwardedRef, "data-solvapay-amount-picker": "", ...rest, children }) });
|
|
4488
5002
|
});
|
|
4489
5003
|
var Option = forwardRef6(function AmountPickerOption({ asChild, amount, onClick, children, ...rest }, forwardedRef) {
|
|
4490
5004
|
const ctx = usePickerCtx("Option");
|
|
@@ -4508,10 +5022,10 @@ var Option = forwardRef6(function AmountPickerOption({ asChild, amount, onClick,
|
|
|
4508
5022
|
if (asChild) {
|
|
4509
5023
|
return (
|
|
4510
5024
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4511
|
-
/* @__PURE__ */
|
|
5025
|
+
/* @__PURE__ */ jsx14(Slot, { ref: forwardedRef, ...commonProps, children: children ?? defaultLabel })
|
|
4512
5026
|
);
|
|
4513
5027
|
}
|
|
4514
|
-
return /* @__PURE__ */
|
|
5028
|
+
return /* @__PURE__ */ jsx14("button", { ref: forwardedRef, type: "button", ...commonProps, children: children ?? defaultLabel });
|
|
4515
5029
|
});
|
|
4516
5030
|
var Custom = forwardRef6(function AmountPickerCustom({ asChild, onChange, onFocus, ...rest }, forwardedRef) {
|
|
4517
5031
|
const ctx = usePickerCtx("Custom");
|
|
@@ -4534,15 +5048,15 @@ var Custom = forwardRef6(function AmountPickerCustom({ asChild, onChange, onFocu
|
|
|
4534
5048
|
if (asChild) {
|
|
4535
5049
|
return (
|
|
4536
5050
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4537
|
-
/* @__PURE__ */
|
|
5051
|
+
/* @__PURE__ */ jsx14(Slot, { ref: forwardedRef, ...commonProps })
|
|
4538
5052
|
);
|
|
4539
5053
|
}
|
|
4540
|
-
return /* @__PURE__ */
|
|
5054
|
+
return /* @__PURE__ */ jsx14("input", { ref: forwardedRef, ...commonProps });
|
|
4541
5055
|
});
|
|
4542
5056
|
var Confirm = forwardRef6(function AmountPickerConfirm({ asChild, onClick, onConfirm, disabled, children, ...rest }, forwardedRef) {
|
|
4543
5057
|
const ctx = usePickerCtx("Confirm");
|
|
4544
5058
|
const isDisabled = disabled || !ctx.resolvedAmount;
|
|
4545
|
-
const handleConfirm =
|
|
5059
|
+
const handleConfirm = useCallback12(() => {
|
|
4546
5060
|
if (!ctx.validate()) return;
|
|
4547
5061
|
if (ctx.emit === "minor") {
|
|
4548
5062
|
if (ctx.resolvedAmountMinor != null) onConfirm?.(ctx.resolvedAmountMinor);
|
|
@@ -4561,10 +5075,10 @@ var Confirm = forwardRef6(function AmountPickerConfirm({ asChild, onClick, onCon
|
|
|
4561
5075
|
if (asChild) {
|
|
4562
5076
|
return (
|
|
4563
5077
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4564
|
-
/* @__PURE__ */
|
|
5078
|
+
/* @__PURE__ */ jsx14(Slot, { ref: forwardedRef, ...commonProps, children })
|
|
4565
5079
|
);
|
|
4566
5080
|
}
|
|
4567
|
-
return /* @__PURE__ */
|
|
5081
|
+
return /* @__PURE__ */ jsx14("button", { ref: forwardedRef, type: "button", ...commonProps, children });
|
|
4568
5082
|
});
|
|
4569
5083
|
var AmountPickerRoot2 = Root3;
|
|
4570
5084
|
var AmountPickerOption2 = Option;
|
|
@@ -4593,7 +5107,7 @@ function useAmountPickerCopy() {
|
|
|
4593
5107
|
}
|
|
4594
5108
|
|
|
4595
5109
|
// src/hooks/useTopup.ts
|
|
4596
|
-
import { useState as
|
|
5110
|
+
import { useState as useState12, useCallback as useCallback13, useRef as useRef6 } from "react";
|
|
4597
5111
|
import { loadStripe as loadStripe2 } from "@stripe/stripe-js";
|
|
4598
5112
|
var stripePromiseCache2 = /* @__PURE__ */ new Map();
|
|
4599
5113
|
function getStripeCacheKey2(publishableKey, accountId) {
|
|
@@ -4602,13 +5116,13 @@ function getStripeCacheKey2(publishableKey, accountId) {
|
|
|
4602
5116
|
function useTopup(options) {
|
|
4603
5117
|
const { amount, currency, autoRecharge } = options;
|
|
4604
5118
|
const { createTopupPayment, customerRef, updateCustomerRef } = useSolvaPay();
|
|
4605
|
-
const [loading, setLoading] =
|
|
4606
|
-
const [error, setError] =
|
|
4607
|
-
const [stripePromise, setStripePromise] =
|
|
4608
|
-
const [clientSecret, setClientSecret] =
|
|
4609
|
-
const [processorPaymentId, setProcessorPaymentId] =
|
|
5119
|
+
const [loading, setLoading] = useState12(false);
|
|
5120
|
+
const [error, setError] = useState12(null);
|
|
5121
|
+
const [stripePromise, setStripePromise] = useState12(null);
|
|
5122
|
+
const [clientSecret, setClientSecret] = useState12(null);
|
|
5123
|
+
const [processorPaymentId, setProcessorPaymentId] = useState12(null);
|
|
4610
5124
|
const isStartingRef = useRef6(false);
|
|
4611
|
-
const startTopup =
|
|
5125
|
+
const startTopup = useCallback13(async () => {
|
|
4612
5126
|
if (isStartingRef.current || loading) {
|
|
4613
5127
|
return;
|
|
4614
5128
|
}
|
|
@@ -4656,7 +5170,7 @@ function useTopup(options) {
|
|
|
4656
5170
|
isStartingRef.current = false;
|
|
4657
5171
|
}
|
|
4658
5172
|
}, [amount, currency, autoRecharge, createTopupPayment, customerRef, updateCustomerRef, loading]);
|
|
4659
|
-
const reset =
|
|
5173
|
+
const reset = useCallback13(() => {
|
|
4660
5174
|
isStartingRef.current = false;
|
|
4661
5175
|
setLoading(false);
|
|
4662
5176
|
setError(null);
|
|
@@ -4676,15 +5190,15 @@ function useTopup(options) {
|
|
|
4676
5190
|
}
|
|
4677
5191
|
|
|
4678
5192
|
// src/primitives/TopupForm.tsx
|
|
4679
|
-
import
|
|
4680
|
-
createContext as
|
|
5193
|
+
import React13, {
|
|
5194
|
+
createContext as createContext8,
|
|
4681
5195
|
forwardRef as forwardRef7,
|
|
4682
|
-
useCallback as
|
|
4683
|
-
useContext as
|
|
4684
|
-
useEffect as
|
|
4685
|
-
useMemo as
|
|
5196
|
+
useCallback as useCallback14,
|
|
5197
|
+
useContext as useContext11,
|
|
5198
|
+
useEffect as useEffect11,
|
|
5199
|
+
useMemo as useMemo10,
|
|
4686
5200
|
useRef as useRef7,
|
|
4687
|
-
useState as
|
|
5201
|
+
useState as useState13
|
|
4688
5202
|
} from "react";
|
|
4689
5203
|
import {
|
|
4690
5204
|
Elements as Elements2,
|
|
@@ -4692,10 +5206,14 @@ import {
|
|
|
4692
5206
|
useElements as useElements2,
|
|
4693
5207
|
PaymentElement as StripePaymentElement2
|
|
4694
5208
|
} from "@stripe/react-stripe-js";
|
|
4695
|
-
import {
|
|
4696
|
-
|
|
5209
|
+
import {
|
|
5210
|
+
isCustomerAddressComplete as isCustomerAddressComplete3,
|
|
5211
|
+
resolveBuyerCountry as resolveBuyerCountry3
|
|
5212
|
+
} from "@solvapay/core";
|
|
5213
|
+
import { Fragment as Fragment7, jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5214
|
+
var TopupFormContext = createContext8(null);
|
|
4697
5215
|
function useTopupCtx(part) {
|
|
4698
|
-
const ctx =
|
|
5216
|
+
const ctx = useContext11(TopupFormContext);
|
|
4699
5217
|
if (!ctx) {
|
|
4700
5218
|
throw new Error(`TopupForm.${part} must be rendered inside <TopupForm.Root>.`);
|
|
4701
5219
|
}
|
|
@@ -4712,12 +5230,13 @@ var Root4 = forwardRef7(function TopupFormRoot(props, forwardedRef) {
|
|
|
4712
5230
|
returnUrl,
|
|
4713
5231
|
submitButtonText: _submitButtonText,
|
|
4714
5232
|
buttonClassName: _buttonClassName,
|
|
5233
|
+
appearance,
|
|
4715
5234
|
className,
|
|
4716
5235
|
asChild,
|
|
4717
5236
|
children,
|
|
4718
5237
|
...rest
|
|
4719
5238
|
} = props;
|
|
4720
|
-
const solva =
|
|
5239
|
+
const solva = useContext11(SolvaPayContext);
|
|
4721
5240
|
if (!solva) throw new MissingProviderError("TopupForm");
|
|
4722
5241
|
const { processTopupPayment, attachBusinessDetails, customerRef } = solva;
|
|
4723
5242
|
const copy = useCopy();
|
|
@@ -4736,7 +5255,7 @@ var Root4 = forwardRef7(function TopupFormRoot(props, forwardedRef) {
|
|
|
4736
5255
|
});
|
|
4737
5256
|
const hasInitializedRef = useRef7(false);
|
|
4738
5257
|
const hasAmount = amount > 0;
|
|
4739
|
-
|
|
5258
|
+
useEffect11(() => {
|
|
4740
5259
|
if (!hasInitializedRef.current && hasAmount && !loading && !topupError && !clientSecret) {
|
|
4741
5260
|
hasInitializedRef.current = true;
|
|
4742
5261
|
startTopup().catch((error) => {
|
|
@@ -4747,14 +5266,30 @@ var Root4 = forwardRef7(function TopupFormRoot(props, forwardedRef) {
|
|
|
4747
5266
|
if (hasAmount && clientSecret) hasInitializedRef.current = true;
|
|
4748
5267
|
}, [hasAmount, loading, topupError, clientSecret, startTopup]);
|
|
4749
5268
|
const finalReturnUrl = returnUrl || (typeof window !== "undefined" ? window.location.href : "/");
|
|
4750
|
-
const
|
|
5269
|
+
const [rootEl, setRootEl] = useState13(null);
|
|
5270
|
+
const attachRoot = useCallback14((node) => {
|
|
5271
|
+
if (!node) return;
|
|
5272
|
+
setRootEl((prev) => prev === node ? prev : node);
|
|
5273
|
+
}, []);
|
|
5274
|
+
const resolvedAppearance = useStripeAppearance(rootEl, appearance);
|
|
5275
|
+
const elementsOptions = useMemo10(() => {
|
|
4751
5276
|
if (!clientSecret) return void 0;
|
|
4752
|
-
return {
|
|
4753
|
-
|
|
4754
|
-
|
|
5277
|
+
return {
|
|
5278
|
+
clientSecret,
|
|
5279
|
+
locale: toStripeElementLocale(locale),
|
|
5280
|
+
...resolvedAppearance ? { appearance: resolvedAppearance } : {}
|
|
5281
|
+
};
|
|
5282
|
+
}, [clientSecret, locale, resolvedAppearance]);
|
|
4755
5283
|
const outerError = !hasAmount ? copy.errors.configMissingAmount : topupError ? `${copy.errors.topupInitFailed} ${topupError.message || copy.errors.unknownError}` : null;
|
|
4756
5284
|
const dataState = outerError ? "error" : clientSecret && stripePromise ? "ready" : "loading";
|
|
4757
|
-
const
|
|
5285
|
+
const appearanceReady = appearance !== void 0 || rootEl !== null;
|
|
5286
|
+
const canMountElements = !!(stripePromise && clientSecret && elementsOptions && appearanceReady);
|
|
5287
|
+
const businessAttach = useBusinessDetailsAttach({
|
|
5288
|
+
processorPaymentId,
|
|
5289
|
+
attachBusinessDetails,
|
|
5290
|
+
customerRef,
|
|
5291
|
+
onTaxChange
|
|
5292
|
+
});
|
|
4758
5293
|
const innerCommon = {
|
|
4759
5294
|
amount,
|
|
4760
5295
|
currency,
|
|
@@ -4765,26 +5300,38 @@ var Root4 = forwardRef7(function TopupFormRoot(props, forwardedRef) {
|
|
|
4765
5300
|
state: dataState,
|
|
4766
5301
|
onSuccess,
|
|
4767
5302
|
onError,
|
|
4768
|
-
onTaxChange,
|
|
4769
5303
|
processTopupPayment,
|
|
4770
|
-
|
|
4771
|
-
customerRef
|
|
5304
|
+
businessAttach
|
|
4772
5305
|
};
|
|
4773
|
-
const
|
|
4774
|
-
|
|
5306
|
+
const rootRef = composeRefs(forwardedRef, attachRoot);
|
|
5307
|
+
if (asChild) {
|
|
5308
|
+
const slotted = /* @__PURE__ */ jsx15(
|
|
5309
|
+
Slot,
|
|
5310
|
+
{
|
|
5311
|
+
ref: rootRef,
|
|
5312
|
+
className,
|
|
5313
|
+
"data-solvapay-topup-form": "",
|
|
5314
|
+
"data-state": dataState,
|
|
5315
|
+
...rest,
|
|
5316
|
+
children
|
|
5317
|
+
}
|
|
5318
|
+
);
|
|
5319
|
+
if (canMountElements) {
|
|
5320
|
+
return /* @__PURE__ */ jsx15(Elements2, { stripe: stripePromise, options: elementsOptions, children: /* @__PURE__ */ jsx15(Inner, { ...innerCommon, children: slotted }) }, clientSecret);
|
|
5321
|
+
}
|
|
5322
|
+
return /* @__PURE__ */ jsx15(OfflineInner, { ...innerCommon, children: slotted });
|
|
5323
|
+
}
|
|
5324
|
+
return /* @__PURE__ */ jsx15(
|
|
5325
|
+
"section",
|
|
4775
5326
|
{
|
|
4776
|
-
ref:
|
|
5327
|
+
ref: rootRef,
|
|
4777
5328
|
className,
|
|
4778
5329
|
"data-solvapay-topup-form": "",
|
|
4779
5330
|
"data-state": dataState,
|
|
4780
5331
|
...rest,
|
|
4781
|
-
children
|
|
5332
|
+
children: canMountElements ? /* @__PURE__ */ jsx15(Elements2, { stripe: stripePromise, options: elementsOptions, children: /* @__PURE__ */ jsx15(Inner, { ...innerCommon, children }) }, clientSecret) : /* @__PURE__ */ jsx15(OfflineInner, { ...innerCommon, children })
|
|
4782
5333
|
}
|
|
4783
5334
|
);
|
|
4784
|
-
if (canMountElements) {
|
|
4785
|
-
return /* @__PURE__ */ jsx14(Elements2, { stripe: stripePromise, options: elementsOptions, children: /* @__PURE__ */ jsx14(Inner, { ...innerCommon, children: shell }) }, clientSecret);
|
|
4786
|
-
}
|
|
4787
|
-
return /* @__PURE__ */ jsx14(OfflineInner, { ...innerCommon, children: shell });
|
|
4788
5335
|
});
|
|
4789
5336
|
var Inner = ({
|
|
4790
5337
|
amount,
|
|
@@ -4796,21 +5343,28 @@ var Inner = ({
|
|
|
4796
5343
|
state,
|
|
4797
5344
|
onSuccess,
|
|
4798
5345
|
onError,
|
|
4799
|
-
onTaxChange,
|
|
4800
5346
|
processTopupPayment,
|
|
4801
|
-
|
|
4802
|
-
customerRef,
|
|
5347
|
+
businessAttach,
|
|
4803
5348
|
children
|
|
4804
5349
|
}) => {
|
|
4805
5350
|
const stripe = useStripe2();
|
|
5351
|
+
const stripeAvailable = !!stripe;
|
|
5352
|
+
const stripeRef = useRef7(stripe);
|
|
4806
5353
|
const elements = useElements2();
|
|
4807
5354
|
const copy = useCopy();
|
|
4808
|
-
const
|
|
4809
|
-
const [
|
|
4810
|
-
const [
|
|
5355
|
+
const customer = useCustomer();
|
|
5356
|
+
const [paymentInputComplete, setPaymentInputComplete] = useState13(false);
|
|
5357
|
+
const [isProcessing, setIsProcessing] = useState13(false);
|
|
5358
|
+
const [error, setError] = useState13(null);
|
|
4811
5359
|
const returnResumeStarted = useRef7(false);
|
|
4812
|
-
|
|
4813
|
-
|
|
5360
|
+
useEffect11(() => {
|
|
5361
|
+
stripeRef.current = stripe;
|
|
5362
|
+
});
|
|
5363
|
+
useEffect11(() => {
|
|
5364
|
+
const stripeApi = stripeRef.current;
|
|
5365
|
+
if (!stripeAvailable || !stripeApi || returnResumeStarted.current || typeof window === "undefined") {
|
|
5366
|
+
return;
|
|
5367
|
+
}
|
|
4814
5368
|
const returnClientSecret = readPaymentIntentClientSecret(window.location.search);
|
|
4815
5369
|
if (!returnClientSecret) return;
|
|
4816
5370
|
returnResumeStarted.current = true;
|
|
@@ -4818,7 +5372,7 @@ var Inner = ({
|
|
|
4818
5372
|
void (async () => {
|
|
4819
5373
|
setIsProcessing(true);
|
|
4820
5374
|
setError(null);
|
|
4821
|
-
const retrieved = await
|
|
5375
|
+
const retrieved = await stripeApi.retrievePaymentIntent(returnClientSecret);
|
|
4822
5376
|
if (cancelled) return;
|
|
4823
5377
|
stripPaymentIntentParams();
|
|
4824
5378
|
if (retrieved.error || !retrieved.paymentIntent) {
|
|
@@ -4828,7 +5382,7 @@ var Inner = ({
|
|
|
4828
5382
|
}
|
|
4829
5383
|
let paymentIntent = retrieved.paymentIntent;
|
|
4830
5384
|
if (paymentIntent.status === "requires_action") {
|
|
4831
|
-
const actionResult = await
|
|
5385
|
+
const actionResult = await stripeApi.handleNextAction({ clientSecret: returnClientSecret });
|
|
4832
5386
|
if (cancelled) return;
|
|
4833
5387
|
if (actionResult.error || !actionResult.paymentIntent) {
|
|
4834
5388
|
setError(copy.errors.paymentRequires3ds);
|
|
@@ -4880,7 +5434,7 @@ var Inner = ({
|
|
|
4880
5434
|
return () => {
|
|
4881
5435
|
cancelled = true;
|
|
4882
5436
|
};
|
|
4883
|
-
}, [
|
|
5437
|
+
}, [stripeAvailable, copy, processTopupPayment, onSuccess, onError]);
|
|
4884
5438
|
const {
|
|
4885
5439
|
businessDetails,
|
|
4886
5440
|
setBusinessDetails,
|
|
@@ -4891,15 +5445,10 @@ var Inner = ({
|
|
|
4891
5445
|
businessDetailsError,
|
|
4892
5446
|
requiresBusinessAttach,
|
|
4893
5447
|
runAttach
|
|
4894
|
-
} =
|
|
4895
|
-
processorPaymentId,
|
|
4896
|
-
attachBusinessDetails,
|
|
4897
|
-
customerRef,
|
|
4898
|
-
onTaxChange
|
|
4899
|
-
});
|
|
5448
|
+
} = businessAttach;
|
|
4900
5449
|
const isReady = !!(stripe && elements);
|
|
4901
|
-
const canSubmit = isReady && paymentInputComplete && !isProcessing && !!clientSecret && (!requiresBusinessAttach || businessDetailsAttached) && !businessDetailsAttaching;
|
|
4902
|
-
const submit =
|
|
5450
|
+
const canSubmit = isReady && paymentInputComplete && !isProcessing && !!clientSecret && (!requiresBusinessAttach || businessDetailsAttached) && isCustomerAddressComplete3(businessDetails) && !businessDetailsAttaching;
|
|
5451
|
+
const submit = useCallback14(async () => {
|
|
4903
5452
|
if (!stripe || !elements || !clientSecret) {
|
|
4904
5453
|
const msg = copy.errors.stripeUnavailable;
|
|
4905
5454
|
setError(msg);
|
|
@@ -4917,44 +5466,51 @@ var Inner = ({
|
|
|
4917
5466
|
}
|
|
4918
5467
|
setError(null);
|
|
4919
5468
|
setIsProcessing(true);
|
|
4920
|
-
const
|
|
4921
|
-
|
|
4922
|
-
const msg = submitError.message || copy.errors.paymentUnexpected;
|
|
4923
|
-
setError(msg);
|
|
4924
|
-
setIsProcessing(false);
|
|
4925
|
-
onError?.(new Error(msg));
|
|
4926
|
-
return;
|
|
4927
|
-
}
|
|
4928
|
-
const { error: confirmError, paymentIntent } = await stripe.confirmPayment({
|
|
5469
|
+
const result = await confirmPayment({
|
|
5470
|
+
stripe,
|
|
4929
5471
|
elements,
|
|
4930
5472
|
clientSecret,
|
|
4931
|
-
|
|
4932
|
-
|
|
5473
|
+
returnUrl,
|
|
5474
|
+
billingDetails: buildConfirmBillingDetails({
|
|
5475
|
+
name: customer.name,
|
|
5476
|
+
email: customer.email,
|
|
5477
|
+
country: resolveBuyerCountry3(businessDetails),
|
|
5478
|
+
state: businessDetails.customerState,
|
|
5479
|
+
postalCode: businessDetails.customerPostalCode
|
|
5480
|
+
}),
|
|
5481
|
+
copy
|
|
4933
5482
|
});
|
|
4934
|
-
if (
|
|
4935
|
-
|
|
4936
|
-
setError(msg);
|
|
5483
|
+
if (result.status === "error" || result.status === "requires_action" || result.status === "other") {
|
|
5484
|
+
setError(result.message);
|
|
4937
5485
|
setIsProcessing(false);
|
|
4938
|
-
|
|
5486
|
+
if (result.status === "error") {
|
|
5487
|
+
onError?.(new Error(result.message));
|
|
5488
|
+
}
|
|
4939
5489
|
return;
|
|
4940
5490
|
}
|
|
5491
|
+
if (result.status === "pending") {
|
|
5492
|
+
setError(result.message);
|
|
5493
|
+
setIsProcessing(false);
|
|
5494
|
+
return;
|
|
5495
|
+
}
|
|
5496
|
+
const paymentIntent = result.paymentIntent;
|
|
4941
5497
|
let creditsAdded;
|
|
4942
5498
|
if (paymentIntent && processTopupPayment) {
|
|
4943
5499
|
try {
|
|
4944
|
-
const
|
|
4945
|
-
if (
|
|
5500
|
+
const result2 = await processTopupPayment({ paymentIntentId: paymentIntent.id });
|
|
5501
|
+
if (result2.status === "processing") {
|
|
4946
5502
|
setError(copy.errors.paymentPending);
|
|
4947
5503
|
setIsProcessing(false);
|
|
4948
5504
|
return;
|
|
4949
5505
|
}
|
|
4950
|
-
if (
|
|
5506
|
+
if (result2.status === "failed" || result2.status === "cancelled") {
|
|
4951
5507
|
setError(copy.errors.paymentUnexpected);
|
|
4952
5508
|
setIsProcessing(false);
|
|
4953
|
-
onError?.(new Error(`Topup ${
|
|
5509
|
+
onError?.(new Error(`Topup ${result2.status}`));
|
|
4954
5510
|
return;
|
|
4955
5511
|
}
|
|
4956
|
-
if (
|
|
4957
|
-
creditsAdded =
|
|
5512
|
+
if (result2.status === "succeeded" && typeof result2.creditsAdded === "number") {
|
|
5513
|
+
creditsAdded = result2.creditsAdded;
|
|
4958
5514
|
}
|
|
4959
5515
|
} catch (err) {
|
|
4960
5516
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -4976,6 +5532,7 @@ var Inner = ({
|
|
|
4976
5532
|
elements,
|
|
4977
5533
|
clientSecret,
|
|
4978
5534
|
returnUrl,
|
|
5535
|
+
customer,
|
|
4979
5536
|
copy,
|
|
4980
5537
|
onSuccess,
|
|
4981
5538
|
onError,
|
|
@@ -4987,7 +5544,7 @@ var Inner = ({
|
|
|
4987
5544
|
businessDetailsError
|
|
4988
5545
|
]);
|
|
4989
5546
|
const effectiveError = error ?? outerError ?? businessDetailsError;
|
|
4990
|
-
const ctx =
|
|
5547
|
+
const ctx = useMemo10(
|
|
4991
5548
|
() => ({
|
|
4992
5549
|
amount,
|
|
4993
5550
|
currency,
|
|
@@ -5036,7 +5593,7 @@ var Inner = ({
|
|
|
5036
5593
|
submit
|
|
5037
5594
|
]
|
|
5038
5595
|
);
|
|
5039
|
-
return /* @__PURE__ */
|
|
5596
|
+
return /* @__PURE__ */ jsx15(TopupFormContext.Provider, { value: ctx, children });
|
|
5040
5597
|
};
|
|
5041
5598
|
var OfflineInner = ({
|
|
5042
5599
|
amount,
|
|
@@ -5046,15 +5603,14 @@ var OfflineInner = ({
|
|
|
5046
5603
|
returnUrl,
|
|
5047
5604
|
outerError,
|
|
5048
5605
|
state,
|
|
5606
|
+
businessAttach,
|
|
5049
5607
|
children
|
|
5050
5608
|
}) => {
|
|
5051
|
-
const noopSubmit =
|
|
5609
|
+
const noopSubmit = useCallback14(async () => {
|
|
5052
5610
|
}, []);
|
|
5053
|
-
const noopSet =
|
|
5611
|
+
const noopSet = useCallback14(() => {
|
|
5054
5612
|
}, []);
|
|
5055
|
-
const
|
|
5056
|
-
}, []);
|
|
5057
|
-
const ctx = useMemo9(
|
|
5613
|
+
const ctx = useMemo10(
|
|
5058
5614
|
() => ({
|
|
5059
5615
|
amount,
|
|
5060
5616
|
currency,
|
|
@@ -5069,13 +5625,13 @@ var OfflineInner = ({
|
|
|
5069
5625
|
canSubmit: false,
|
|
5070
5626
|
error: outerError,
|
|
5071
5627
|
returnUrl,
|
|
5072
|
-
businessDetails:
|
|
5073
|
-
taxBreakdown:
|
|
5074
|
-
businessDetailsAttached:
|
|
5075
|
-
businessDetailsAttaching:
|
|
5076
|
-
businessDetailsError:
|
|
5077
|
-
fieldErrors:
|
|
5078
|
-
setBusinessDetails:
|
|
5628
|
+
businessDetails: businessAttach.businessDetails,
|
|
5629
|
+
taxBreakdown: businessAttach.taxBreakdown,
|
|
5630
|
+
businessDetailsAttached: businessAttach.businessDetailsAttached,
|
|
5631
|
+
businessDetailsAttaching: businessAttach.businessDetailsAttaching,
|
|
5632
|
+
businessDetailsError: businessAttach.businessDetailsError,
|
|
5633
|
+
fieldErrors: businessAttach.fieldErrors,
|
|
5634
|
+
setBusinessDetails: businessAttach.setBusinessDetails,
|
|
5079
5635
|
setPaymentInputComplete: noopSet,
|
|
5080
5636
|
submit: noopSubmit
|
|
5081
5637
|
}),
|
|
@@ -5087,21 +5643,21 @@ var OfflineInner = ({
|
|
|
5087
5643
|
processorPaymentId,
|
|
5088
5644
|
outerError,
|
|
5089
5645
|
returnUrl,
|
|
5646
|
+
businessAttach,
|
|
5090
5647
|
noopSet,
|
|
5091
|
-
noopSubmit
|
|
5092
|
-
noopBusinessSet
|
|
5648
|
+
noopSubmit
|
|
5093
5649
|
]
|
|
5094
5650
|
);
|
|
5095
|
-
return /* @__PURE__ */
|
|
5651
|
+
return /* @__PURE__ */ jsx15(TopupFormContext.Provider, { value: ctx, children });
|
|
5096
5652
|
};
|
|
5097
5653
|
var PaymentElementSlot2 = ({ options }) => {
|
|
5098
5654
|
const { setPaymentInputComplete, isReady, stripe, elements } = useTopupCtx("PaymentElement");
|
|
5099
5655
|
const locale = useLocale();
|
|
5100
5656
|
if (!stripe || !elements) return null;
|
|
5101
5657
|
if (!isReady) {
|
|
5102
|
-
return /* @__PURE__ */
|
|
5658
|
+
return /* @__PURE__ */ jsx15("output", { "data-solvapay-topup-form-loading": "", children: /* @__PURE__ */ jsx15(Spinner, { size: "sm" }) });
|
|
5103
5659
|
}
|
|
5104
|
-
return /* @__PURE__ */
|
|
5660
|
+
return /* @__PURE__ */ jsx15("section", { "data-solvapay-topup-form-payment-element": "", children: /* @__PURE__ */ jsx15(
|
|
5105
5661
|
StripePaymentElement2,
|
|
5106
5662
|
{
|
|
5107
5663
|
options: withPaymentElementDefaults(options),
|
|
@@ -5116,8 +5672,8 @@ var SubmitButton2 = forwardRef7(
|
|
|
5116
5672
|
const copy = useCopy();
|
|
5117
5673
|
const dataState = ctx.isProcessing ? "processing" : !ctx.canSubmit ? "disabled" : "idle";
|
|
5118
5674
|
const processingContent = /* @__PURE__ */ jsxs7(Fragment7, { children: [
|
|
5119
|
-
/* @__PURE__ */
|
|
5120
|
-
/* @__PURE__ */
|
|
5675
|
+
/* @__PURE__ */ jsx15(Spinner, { size: "sm" }),
|
|
5676
|
+
/* @__PURE__ */ jsx15("span", { children: copy.cta.processing })
|
|
5121
5677
|
] });
|
|
5122
5678
|
const commonProps = {
|
|
5123
5679
|
"data-solvapay-topup-form-submit": "",
|
|
@@ -5132,38 +5688,38 @@ var SubmitButton2 = forwardRef7(
|
|
|
5132
5688
|
...rest
|
|
5133
5689
|
};
|
|
5134
5690
|
if (asChild) {
|
|
5135
|
-
const slotChild = ctx.isProcessing &&
|
|
5691
|
+
const slotChild = ctx.isProcessing && React13.isValidElement(children) ? React13.cloneElement(
|
|
5136
5692
|
children,
|
|
5137
5693
|
void 0,
|
|
5138
5694
|
processingContent
|
|
5139
5695
|
) : children;
|
|
5140
|
-
return /* @__PURE__ */
|
|
5696
|
+
return /* @__PURE__ */ jsx15(Slot, { ref: forwardedRef, ...commonProps, children: slotChild });
|
|
5141
5697
|
}
|
|
5142
5698
|
const content = ctx.isProcessing ? processingContent : children ? children : copy.cta.topUp;
|
|
5143
|
-
return /* @__PURE__ */
|
|
5699
|
+
return /* @__PURE__ */ jsx15("button", { ref: forwardedRef, type: "submit", ...commonProps, children: content });
|
|
5144
5700
|
}
|
|
5145
5701
|
);
|
|
5146
5702
|
var Loading2 = forwardRef7(function TopupFormLoading({ asChild, children, ...rest }, forwardedRef) {
|
|
5147
5703
|
const ctx = useTopupCtx("Loading");
|
|
5148
5704
|
if (ctx.state !== "loading") return null;
|
|
5149
5705
|
if (asChild) {
|
|
5150
|
-
return /* @__PURE__ */
|
|
5706
|
+
return /* @__PURE__ */ jsx15(
|
|
5151
5707
|
Slot,
|
|
5152
5708
|
{
|
|
5153
5709
|
ref: forwardedRef,
|
|
5154
5710
|
"data-solvapay-topup-form-loading": "",
|
|
5155
5711
|
...rest,
|
|
5156
|
-
children: children ?? /* @__PURE__ */
|
|
5712
|
+
children: children ?? /* @__PURE__ */ jsx15(Spinner, { size: "sm" })
|
|
5157
5713
|
}
|
|
5158
5714
|
);
|
|
5159
5715
|
}
|
|
5160
|
-
return /* @__PURE__ */
|
|
5716
|
+
return /* @__PURE__ */ jsx15("output", { ref: forwardedRef, "data-solvapay-topup-form-loading": "", ...rest, children: children ?? /* @__PURE__ */ jsx15(Spinner, { size: "sm" }) });
|
|
5161
5717
|
});
|
|
5162
5718
|
var ErrorSlot2 = forwardRef7(function TopupFormError({ asChild, children, ...rest }, forwardedRef) {
|
|
5163
5719
|
const ctx = useTopupCtx("Error");
|
|
5164
5720
|
if (!ctx.error) return null;
|
|
5165
5721
|
if (asChild) {
|
|
5166
|
-
return /* @__PURE__ */
|
|
5722
|
+
return /* @__PURE__ */ jsx15(
|
|
5167
5723
|
Slot,
|
|
5168
5724
|
{
|
|
5169
5725
|
ref: forwardedRef,
|
|
@@ -5176,7 +5732,7 @@ var ErrorSlot2 = forwardRef7(function TopupFormError({ asChild, children, ...res
|
|
|
5176
5732
|
}
|
|
5177
5733
|
);
|
|
5178
5734
|
}
|
|
5179
|
-
return /* @__PURE__ */
|
|
5735
|
+
return /* @__PURE__ */ jsx15(
|
|
5180
5736
|
"p",
|
|
5181
5737
|
{
|
|
5182
5738
|
ref: forwardedRef,
|
|
@@ -5233,11 +5789,11 @@ function useTopupForm() {
|
|
|
5233
5789
|
}
|
|
5234
5790
|
|
|
5235
5791
|
// src/primitives/BalanceBadge.tsx
|
|
5236
|
-
import { forwardRef as forwardRef8, useContext as
|
|
5792
|
+
import { forwardRef as forwardRef8, useContext as useContext12 } from "react";
|
|
5237
5793
|
import { creditsToDisplayMinorUnits, minorUnitsPerMajor } from "@solvapay/core";
|
|
5238
|
-
import { Fragment as Fragment8, jsx as
|
|
5794
|
+
import { Fragment as Fragment8, jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
5239
5795
|
var BalanceBadge = forwardRef8(function BalanceBadge2({ asChild, numberOnly, lowThreshold = 10, children, ...rest }, forwardedRef) {
|
|
5240
|
-
const solva =
|
|
5796
|
+
const solva = useContext12(SolvaPayContext);
|
|
5241
5797
|
if (!solva) throw new MissingProviderError("BalanceBadge");
|
|
5242
5798
|
const { credits, displayCurrency, creditsPerMinorUnit, displayExchangeRate, loading } = useBalance();
|
|
5243
5799
|
const copy = useCopy();
|
|
@@ -5254,10 +5810,10 @@ var BalanceBadge = forwardRef8(function BalanceBadge2({ asChild, numberOnly, low
|
|
|
5254
5810
|
if (asChild) {
|
|
5255
5811
|
return (
|
|
5256
5812
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5257
|
-
/* @__PURE__ */
|
|
5813
|
+
/* @__PURE__ */ jsx16(Slot, { ref: forwardedRef, ...commonProps, children: children ?? /* @__PURE__ */ jsx16(Fragment8, {}) })
|
|
5258
5814
|
);
|
|
5259
5815
|
}
|
|
5260
|
-
return /* @__PURE__ */
|
|
5816
|
+
return /* @__PURE__ */ jsx16("span", { ref: forwardedRef, ...commonProps });
|
|
5261
5817
|
}
|
|
5262
5818
|
if (credits == null) return null;
|
|
5263
5819
|
const formattedCredits = new Intl.NumberFormat(locale).format(credits);
|
|
@@ -5287,22 +5843,22 @@ var BalanceBadge = forwardRef8(function BalanceBadge2({ asChild, numberOnly, low
|
|
|
5287
5843
|
if (asChild) {
|
|
5288
5844
|
return (
|
|
5289
5845
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5290
|
-
/* @__PURE__ */
|
|
5846
|
+
/* @__PURE__ */ jsx16(Slot, { ref: forwardedRef, ...commonProps, children: content })
|
|
5291
5847
|
);
|
|
5292
5848
|
}
|
|
5293
|
-
return /* @__PURE__ */
|
|
5849
|
+
return /* @__PURE__ */ jsx16("span", { ref: forwardedRef, ...commonProps, children: content });
|
|
5294
5850
|
});
|
|
5295
5851
|
|
|
5296
5852
|
// src/primitives/PlanSelector.tsx
|
|
5297
5853
|
import {
|
|
5298
|
-
createContext as
|
|
5854
|
+
createContext as createContext9,
|
|
5299
5855
|
forwardRef as forwardRef9,
|
|
5300
|
-
useCallback as
|
|
5301
|
-
useContext as
|
|
5302
|
-
useEffect as
|
|
5303
|
-
useMemo as
|
|
5856
|
+
useCallback as useCallback15,
|
|
5857
|
+
useContext as useContext13,
|
|
5858
|
+
useEffect as useEffect12,
|
|
5859
|
+
useMemo as useMemo11,
|
|
5304
5860
|
useRef as useRef8,
|
|
5305
|
-
useState as
|
|
5861
|
+
useState as useState14
|
|
5306
5862
|
} from "react";
|
|
5307
5863
|
|
|
5308
5864
|
// src/utils/isPayg.ts
|
|
@@ -5343,18 +5899,18 @@ function resolvePlanPricingOption(plan, currency) {
|
|
|
5343
5899
|
}
|
|
5344
5900
|
|
|
5345
5901
|
// src/primitives/PlanSelector.tsx
|
|
5346
|
-
import { jsx as
|
|
5347
|
-
var PlanSelectorContext =
|
|
5902
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
5903
|
+
var PlanSelectorContext = createContext9(null);
|
|
5348
5904
|
function usePlanSelectorContext(part) {
|
|
5349
|
-
const ctx =
|
|
5905
|
+
const ctx = useContext13(PlanSelectorContext);
|
|
5350
5906
|
if (!ctx) {
|
|
5351
5907
|
throw new Error(`PlanSelector.${part} must be rendered inside <PlanSelector.Root>.`);
|
|
5352
5908
|
}
|
|
5353
5909
|
return ctx;
|
|
5354
5910
|
}
|
|
5355
|
-
var CardContext =
|
|
5911
|
+
var CardContext = createContext9(null);
|
|
5356
5912
|
function useCardContext(part) {
|
|
5357
|
-
const ctx =
|
|
5913
|
+
const ctx = useContext13(CardContext);
|
|
5358
5914
|
if (!ctx) {
|
|
5359
5915
|
throw new Error(`PlanSelector.${part} must be rendered inside <PlanSelector.Card>.`);
|
|
5360
5916
|
}
|
|
@@ -5374,12 +5930,12 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5374
5930
|
children,
|
|
5375
5931
|
...rest
|
|
5376
5932
|
} = props;
|
|
5377
|
-
const solva =
|
|
5933
|
+
const solva = useContext13(SolvaPayContext);
|
|
5378
5934
|
if (!solva) throw new MissingProviderError("PlanSelector");
|
|
5379
5935
|
if (!productRef) throw new MissingProductRefError("PlanSelector");
|
|
5380
5936
|
const { _config } = solva;
|
|
5381
5937
|
const { purchases } = usePurchase();
|
|
5382
|
-
const effectiveFetcher =
|
|
5938
|
+
const effectiveFetcher = useMemo11(
|
|
5383
5939
|
() => fetcher ?? ((ref) => defaultListPlans(ref, _config)),
|
|
5384
5940
|
[fetcher, _config]
|
|
5385
5941
|
);
|
|
@@ -5391,24 +5947,24 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5391
5947
|
autoSelectFirstPaid,
|
|
5392
5948
|
initialPlanRef
|
|
5393
5949
|
});
|
|
5394
|
-
const autoCurrentPlanRef =
|
|
5950
|
+
const autoCurrentPlanRef = useMemo11(() => {
|
|
5395
5951
|
const active = purchases.filter((p) => p.status === "active").sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0];
|
|
5396
5952
|
return active?.planSnapshot?.reference ?? null;
|
|
5397
5953
|
}, [purchases]);
|
|
5398
5954
|
const resolvedCurrentPlanRef = currentPlanRef === null ? null : currentPlanRef ?? autoCurrentPlanRef;
|
|
5399
|
-
const isCurrent =
|
|
5955
|
+
const isCurrent = useCallback15(
|
|
5400
5956
|
(ref) => resolvedCurrentPlanRef === ref,
|
|
5401
5957
|
[resolvedCurrentPlanRef]
|
|
5402
5958
|
);
|
|
5403
|
-
const isFree =
|
|
5959
|
+
const isFree = useCallback15(
|
|
5404
5960
|
(ref) => plans.find((p) => p.reference === ref)?.requiresPayment === false,
|
|
5405
5961
|
[plans]
|
|
5406
5962
|
);
|
|
5407
|
-
const isPopular =
|
|
5963
|
+
const isPopular = useCallback15(
|
|
5408
5964
|
(ref) => popularPlanRef === ref,
|
|
5409
5965
|
[popularPlanRef]
|
|
5410
5966
|
);
|
|
5411
|
-
const select =
|
|
5967
|
+
const select = useCallback15(
|
|
5412
5968
|
(ref) => {
|
|
5413
5969
|
const plan = plans.find((p) => p.reference === ref);
|
|
5414
5970
|
if (!plan) return;
|
|
@@ -5418,29 +5974,29 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5418
5974
|
},
|
|
5419
5975
|
[plans, selectPlan, onSelect]
|
|
5420
5976
|
);
|
|
5421
|
-
const clearSelection =
|
|
5977
|
+
const clearSelection = useCallback15(() => {
|
|
5422
5978
|
setSelectedPlanIndex(-1);
|
|
5423
5979
|
}, [setSelectedPlanIndex]);
|
|
5424
5980
|
const selectedPlanRef = selectedPlan?.reference ?? null;
|
|
5425
|
-
const [preferredCurrency, setPreferredCurrencyState] =
|
|
5426
|
-
const [selectedCurrencies, setSelectedCurrencies] =
|
|
5427
|
-
const getSelectedOption =
|
|
5981
|
+
const [preferredCurrency, setPreferredCurrencyState] = useState14(null);
|
|
5982
|
+
const [selectedCurrencies, setSelectedCurrencies] = useState14({});
|
|
5983
|
+
const getSelectedOption = useCallback15(
|
|
5428
5984
|
(plan) => resolvePlanPricingOption(
|
|
5429
5985
|
plan,
|
|
5430
5986
|
selectedCurrencies[plan.reference] ?? preferredCurrency ?? null
|
|
5431
5987
|
),
|
|
5432
5988
|
[selectedCurrencies, preferredCurrency]
|
|
5433
5989
|
);
|
|
5434
|
-
const setPreferredCurrency =
|
|
5990
|
+
const setPreferredCurrency = useCallback15((currency) => {
|
|
5435
5991
|
setPreferredCurrencyState(currency.toUpperCase());
|
|
5436
5992
|
setSelectedCurrencies({});
|
|
5437
5993
|
}, []);
|
|
5438
|
-
const setPlanCurrency =
|
|
5994
|
+
const setPlanCurrency = useCallback15((planRef, currency) => {
|
|
5439
5995
|
setSelectedCurrencies((current) => ({ ...current, [planRef]: currency }));
|
|
5440
5996
|
}, []);
|
|
5441
5997
|
const selectedCurrency = selectedPlan ? getSelectedOption(selectedPlan).currency : null;
|
|
5442
5998
|
const autoCurrentAppliedKeyRef = useRef8(null);
|
|
5443
|
-
|
|
5999
|
+
useEffect12(() => {
|
|
5444
6000
|
if (autoCurrentAppliedKeyRef.current === productRef) return;
|
|
5445
6001
|
if (selectedPlanRef) {
|
|
5446
6002
|
autoCurrentAppliedKeyRef.current = productRef;
|
|
@@ -5455,7 +6011,7 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5455
6011
|
autoCurrentAppliedKeyRef.current = productRef;
|
|
5456
6012
|
select(resolvedCurrentPlanRef);
|
|
5457
6013
|
}, [productRef, plans, resolvedCurrentPlanRef, selectedPlanRef, select]);
|
|
5458
|
-
const ctx =
|
|
6014
|
+
const ctx = useMemo11(
|
|
5459
6015
|
() => ({
|
|
5460
6016
|
plans,
|
|
5461
6017
|
loading,
|
|
@@ -5495,7 +6051,7 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5495
6051
|
getSelectedOption
|
|
5496
6052
|
]
|
|
5497
6053
|
);
|
|
5498
|
-
return /* @__PURE__ */
|
|
6054
|
+
return /* @__PURE__ */ jsx17(
|
|
5499
6055
|
PlanSelectionProvider,
|
|
5500
6056
|
{
|
|
5501
6057
|
value: {
|
|
@@ -5514,7 +6070,7 @@ var Root5 = forwardRef9(function PlanSelectorRoot(props, forwardedRef) {
|
|
|
5514
6070
|
loading,
|
|
5515
6071
|
error
|
|
5516
6072
|
},
|
|
5517
|
-
children: /* @__PURE__ */
|
|
6073
|
+
children: /* @__PURE__ */ jsx17("div", { ref: forwardedRef, "data-solvapay-plan-selector": "", ...rest, children: /* @__PURE__ */ jsx17(PlanSelectorContext.Provider, { value: ctx, children }) })
|
|
5518
6074
|
}
|
|
5519
6075
|
);
|
|
5520
6076
|
});
|
|
@@ -5522,11 +6078,11 @@ var Heading = forwardRef9(function PlanSelectorHeading({ asChild, children, ...r
|
|
|
5522
6078
|
usePlanSelectorContext("Heading");
|
|
5523
6079
|
const copy = useCopy();
|
|
5524
6080
|
const Comp = asChild ? Slot : "h3";
|
|
5525
|
-
return /* @__PURE__ */
|
|
6081
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-heading": "", ...rest, children: children ?? copy.planSelector.heading });
|
|
5526
6082
|
});
|
|
5527
6083
|
var Grid = forwardRef9(function PlanSelectorGrid({ children, ...rest }, forwardedRef) {
|
|
5528
6084
|
const ctx = usePlanSelectorContext("Grid");
|
|
5529
|
-
return /* @__PURE__ */
|
|
6085
|
+
return /* @__PURE__ */ jsx17("div", { ref: forwardedRef, "data-solvapay-plan-selector-grid": "", ...rest, children: ctx.plans.map((plan) => {
|
|
5530
6086
|
const isCurrent = ctx.isCurrent(plan.reference);
|
|
5531
6087
|
const isFree = ctx.isFree(plan.reference);
|
|
5532
6088
|
const isPopular = ctx.isPopular(plan.reference);
|
|
@@ -5548,7 +6104,7 @@ var Grid = forwardRef9(function PlanSelectorGrid({ children, ...rest }, forwarde
|
|
|
5548
6104
|
select: () => ctx.select(plan.reference),
|
|
5549
6105
|
setCurrency: (currency) => ctx.setPlanCurrency(plan.reference, currency)
|
|
5550
6106
|
};
|
|
5551
|
-
return /* @__PURE__ */
|
|
6107
|
+
return /* @__PURE__ */ jsx17(CardContext.Provider, { value: cardCtx, children }, plan.reference);
|
|
5552
6108
|
}) });
|
|
5553
6109
|
});
|
|
5554
6110
|
var Card = forwardRef9(function PlanSelectorCard({ asChild, onClick, children, ...rest }, forwardedRef) {
|
|
@@ -5569,10 +6125,10 @@ var Card = forwardRef9(function PlanSelectorCard({ asChild, onClick, children, .
|
|
|
5569
6125
|
if (asChild) {
|
|
5570
6126
|
return (
|
|
5571
6127
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5572
|
-
/* @__PURE__ */
|
|
6128
|
+
/* @__PURE__ */ jsx17(Slot, { ref: forwardedRef, ...commonProps, children })
|
|
5573
6129
|
);
|
|
5574
6130
|
}
|
|
5575
|
-
return /* @__PURE__ */
|
|
6131
|
+
return /* @__PURE__ */ jsx17(
|
|
5576
6132
|
"button",
|
|
5577
6133
|
{
|
|
5578
6134
|
ref: forwardedRef,
|
|
@@ -5589,13 +6145,13 @@ var CardName = forwardRef9(function PlanSelectorCardName({ asChild, children, ..
|
|
|
5589
6145
|
const label = card.plan.name ?? fallback;
|
|
5590
6146
|
if (!label && children == null) return null;
|
|
5591
6147
|
const Comp = asChild ? Slot : "span";
|
|
5592
|
-
return /* @__PURE__ */
|
|
6148
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-card-name": "", ...rest, children: children ?? label });
|
|
5593
6149
|
});
|
|
5594
6150
|
var CardPrice = forwardRef9(function PlanSelectorCardPrice({ asChild, children, ...rest }, forwardedRef) {
|
|
5595
6151
|
const card = useCardContext("CardPrice");
|
|
5596
6152
|
const locale = useLocale();
|
|
5597
6153
|
const copy = useCopy();
|
|
5598
|
-
const formatted =
|
|
6154
|
+
const formatted = useMemo11(() => {
|
|
5599
6155
|
if (card.isFree) return copy.planSelector.freeBadge;
|
|
5600
6156
|
if (card.plan.type === "usage-based") {
|
|
5601
6157
|
return copy.planSelector.usageRateLabel;
|
|
@@ -5615,7 +6171,7 @@ var CardPrice = forwardRef9(function PlanSelectorCardPrice({ asChild, children,
|
|
|
5615
6171
|
copy.interval.free
|
|
5616
6172
|
]);
|
|
5617
6173
|
const Comp = asChild ? Slot : "span";
|
|
5618
|
-
return /* @__PURE__ */
|
|
6174
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-card-price": "", ...rest, children: children ?? formatted });
|
|
5619
6175
|
});
|
|
5620
6176
|
var CardInterval = forwardRef9(function PlanSelectorCardInterval({ asChild, children, ...rest }, forwardedRef) {
|
|
5621
6177
|
const card = useCardContext("CardInterval");
|
|
@@ -5625,7 +6181,7 @@ var CardInterval = forwardRef9(function PlanSelectorCardInterval({ asChild, chil
|
|
|
5625
6181
|
if (!rawInterval) return null;
|
|
5626
6182
|
const text = interpolate(copy.planSelector.perIntervalShort, { interval: rawInterval });
|
|
5627
6183
|
const Comp = asChild ? Slot : "span";
|
|
5628
|
-
return /* @__PURE__ */
|
|
6184
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-card-interval": "", ...rest, children: children ?? text });
|
|
5629
6185
|
});
|
|
5630
6186
|
function normalizeBillingCycle(cycle) {
|
|
5631
6187
|
if (!cycle) return null;
|
|
@@ -5638,7 +6194,7 @@ function normalizeBillingCycle(cycle) {
|
|
|
5638
6194
|
}
|
|
5639
6195
|
var CurrencySwitcher = forwardRef9(function PlanSelectorCurrencySwitcher({ children, onChange, className, ...rest }, forwardedRef) {
|
|
5640
6196
|
const ctx = usePlanSelectorContext("CurrencySwitcher");
|
|
5641
|
-
const availableCurrencies =
|
|
6197
|
+
const availableCurrencies = useMemo11(() => {
|
|
5642
6198
|
const currencies = /* @__PURE__ */ new Set();
|
|
5643
6199
|
for (const plan of ctx.plans) {
|
|
5644
6200
|
const options = getPlanPricingOptions(plan);
|
|
@@ -5651,7 +6207,7 @@ var CurrencySwitcher = forwardRef9(function PlanSelectorCurrencySwitcher({ child
|
|
|
5651
6207
|
}, [ctx.plans]);
|
|
5652
6208
|
if (availableCurrencies.length < 2) return null;
|
|
5653
6209
|
const effectiveCurrency = ctx.preferredCurrency ?? (ctx.selectedPlan ? ctx.getSelectedOption(ctx.selectedPlan).currency.toUpperCase() : null) ?? availableCurrencies[0];
|
|
5654
|
-
return /* @__PURE__ */
|
|
6210
|
+
return /* @__PURE__ */ jsx17(
|
|
5655
6211
|
"select",
|
|
5656
6212
|
{
|
|
5657
6213
|
ref: forwardedRef,
|
|
@@ -5663,7 +6219,7 @@ var CurrencySwitcher = forwardRef9(function PlanSelectorCurrencySwitcher({ child
|
|
|
5663
6219
|
onChange?.(event);
|
|
5664
6220
|
},
|
|
5665
6221
|
...rest,
|
|
5666
|
-
children: children ?? availableCurrencies.map((currency) => /* @__PURE__ */
|
|
6222
|
+
children: children ?? availableCurrencies.map((currency) => /* @__PURE__ */ jsx17("option", { value: currency, children: currency }, currency))
|
|
5667
6223
|
}
|
|
5668
6224
|
);
|
|
5669
6225
|
});
|
|
@@ -5671,7 +6227,7 @@ var CardCurrency = forwardRef9(
|
|
|
5671
6227
|
function PlanSelectorCardCurrency({ children, onChange, ...rest }, forwardedRef) {
|
|
5672
6228
|
const card = useCardContext("CardCurrency");
|
|
5673
6229
|
if (card.pricingOptions.length <= 1) return null;
|
|
5674
|
-
return /* @__PURE__ */
|
|
6230
|
+
return /* @__PURE__ */ jsx17(
|
|
5675
6231
|
"select",
|
|
5676
6232
|
{
|
|
5677
6233
|
ref: forwardedRef,
|
|
@@ -5682,7 +6238,7 @@ var CardCurrency = forwardRef9(
|
|
|
5682
6238
|
onChange?.(event);
|
|
5683
6239
|
},
|
|
5684
6240
|
...rest,
|
|
5685
|
-
children: children ?? card.pricingOptions.map((option) => /* @__PURE__ */
|
|
6241
|
+
children: children ?? card.pricingOptions.map((option) => /* @__PURE__ */ jsx17("option", { value: option.currency, children: option.currency }, option.currency))
|
|
5686
6242
|
}
|
|
5687
6243
|
);
|
|
5688
6244
|
}
|
|
@@ -5701,7 +6257,7 @@ var CardBadge = forwardRef9(function PlanSelectorCardBadge({ asChild, children,
|
|
|
5701
6257
|
}
|
|
5702
6258
|
if (!variant) return null;
|
|
5703
6259
|
const Comp = asChild ? Slot : "span";
|
|
5704
|
-
return /* @__PURE__ */
|
|
6260
|
+
return /* @__PURE__ */ jsx17(
|
|
5705
6261
|
Comp,
|
|
5706
6262
|
{
|
|
5707
6263
|
ref: forwardedRef,
|
|
@@ -5716,13 +6272,13 @@ var Loading3 = forwardRef9(function PlanSelectorLoading({ asChild, children, ...
|
|
|
5716
6272
|
const ctx = usePlanSelectorContext("Loading");
|
|
5717
6273
|
if (!ctx.loading || ctx.plans.length > 0) return null;
|
|
5718
6274
|
const Comp = asChild ? Slot : "div";
|
|
5719
|
-
return /* @__PURE__ */
|
|
6275
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-loading": "", ...rest, children });
|
|
5720
6276
|
});
|
|
5721
6277
|
var ErrorSlot3 = forwardRef9(function PlanSelectorError({ asChild, children, ...rest }, forwardedRef) {
|
|
5722
6278
|
const ctx = usePlanSelectorContext("Error");
|
|
5723
6279
|
if (!ctx.error) return null;
|
|
5724
6280
|
const Comp = asChild ? Slot : "div";
|
|
5725
|
-
return /* @__PURE__ */
|
|
6281
|
+
return /* @__PURE__ */ jsx17(Comp, { ref: forwardedRef, "data-solvapay-plan-selector-error": "", role: "alert", ...rest, children: children ?? ctx.error.message });
|
|
5726
6282
|
});
|
|
5727
6283
|
var PlanSelectorRoot2 = Root5;
|
|
5728
6284
|
var PlanSelectorHeading2 = Heading;
|
|
@@ -5755,13 +6311,13 @@ function usePlanSelector() {
|
|
|
5755
6311
|
}
|
|
5756
6312
|
|
|
5757
6313
|
// src/hooks/usePurchaseActions.ts
|
|
5758
|
-
import { useState as
|
|
6314
|
+
import { useState as useState15, useCallback as useCallback16 } from "react";
|
|
5759
6315
|
function usePurchaseActions() {
|
|
5760
6316
|
const ctx = useSolvaPay();
|
|
5761
|
-
const [isCancelling, setIsCancelling] =
|
|
5762
|
-
const [isReactivating, setIsReactivating] =
|
|
5763
|
-
const [isActivating, setIsActivating] =
|
|
5764
|
-
const cancelRenewal =
|
|
6317
|
+
const [isCancelling, setIsCancelling] = useState15(false);
|
|
6318
|
+
const [isReactivating, setIsReactivating] = useState15(false);
|
|
6319
|
+
const [isActivating, setIsActivating] = useState15(false);
|
|
6320
|
+
const cancelRenewal = useCallback16(
|
|
5765
6321
|
async (params) => {
|
|
5766
6322
|
setIsCancelling(true);
|
|
5767
6323
|
try {
|
|
@@ -5772,7 +6328,7 @@ function usePurchaseActions() {
|
|
|
5772
6328
|
},
|
|
5773
6329
|
[ctx.cancelRenewal]
|
|
5774
6330
|
);
|
|
5775
|
-
const reactivateRenewal =
|
|
6331
|
+
const reactivateRenewal = useCallback16(
|
|
5776
6332
|
async (params) => {
|
|
5777
6333
|
setIsReactivating(true);
|
|
5778
6334
|
try {
|
|
@@ -5783,7 +6339,7 @@ function usePurchaseActions() {
|
|
|
5783
6339
|
},
|
|
5784
6340
|
[ctx.reactivateRenewal]
|
|
5785
6341
|
);
|
|
5786
|
-
const activatePlan =
|
|
6342
|
+
const activatePlan = useCallback16(
|
|
5787
6343
|
async (params) => {
|
|
5788
6344
|
setIsActivating(true);
|
|
5789
6345
|
try {
|
|
@@ -5804,88 +6360,15 @@ function usePurchaseActions() {
|
|
|
5804
6360
|
};
|
|
5805
6361
|
}
|
|
5806
6362
|
|
|
5807
|
-
// src/primitives/CancelPlanButton.tsx
|
|
5808
|
-
import { countsUsage } from "@solvapay/core";
|
|
5809
|
-
import { forwardRef as forwardRef10, useCallback as useCallback16, useContext as useContext13 } from "react";
|
|
5810
|
-
import { Fragment as Fragment9, jsx as jsx17 } from "react/jsx-runtime";
|
|
5811
|
-
function resolveConfirmText(confirm, purchase, defaults) {
|
|
5812
|
-
if (confirm === false) return null;
|
|
5813
|
-
if (typeof confirm === "string") return confirm;
|
|
5814
|
-
const isUsageBased = (countsUsage(purchase?.planSnapshot) || purchase?.planSnapshot?.isMetered === true) && purchase?.isRecurring !== true;
|
|
5815
|
-
if (isUsageBased) return defaults.usageBased;
|
|
5816
|
-
return defaults.recurring;
|
|
5817
|
-
}
|
|
5818
|
-
var CancelPlanButton = forwardRef10(
|
|
5819
|
-
function CancelPlanButton2({
|
|
5820
|
-
asChild,
|
|
5821
|
-
purchaseRef,
|
|
5822
|
-
reason,
|
|
5823
|
-
confirm = true,
|
|
5824
|
-
onCancelled,
|
|
5825
|
-
onError,
|
|
5826
|
-
onClick,
|
|
5827
|
-
children,
|
|
5828
|
-
...rest
|
|
5829
|
-
}, forwardedRef) {
|
|
5830
|
-
const solva = useContext13(SolvaPayContext);
|
|
5831
|
-
if (!solva) throw new MissingProviderError("CancelPlanButton");
|
|
5832
|
-
const copy = useCopy();
|
|
5833
|
-
const { activePurchase } = usePurchase();
|
|
5834
|
-
const { cancelRenewal, isCancelling } = usePurchaseActions();
|
|
5835
|
-
const effectivePurchase = purchaseRef ? activePurchase && activePurchase.reference === purchaseRef ? activePurchase : { reference: purchaseRef } : activePurchase;
|
|
5836
|
-
const effectiveRef = purchaseRef ?? effectivePurchase?.reference;
|
|
5837
|
-
const cancel = useCallback16(async () => {
|
|
5838
|
-
if (!effectiveRef) return;
|
|
5839
|
-
const confirmText = resolveConfirmText(confirm, effectivePurchase, {
|
|
5840
|
-
recurring: copy.cancelPlan.confirmRecurring,
|
|
5841
|
-
usageBased: copy.cancelPlan.confirmUsageBased
|
|
5842
|
-
});
|
|
5843
|
-
if (confirmText && typeof window !== "undefined" && !window.confirm(confirmText)) {
|
|
5844
|
-
return;
|
|
5845
|
-
}
|
|
5846
|
-
try {
|
|
5847
|
-
await cancelRenewal({ purchaseRef: effectiveRef, reason });
|
|
5848
|
-
onCancelled?.();
|
|
5849
|
-
} catch (err) {
|
|
5850
|
-
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
5851
|
-
}
|
|
5852
|
-
}, [effectiveRef, effectivePurchase, confirm, copy, cancelRenewal, reason, onCancelled, onError]);
|
|
5853
|
-
if (effectivePurchase?.status === "active" && effectivePurchase.cancelledAt) {
|
|
5854
|
-
return null;
|
|
5855
|
-
}
|
|
5856
|
-
const disabled = isCancelling || !effectiveRef;
|
|
5857
|
-
const state = isCancelling ? "cancelling" : "idle";
|
|
5858
|
-
const commonProps = {
|
|
5859
|
-
"data-solvapay-cancel-plan": "",
|
|
5860
|
-
"data-state": state,
|
|
5861
|
-
"aria-busy": isCancelling,
|
|
5862
|
-
"aria-disabled": disabled || void 0,
|
|
5863
|
-
disabled,
|
|
5864
|
-
onClick: composeEventHandlers(onClick, () => {
|
|
5865
|
-
void cancel();
|
|
5866
|
-
}),
|
|
5867
|
-
...rest
|
|
5868
|
-
};
|
|
5869
|
-
const label = isCancelling ? copy.cancelPlan.buttonLoading : copy.cancelPlan.button;
|
|
5870
|
-
if (asChild) {
|
|
5871
|
-
return (
|
|
5872
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5873
|
-
/* @__PURE__ */ jsx17(Slot, { ref: forwardedRef, ...commonProps, children: children ?? /* @__PURE__ */ jsx17(Fragment9, { children: label }) })
|
|
5874
|
-
);
|
|
5875
|
-
}
|
|
5876
|
-
return /* @__PURE__ */ jsx17("button", { ref: forwardedRef, type: "button", ...commonProps, children: children ?? label });
|
|
5877
|
-
}
|
|
5878
|
-
);
|
|
5879
|
-
|
|
5880
6363
|
// src/hooks/usePurchaseStatus.ts
|
|
5881
|
-
import { useMemo as
|
|
6364
|
+
import { useMemo as useMemo12, useCallback as useCallback17 } from "react";
|
|
5882
6365
|
function usePurchaseStatus() {
|
|
5883
6366
|
const { purchases } = usePurchase();
|
|
5884
6367
|
const locale = useLocale();
|
|
5885
6368
|
const isPaidPurchase2 = useCallback17((p) => {
|
|
5886
6369
|
return (p.amount ?? 0) > 0;
|
|
5887
6370
|
}, []);
|
|
5888
|
-
const purchaseData =
|
|
6371
|
+
const purchaseData = useMemo12(() => {
|
|
5889
6372
|
const cancelledPaidPurchases = purchases.filter((p) => {
|
|
5890
6373
|
return p.status === "active" && p.cancelledAt && isPaidPurchase2(p) && isPlanPurchase(p);
|
|
5891
6374
|
});
|
|
@@ -5927,14 +6410,14 @@ function usePurchaseStatus() {
|
|
|
5927
6410
|
|
|
5928
6411
|
// src/primitives/CancelledPlanNotice.tsx
|
|
5929
6412
|
import {
|
|
5930
|
-
createContext as
|
|
5931
|
-
forwardRef as
|
|
6413
|
+
createContext as createContext10,
|
|
6414
|
+
forwardRef as forwardRef10,
|
|
5932
6415
|
useCallback as useCallback18,
|
|
5933
6416
|
useContext as useContext14,
|
|
5934
|
-
useMemo as
|
|
6417
|
+
useMemo as useMemo13
|
|
5935
6418
|
} from "react";
|
|
5936
|
-
import { Fragment as
|
|
5937
|
-
var CancelledPlanNoticeContext =
|
|
6419
|
+
import { Fragment as Fragment9, jsx as jsx18 } from "react/jsx-runtime";
|
|
6420
|
+
var CancelledPlanNoticeContext = createContext10(null);
|
|
5938
6421
|
function useNoticeCtx(part) {
|
|
5939
6422
|
const ctx = useContext14(CancelledPlanNoticeContext);
|
|
5940
6423
|
if (!ctx) {
|
|
@@ -5944,7 +6427,7 @@ function useNoticeCtx(part) {
|
|
|
5944
6427
|
}
|
|
5945
6428
|
return ctx;
|
|
5946
6429
|
}
|
|
5947
|
-
var Root6 =
|
|
6430
|
+
var Root6 = forwardRef10(function CancelledPlanNoticeRoot({ onReactivated, onError, asChild, children, ...rest }, forwardedRef) {
|
|
5948
6431
|
const solva = useContext14(SolvaPayContext);
|
|
5949
6432
|
if (!solva) throw new MissingProviderError("CancelledPlanNotice");
|
|
5950
6433
|
const {
|
|
@@ -5963,11 +6446,11 @@ var Root6 = forwardRef11(function CancelledPlanNoticeRoot({ onReactivated, onErr
|
|
|
5963
6446
|
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
5964
6447
|
}
|
|
5965
6448
|
}, [cancelledPurchase, reactivateRenewal, onReactivated, onError]);
|
|
5966
|
-
const daysRemaining =
|
|
6449
|
+
const daysRemaining = useMemo13(
|
|
5967
6450
|
() => cancelledPurchase ? getDaysUntilExpiration(cancelledPurchase.endDate) : null,
|
|
5968
6451
|
[cancelledPurchase, getDaysUntilExpiration]
|
|
5969
6452
|
);
|
|
5970
|
-
const ctx =
|
|
6453
|
+
const ctx = useMemo13(() => {
|
|
5971
6454
|
if (!cancelledPurchase) return null;
|
|
5972
6455
|
const state = daysRemaining != null && daysRemaining > 0 ? "active" : "expired";
|
|
5973
6456
|
return {
|
|
@@ -5994,13 +6477,13 @@ var Root6 = forwardRef11(function CancelledPlanNoticeRoot({ onReactivated, onErr
|
|
|
5994
6477
|
}
|
|
5995
6478
|
) });
|
|
5996
6479
|
});
|
|
5997
|
-
var Heading2 =
|
|
6480
|
+
var Heading2 = forwardRef10(function CancelledPlanNoticeHeading({ asChild, children, ...rest }, forwardedRef) {
|
|
5998
6481
|
useNoticeCtx("Heading");
|
|
5999
6482
|
const copy = useCopy();
|
|
6000
6483
|
const Comp = asChild ? Slot : "p";
|
|
6001
6484
|
return /* @__PURE__ */ jsx18(Comp, { ref: forwardedRef, "data-solvapay-cancelled-notice-heading": "", ...rest, children: children ?? copy.cancelledNotice.heading });
|
|
6002
6485
|
});
|
|
6003
|
-
var Expires =
|
|
6486
|
+
var Expires = forwardRef10(function CancelledPlanNoticeExpires({ asChild, children, ...rest }, forwardedRef) {
|
|
6004
6487
|
const ctx = useNoticeCtx("Expires");
|
|
6005
6488
|
const copy = useCopy();
|
|
6006
6489
|
const date = ctx.formatDate(ctx.purchase.endDate);
|
|
@@ -6011,7 +6494,7 @@ var Expires = forwardRef11(function CancelledPlanNoticeExpires({ asChild, childr
|
|
|
6011
6494
|
const Comp = asChild ? Slot : "p";
|
|
6012
6495
|
return /* @__PURE__ */ jsx18(Comp, { ref: forwardedRef, "data-solvapay-cancelled-notice-expires": "", ...rest, children: children ?? interpolate(copy.cancelledNotice.expiresLabel, { date: date ?? "" }) });
|
|
6013
6496
|
});
|
|
6014
|
-
var DaysRemaining =
|
|
6497
|
+
var DaysRemaining = forwardRef10(
|
|
6015
6498
|
function CancelledPlanNoticeDaysRemaining({ asChild, children, ...rest }, forwardedRef) {
|
|
6016
6499
|
const ctx = useNoticeCtx("DaysRemaining");
|
|
6017
6500
|
const copy = useCopy();
|
|
@@ -6021,7 +6504,7 @@ var DaysRemaining = forwardRef11(
|
|
|
6021
6504
|
return /* @__PURE__ */ jsx18(Comp, { ref: forwardedRef, "data-solvapay-cancelled-notice-days-remaining": "", ...rest, children: children ?? interpolate(template, { days: ctx.daysRemaining }) });
|
|
6022
6505
|
}
|
|
6023
6506
|
);
|
|
6024
|
-
var AccessUntil =
|
|
6507
|
+
var AccessUntil = forwardRef10(
|
|
6025
6508
|
function CancelledPlanNoticeAccessUntil({ asChild, children, ...rest }, forwardedRef) {
|
|
6026
6509
|
const ctx = useNoticeCtx("AccessUntil");
|
|
6027
6510
|
const copy = useCopy();
|
|
@@ -6032,7 +6515,7 @@ var AccessUntil = forwardRef11(
|
|
|
6032
6515
|
}) });
|
|
6033
6516
|
}
|
|
6034
6517
|
);
|
|
6035
|
-
var CancelledOn =
|
|
6518
|
+
var CancelledOn = forwardRef10(
|
|
6036
6519
|
function CancelledPlanNoticeCancelledOn({ asChild, children, ...rest }, forwardedRef) {
|
|
6037
6520
|
const ctx = useNoticeCtx("CancelledOn");
|
|
6038
6521
|
const copy = useCopy();
|
|
@@ -6042,13 +6525,13 @@ var CancelledOn = forwardRef11(
|
|
|
6042
6525
|
return /* @__PURE__ */ jsx18(Comp, { ref: forwardedRef, "data-solvapay-cancelled-notice-cancelled-on": "", ...rest, children: children ?? interpolate(copy.cancelledNotice.cancelledOn, { date: date ?? "" }) });
|
|
6043
6526
|
}
|
|
6044
6527
|
);
|
|
6045
|
-
var Reason =
|
|
6528
|
+
var Reason = forwardRef10(function CancelledPlanNoticeReason({ asChild, children, ...rest }, forwardedRef) {
|
|
6046
6529
|
const ctx = useNoticeCtx("Reason");
|
|
6047
6530
|
if (!ctx.hasReason) return null;
|
|
6048
6531
|
const Comp = asChild ? Slot : "span";
|
|
6049
6532
|
return /* @__PURE__ */ jsx18(Comp, { ref: forwardedRef, "data-solvapay-cancelled-notice-reason": "", ...rest, children: children ?? ctx.purchase.cancellationReason });
|
|
6050
6533
|
});
|
|
6051
|
-
var ReactivateButton =
|
|
6534
|
+
var ReactivateButton = forwardRef10(
|
|
6052
6535
|
function CancelledPlanNoticeReactivateButton({ asChild, onClick, children, ...rest }, forwardedRef) {
|
|
6053
6536
|
const ctx = useNoticeCtx("ReactivateButton");
|
|
6054
6537
|
const copy = useCopy();
|
|
@@ -6068,7 +6551,7 @@ var ReactivateButton = forwardRef11(
|
|
|
6068
6551
|
if (asChild) {
|
|
6069
6552
|
return (
|
|
6070
6553
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6071
|
-
/* @__PURE__ */ jsx18(Slot, { ref: forwardedRef, ...commonProps, children: children ?? /* @__PURE__ */ jsx18(
|
|
6554
|
+
/* @__PURE__ */ jsx18(Slot, { ref: forwardedRef, ...commonProps, children: children ?? /* @__PURE__ */ jsx18(Fragment9, { children: label }) })
|
|
6072
6555
|
);
|
|
6073
6556
|
}
|
|
6074
6557
|
return /* @__PURE__ */ jsx18("button", { ref: forwardedRef, type: "button", ...commonProps, children: children ?? label });
|
|
@@ -6097,14 +6580,14 @@ function useCancelledPlanNotice() {
|
|
|
6097
6580
|
}
|
|
6098
6581
|
|
|
6099
6582
|
// src/hooks/useTransport.ts
|
|
6100
|
-
import { useMemo as
|
|
6583
|
+
import { useMemo as useMemo14 } from "react";
|
|
6101
6584
|
function useTransport() {
|
|
6102
6585
|
const { _config } = useSolvaPay();
|
|
6103
|
-
return
|
|
6586
|
+
return useMemo14(() => _config?.transport ?? createHttpTransport(_config), [_config]);
|
|
6104
6587
|
}
|
|
6105
6588
|
|
|
6106
6589
|
// src/hooks/useLimits.ts
|
|
6107
|
-
import { useCallback as useCallback19, useEffect as
|
|
6590
|
+
import { useCallback as useCallback19, useEffect as useEffect13, useRef as useRef9, useState as useState16 } from "react";
|
|
6108
6591
|
var CACHE_TTL_MS = 1e4;
|
|
6109
6592
|
var OPTIMISTIC_GRACE_MS = 8e3;
|
|
6110
6593
|
var limitsCache = /* @__PURE__ */ new Map();
|
|
@@ -6121,13 +6604,13 @@ function useLimits(options) {
|
|
|
6121
6604
|
const { customerRef } = useCustomer();
|
|
6122
6605
|
const { purchase } = useSolvaPay();
|
|
6123
6606
|
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName2);
|
|
6124
|
-
const [data, setData] =
|
|
6607
|
+
const [data, setData] = useState16(() => {
|
|
6125
6608
|
if (!currentKey) return null;
|
|
6126
6609
|
const cached = limitsCache.get(currentKey);
|
|
6127
6610
|
if (!cached || Date.now() - cached.timestamp >= CACHE_TTL_MS) return null;
|
|
6128
6611
|
return cached.data;
|
|
6129
6612
|
});
|
|
6130
|
-
const [loading, setLoading] =
|
|
6613
|
+
const [loading, setLoading] = useState16(() => {
|
|
6131
6614
|
if (!currentKey) return false;
|
|
6132
6615
|
const cached = limitsCache.get(currentKey);
|
|
6133
6616
|
if (!cached) return true;
|
|
@@ -6135,8 +6618,8 @@ function useLimits(options) {
|
|
|
6135
6618
|
if (Date.now() - cached.timestamp >= CACHE_TTL_MS) return true;
|
|
6136
6619
|
return false;
|
|
6137
6620
|
});
|
|
6138
|
-
const [error, setError] =
|
|
6139
|
-
const [trackedKey, setTrackedKey] =
|
|
6621
|
+
const [error, setError] = useState16(null);
|
|
6622
|
+
const [trackedKey, setTrackedKey] = useState16(currentKey);
|
|
6140
6623
|
if (trackedKey !== currentKey) {
|
|
6141
6624
|
setTrackedKey(currentKey);
|
|
6142
6625
|
setData(null);
|
|
@@ -6144,10 +6627,10 @@ function useLimits(options) {
|
|
|
6144
6627
|
const unlimited = data === null ? null : isUnlimited(data.remaining);
|
|
6145
6628
|
const optimisticTimerRef = useRef9(null);
|
|
6146
6629
|
const unlimitedRef = useRef9(false);
|
|
6147
|
-
|
|
6630
|
+
useEffect13(() => {
|
|
6148
6631
|
unlimitedRef.current = unlimited === true;
|
|
6149
6632
|
}, [unlimited]);
|
|
6150
|
-
|
|
6633
|
+
useEffect13(() => {
|
|
6151
6634
|
return () => {
|
|
6152
6635
|
if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
|
|
6153
6636
|
};
|
|
@@ -6171,7 +6654,18 @@ function useLimits(options) {
|
|
|
6171
6654
|
);
|
|
6172
6655
|
const fetchLimits = useCallback19(
|
|
6173
6656
|
async (force) => {
|
|
6174
|
-
if (!productRef || !enabled
|
|
6657
|
+
if (!productRef || !enabled) {
|
|
6658
|
+
setLoading(false);
|
|
6659
|
+
return;
|
|
6660
|
+
}
|
|
6661
|
+
if (!transport.getLimits) {
|
|
6662
|
+
const seeded = limitsCache.get(cacheKey(customerRef, productRef, meterName2));
|
|
6663
|
+
if (seeded?.data) {
|
|
6664
|
+
setData(seeded.data);
|
|
6665
|
+
setLoading(false);
|
|
6666
|
+
setError(null);
|
|
6667
|
+
return;
|
|
6668
|
+
}
|
|
6175
6669
|
setLoading(false);
|
|
6176
6670
|
return;
|
|
6177
6671
|
}
|
|
@@ -6199,11 +6693,11 @@ function useLimits(options) {
|
|
|
6199
6693
|
},
|
|
6200
6694
|
[transport, customerRef, productRef, meterName2, enabled, attachToFetch]
|
|
6201
6695
|
);
|
|
6202
|
-
|
|
6696
|
+
useEffect13(() => {
|
|
6203
6697
|
fetchLimits(false);
|
|
6204
6698
|
}, [fetchLimits]);
|
|
6205
6699
|
const prevPurchasesRef = useRef9(null);
|
|
6206
|
-
|
|
6700
|
+
useEffect13(() => {
|
|
6207
6701
|
if (prevPurchasesRef.current !== null && prevPurchasesRef.current !== purchase.purchases) {
|
|
6208
6702
|
fetchLimits(true).catch(() => {
|
|
6209
6703
|
});
|
|
@@ -6222,7 +6716,10 @@ function useLimits(options) {
|
|
|
6222
6716
|
if (!baseline) return prev;
|
|
6223
6717
|
const next = {
|
|
6224
6718
|
...baseline,
|
|
6225
|
-
remaining: Math.max(0, baseline.remaining + delta)
|
|
6719
|
+
remaining: Math.max(0, baseline.remaining + delta),
|
|
6720
|
+
// Keep `used` self-consistent with the remaining nudge so
|
|
6721
|
+
// a meter that reads both does not flash a collapsing cap.
|
|
6722
|
+
...typeof baseline.used === "number" ? { used: Math.max(0, baseline.used - delta) } : {}
|
|
6226
6723
|
// Don't optimistically flip `withinLimits` — paywall gating
|
|
6227
6724
|
// can hinge on factors beyond `remaining > 0`
|
|
6228
6725
|
// (activationRequired, etc.). Let the trailing refetch
|
|
@@ -6255,6 +6752,8 @@ function useLimits(options) {
|
|
|
6255
6752
|
needsTopUp: data?.needsTopUp ?? null,
|
|
6256
6753
|
needsUpgrade: data?.needsUpgrade ?? null,
|
|
6257
6754
|
upgraded: data?.upgraded ?? null,
|
|
6755
|
+
used: data?.used ?? null,
|
|
6756
|
+
limit: data?.limit ?? null,
|
|
6258
6757
|
loading,
|
|
6259
6758
|
error,
|
|
6260
6759
|
refetch,
|
|
@@ -6263,18 +6762,24 @@ function useLimits(options) {
|
|
|
6263
6762
|
}
|
|
6264
6763
|
|
|
6265
6764
|
// src/hooks/useUsage.ts
|
|
6266
|
-
import { countsUsage
|
|
6267
|
-
import { useCallback as useCallback20, useEffect as
|
|
6765
|
+
import { countsUsage } from "@solvapay/core";
|
|
6766
|
+
import { useCallback as useCallback20, useEffect as useEffect14, useMemo as useMemo15, useState as useState17 } from "react";
|
|
6767
|
+
var seededUsage = null;
|
|
6768
|
+
var usageSeedGeneration = 0;
|
|
6769
|
+
function seedUsageSnapshot(usage) {
|
|
6770
|
+
seededUsage = usage;
|
|
6771
|
+
usageSeedGeneration += 1;
|
|
6772
|
+
}
|
|
6268
6773
|
function deriveUsage(purchase, limits) {
|
|
6269
6774
|
if (!purchase) return null;
|
|
6270
6775
|
const usage = purchase.usage;
|
|
6271
|
-
if (!
|
|
6776
|
+
if (!countsUsage(purchase.planSnapshot) && purchase.planSnapshot?.isMetered !== true && !usage) {
|
|
6272
6777
|
return null;
|
|
6273
6778
|
}
|
|
6274
|
-
const used = typeof usage?.used === "number" ? usage.used : 0;
|
|
6275
6779
|
const hasFiniteCap = limits.unlimited === false && limits.remaining !== null;
|
|
6276
6780
|
const remaining = hasFiniteCap ? limits.remaining : null;
|
|
6277
|
-
const total =
|
|
6781
|
+
const total = typeof limits.limit === "number" && limits.limit > 0 ? limits.limit : null;
|
|
6782
|
+
const used = typeof limits.used === "number" ? limits.used : total !== null && remaining !== null ? Math.max(0, total - remaining) : typeof usage?.used === "number" ? usage.used : 0;
|
|
6278
6783
|
const percentUsed = total !== null && total > 0 ? Math.min(100, Math.round(used / total * 1e4) / 100) : null;
|
|
6279
6784
|
return {
|
|
6280
6785
|
meterRef: limits.meterName,
|
|
@@ -6290,25 +6795,38 @@ function deriveUsage(purchase, limits) {
|
|
|
6290
6795
|
function useUsage() {
|
|
6291
6796
|
const { activePurchase, refetch: refetchPurchase, loading: purchaseLoading } = usePurchase();
|
|
6292
6797
|
const transport = useTransport();
|
|
6293
|
-
const [override, setOverride] =
|
|
6294
|
-
const [
|
|
6295
|
-
const [
|
|
6296
|
-
const
|
|
6798
|
+
const [override, setOverride] = useState17(() => seededUsage);
|
|
6799
|
+
const [seedGeneration, setSeedGeneration] = useState17(usageSeedGeneration);
|
|
6800
|
+
const [error, setError] = useState17(null);
|
|
6801
|
+
const [transportLoading, setTransportLoading] = useState17(false);
|
|
6802
|
+
if (seedGeneration !== usageSeedGeneration) {
|
|
6803
|
+
setSeedGeneration(usageSeedGeneration);
|
|
6804
|
+
setOverride(seededUsage);
|
|
6805
|
+
}
|
|
6806
|
+
const usageCounted = countsUsage(activePurchase?.planSnapshot) || activePurchase?.planSnapshot?.isMetered === true;
|
|
6297
6807
|
const {
|
|
6298
6808
|
remaining: limitRemaining,
|
|
6299
6809
|
unlimited,
|
|
6300
|
-
meterName: meterName2
|
|
6810
|
+
meterName: meterName2,
|
|
6811
|
+
used: limitUsed,
|
|
6812
|
+
limit
|
|
6301
6813
|
} = useLimits({
|
|
6302
6814
|
productRef: activePurchase?.productRef,
|
|
6303
6815
|
enabled: usageCounted
|
|
6304
6816
|
});
|
|
6305
|
-
const derived =
|
|
6306
|
-
() => deriveUsage(activePurchase ?? null, {
|
|
6307
|
-
|
|
6817
|
+
const derived = useMemo15(
|
|
6818
|
+
() => deriveUsage(activePurchase ?? null, {
|
|
6819
|
+
remaining: limitRemaining,
|
|
6820
|
+
unlimited,
|
|
6821
|
+
meterName: meterName2,
|
|
6822
|
+
used: limitUsed,
|
|
6823
|
+
limit
|
|
6824
|
+
}),
|
|
6825
|
+
[activePurchase, limitRemaining, unlimited, meterName2, limitUsed, limit]
|
|
6308
6826
|
);
|
|
6309
6827
|
const activePurchaseRef = activePurchase?.reference ?? null;
|
|
6310
|
-
|
|
6311
|
-
setOverride(
|
|
6828
|
+
useEffect14(() => {
|
|
6829
|
+
setOverride(seededUsage);
|
|
6312
6830
|
}, [activePurchaseRef]);
|
|
6313
6831
|
const usage = override ?? derived;
|
|
6314
6832
|
const refetch = useCallback20(async () => {
|
|
@@ -6349,9 +6867,9 @@ function useUsage() {
|
|
|
6349
6867
|
}
|
|
6350
6868
|
|
|
6351
6869
|
// src/primitives/UsageMeter.tsx
|
|
6352
|
-
import { createContext as
|
|
6870
|
+
import { createContext as createContext11, forwardRef as forwardRef11, useContext as useContext15, useMemo as useMemo16 } from "react";
|
|
6353
6871
|
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
6354
|
-
var UsageMeterContext =
|
|
6872
|
+
var UsageMeterContext = createContext11(null);
|
|
6355
6873
|
function useUsageMeterCtx(part) {
|
|
6356
6874
|
const ctx = useContext15(UsageMeterContext);
|
|
6357
6875
|
if (!ctx) {
|
|
@@ -6359,7 +6877,7 @@ function useUsageMeterCtx(part) {
|
|
|
6359
6877
|
}
|
|
6360
6878
|
return ctx;
|
|
6361
6879
|
}
|
|
6362
|
-
var Root7 =
|
|
6880
|
+
var Root7 = forwardRef11(function UsageMeterRoot({
|
|
6363
6881
|
warningAt = 75,
|
|
6364
6882
|
criticalAt = 90,
|
|
6365
6883
|
classNames,
|
|
@@ -6374,7 +6892,7 @@ var Root7 = forwardRef12(function UsageMeterRoot({
|
|
|
6374
6892
|
const loading = hookResult.loading && !usage;
|
|
6375
6893
|
const percentUsed = usage?.percentUsed ?? null;
|
|
6376
6894
|
const state = loading ? "loading" : percentUsed === null ? "safe" : percentUsed >= criticalAt ? "critical" : percentUsed >= warningAt ? "warning" : "safe";
|
|
6377
|
-
const ctx =
|
|
6895
|
+
const ctx = useMemo16(
|
|
6378
6896
|
() => ({
|
|
6379
6897
|
usage,
|
|
6380
6898
|
loading,
|
|
@@ -6414,7 +6932,7 @@ var Root7 = forwardRef12(function UsageMeterRoot({
|
|
|
6414
6932
|
}
|
|
6415
6933
|
) });
|
|
6416
6934
|
});
|
|
6417
|
-
var Bar =
|
|
6935
|
+
var Bar = forwardRef11(function UsageMeterBar({ className, style, ...rest }, forwardedRef) {
|
|
6418
6936
|
const ctx = useUsageMeterCtx("Bar");
|
|
6419
6937
|
const width = ctx.percentUsed === null ? 0 : Math.max(0, Math.min(100, ctx.percentUsed));
|
|
6420
6938
|
return /* @__PURE__ */ jsx19(
|
|
@@ -6438,7 +6956,7 @@ var Bar = forwardRef12(function UsageMeterBar({ className, style, ...rest }, for
|
|
|
6438
6956
|
}
|
|
6439
6957
|
);
|
|
6440
6958
|
});
|
|
6441
|
-
var Label =
|
|
6959
|
+
var Label = forwardRef11(function UsageMeterLabel({ className, children, ...rest }, forwardedRef) {
|
|
6442
6960
|
const ctx = useUsageMeterCtx("Label");
|
|
6443
6961
|
const copy = useCopy();
|
|
6444
6962
|
if (!ctx.usage) return null;
|
|
@@ -6474,7 +6992,7 @@ var Label = forwardRef12(function UsageMeterLabel({ className, children, ...rest
|
|
|
6474
6992
|
}
|
|
6475
6993
|
);
|
|
6476
6994
|
});
|
|
6477
|
-
var Percentage =
|
|
6995
|
+
var Percentage = forwardRef11(function UsageMeterPercentage({ className, children, ...rest }, forwardedRef) {
|
|
6478
6996
|
const ctx = useUsageMeterCtx("Percentage");
|
|
6479
6997
|
const copy = useCopy();
|
|
6480
6998
|
if (ctx.percentUsed === null) return null;
|
|
@@ -6495,7 +7013,7 @@ function formatResetsIn(copy, periodEnd, nowMs = typeof performance !== "undefin
|
|
|
6495
7013
|
const daysLeft = Math.max(0, Math.ceil((end - nowMs) / (24 * 60 * 60 * 1e3)));
|
|
6496
7014
|
return daysLeft > 0 ? interpolate(copy.usage.resetsInLabel, { days: String(daysLeft) }) : interpolate(copy.usage.resetsOnLabel, { date: new Date(periodEnd).toLocaleDateString() });
|
|
6497
7015
|
}
|
|
6498
|
-
var ResetsIn =
|
|
7016
|
+
var ResetsIn = forwardRef11(function UsageMeterResetsIn({ className, children, ...rest }, forwardedRef) {
|
|
6499
7017
|
const ctx = useUsageMeterCtx("ResetsIn");
|
|
6500
7018
|
const copy = useCopy();
|
|
6501
7019
|
const periodEnd = ctx.usage?.periodEnd;
|
|
@@ -6513,7 +7031,7 @@ var ResetsIn = forwardRef12(function UsageMeterResetsIn({ className, children, .
|
|
|
6513
7031
|
}
|
|
6514
7032
|
);
|
|
6515
7033
|
});
|
|
6516
|
-
var Loading4 =
|
|
7034
|
+
var Loading4 = forwardRef11(function UsageMeterLoading({ className, children, ...rest }, forwardedRef) {
|
|
6517
7035
|
const ctx = useUsageMeterCtx("Loading");
|
|
6518
7036
|
const copy = useCopy();
|
|
6519
7037
|
if (ctx.state !== "loading") return null;
|
|
@@ -6529,7 +7047,7 @@ var Loading4 = forwardRef12(function UsageMeterLoading({ className, children, ..
|
|
|
6529
7047
|
}
|
|
6530
7048
|
);
|
|
6531
7049
|
});
|
|
6532
|
-
var Empty =
|
|
7050
|
+
var Empty = forwardRef11(function UsageMeterEmpty({ className, children, ...rest }, forwardedRef) {
|
|
6533
7051
|
const ctx = useUsageMeterCtx("Empty");
|
|
6534
7052
|
const copy = useCopy();
|
|
6535
7053
|
if (ctx.loading || ctx.usage !== null) return null;
|
|
@@ -6557,8 +7075,488 @@ function useUsageMeter() {
|
|
|
6557
7075
|
return useUsageMeterCtx("useUsageMeter");
|
|
6558
7076
|
}
|
|
6559
7077
|
|
|
7078
|
+
// src/hooks/useAutoRecharge.ts
|
|
7079
|
+
import { useCallback as useCallback21, useEffect as useEffect15, useRef as useRef10, useState as useState18 } from "react";
|
|
7080
|
+
function mergeAutoRechargeConfig(config, display) {
|
|
7081
|
+
return display ? { ...config, display } : config;
|
|
7082
|
+
}
|
|
7083
|
+
async function fetchAutoRecharge(config) {
|
|
7084
|
+
const transport = config?.transport ?? createHttpTransport(config);
|
|
7085
|
+
if (!transport.getAutoRecharge) return null;
|
|
7086
|
+
const response = await transport.getAutoRecharge();
|
|
7087
|
+
if (!response.config) return null;
|
|
7088
|
+
return mergeAutoRechargeConfig(response.config, response.display);
|
|
7089
|
+
}
|
|
7090
|
+
function useAutoRecharge() {
|
|
7091
|
+
const { _config } = useSolvaPay();
|
|
7092
|
+
const key = autoRechargeCacheKeyFor(_config);
|
|
7093
|
+
const [config, setConfig] = useState18(
|
|
7094
|
+
() => autoRechargeCache.get(key)?.config ?? null
|
|
7095
|
+
);
|
|
7096
|
+
const [loading, setLoading] = useState18(() => {
|
|
7097
|
+
const cached = autoRechargeCache.get(key);
|
|
7098
|
+
return !cached || !cached.config && !cached.promise;
|
|
7099
|
+
});
|
|
7100
|
+
const [saving, setSaving] = useState18(false);
|
|
7101
|
+
const [disabling, setDisabling] = useState18(false);
|
|
7102
|
+
const [error, setError] = useState18(null);
|
|
7103
|
+
const requestSeq = useRef10(0);
|
|
7104
|
+
const load = useCallback21(
|
|
7105
|
+
async (force = false) => {
|
|
7106
|
+
const seq = requestSeq.current;
|
|
7107
|
+
const cached = autoRechargeCache.get(key);
|
|
7108
|
+
const now = Date.now();
|
|
7109
|
+
if (!force && cached?.config && now - cached.timestamp < CACHE_DURATION2) {
|
|
7110
|
+
if (seq !== requestSeq.current) return;
|
|
7111
|
+
setConfig(cached.config);
|
|
7112
|
+
setLoading(false);
|
|
7113
|
+
setError(null);
|
|
7114
|
+
return;
|
|
7115
|
+
}
|
|
7116
|
+
if (!force && cached?.promise) {
|
|
7117
|
+
setLoading(true);
|
|
7118
|
+
try {
|
|
7119
|
+
const value = await cached.promise;
|
|
7120
|
+
if (seq !== requestSeq.current) return;
|
|
7121
|
+
setConfig(value);
|
|
7122
|
+
setError(null);
|
|
7123
|
+
} catch (caught) {
|
|
7124
|
+
if (seq !== requestSeq.current) return;
|
|
7125
|
+
setError(caught instanceof Error ? caught : new Error(String(caught)));
|
|
7126
|
+
} finally {
|
|
7127
|
+
if (seq === requestSeq.current) {
|
|
7128
|
+
setLoading(false);
|
|
7129
|
+
}
|
|
7130
|
+
}
|
|
7131
|
+
return;
|
|
7132
|
+
}
|
|
7133
|
+
setLoading(true);
|
|
7134
|
+
setError(null);
|
|
7135
|
+
const promise = fetchAutoRecharge(_config);
|
|
7136
|
+
writeAutoRechargeCache(key, {
|
|
7137
|
+
config: cached?.config ?? null,
|
|
7138
|
+
promise,
|
|
7139
|
+
timestamp: now
|
|
7140
|
+
});
|
|
7141
|
+
try {
|
|
7142
|
+
const value = await promise;
|
|
7143
|
+
if (seq !== requestSeq.current) return;
|
|
7144
|
+
writeAutoRechargeCache(key, { config: value, promise: null, timestamp: Date.now() });
|
|
7145
|
+
setConfig(value);
|
|
7146
|
+
} catch (caught) {
|
|
7147
|
+
if (seq !== requestSeq.current) return;
|
|
7148
|
+
const err = caught instanceof Error ? caught : new Error(String(caught));
|
|
7149
|
+
writeAutoRechargeCache(key, {
|
|
7150
|
+
config: cached?.config ?? null,
|
|
7151
|
+
promise: null,
|
|
7152
|
+
timestamp: Date.now()
|
|
7153
|
+
});
|
|
7154
|
+
setError(err);
|
|
7155
|
+
} finally {
|
|
7156
|
+
if (seq === requestSeq.current) {
|
|
7157
|
+
setLoading(false);
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
},
|
|
7161
|
+
[_config, key]
|
|
7162
|
+
);
|
|
7163
|
+
useEffect15(() => {
|
|
7164
|
+
void load();
|
|
7165
|
+
}, [load]);
|
|
7166
|
+
useEffect15(() => {
|
|
7167
|
+
return subscribeAutoRecharge(key, () => {
|
|
7168
|
+
const cached = autoRechargeCache.get(key);
|
|
7169
|
+
if (cached) {
|
|
7170
|
+
setConfig(cached.config);
|
|
7171
|
+
return;
|
|
7172
|
+
}
|
|
7173
|
+
void load(true);
|
|
7174
|
+
});
|
|
7175
|
+
}, [key, load]);
|
|
7176
|
+
const refresh = useCallback21(
|
|
7177
|
+
async (force = true) => {
|
|
7178
|
+
await load(force);
|
|
7179
|
+
},
|
|
7180
|
+
[load]
|
|
7181
|
+
);
|
|
7182
|
+
const save = useCallback21(
|
|
7183
|
+
async (input) => {
|
|
7184
|
+
const transport = _config?.transport ?? createHttpTransport(_config);
|
|
7185
|
+
if (!transport.saveAutoRecharge) {
|
|
7186
|
+
throw new Error("saveAutoRecharge is not available on this transport");
|
|
7187
|
+
}
|
|
7188
|
+
setSaving(true);
|
|
7189
|
+
setError(null);
|
|
7190
|
+
const seq = ++requestSeq.current;
|
|
7191
|
+
try {
|
|
7192
|
+
const result = await transport.saveAutoRecharge(input);
|
|
7193
|
+
if (seq !== requestSeq.current) return result;
|
|
7194
|
+
const nextConfig = mergeAutoRechargeConfig(result.config, result.display);
|
|
7195
|
+
writeAutoRechargeCache(key, {
|
|
7196
|
+
config: nextConfig,
|
|
7197
|
+
promise: null,
|
|
7198
|
+
timestamp: Date.now()
|
|
7199
|
+
});
|
|
7200
|
+
setConfig(nextConfig);
|
|
7201
|
+
return result;
|
|
7202
|
+
} catch (caught) {
|
|
7203
|
+
const err = caught instanceof Error ? caught : new Error(String(caught));
|
|
7204
|
+
setError(err);
|
|
7205
|
+
throw err;
|
|
7206
|
+
} finally {
|
|
7207
|
+
setSaving(false);
|
|
7208
|
+
}
|
|
7209
|
+
},
|
|
7210
|
+
[_config, key]
|
|
7211
|
+
);
|
|
7212
|
+
const disable = useCallback21(async () => {
|
|
7213
|
+
const transport = _config?.transport ?? createHttpTransport(_config);
|
|
7214
|
+
if (!transport.disableAutoRecharge) {
|
|
7215
|
+
throw new Error("disableAutoRecharge is not available on this transport");
|
|
7216
|
+
}
|
|
7217
|
+
setDisabling(true);
|
|
7218
|
+
setError(null);
|
|
7219
|
+
const seq = ++requestSeq.current;
|
|
7220
|
+
try {
|
|
7221
|
+
const result = await transport.disableAutoRecharge();
|
|
7222
|
+
if (seq === requestSeq.current) {
|
|
7223
|
+
setConfig((current) => {
|
|
7224
|
+
const disabledConfig = current ? { ...current, enabled: false } : null;
|
|
7225
|
+
writeAutoRechargeCache(key, {
|
|
7226
|
+
config: disabledConfig,
|
|
7227
|
+
promise: null,
|
|
7228
|
+
timestamp: Date.now()
|
|
7229
|
+
});
|
|
7230
|
+
return disabledConfig;
|
|
7231
|
+
});
|
|
7232
|
+
await refresh(true);
|
|
7233
|
+
setConfig((current) => {
|
|
7234
|
+
const disabledConfig = current ? { ...current, enabled: false } : null;
|
|
7235
|
+
writeAutoRechargeCache(key, {
|
|
7236
|
+
config: disabledConfig,
|
|
7237
|
+
promise: null,
|
|
7238
|
+
timestamp: Date.now()
|
|
7239
|
+
});
|
|
7240
|
+
return disabledConfig;
|
|
7241
|
+
});
|
|
7242
|
+
}
|
|
7243
|
+
return result;
|
|
7244
|
+
} catch (caught) {
|
|
7245
|
+
const err = caught instanceof Error ? caught : new Error(String(caught));
|
|
7246
|
+
setError(err);
|
|
7247
|
+
throw err;
|
|
7248
|
+
} finally {
|
|
7249
|
+
setDisabling(false);
|
|
7250
|
+
}
|
|
7251
|
+
}, [_config, key, refresh]);
|
|
7252
|
+
return { config, loading, saving, disabling, error, refresh, save, disable };
|
|
7253
|
+
}
|
|
7254
|
+
|
|
7255
|
+
// src/utils/credit-estimation.ts
|
|
7256
|
+
import { creditsToDisplayMinorUnits as creditsToDisplayMinorUnits2 } from "@solvapay/core";
|
|
7257
|
+
function estimateCredits(resolvedAmountMajor, currency, creditsPerMinorUnit, displayExchangeRate) {
|
|
7258
|
+
if (resolvedAmountMajor == null || resolvedAmountMajor <= 0) return null;
|
|
7259
|
+
if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
|
|
7260
|
+
const rate = displayExchangeRate ?? 1;
|
|
7261
|
+
const resolvedAmountMinor = Math.round(resolvedAmountMajor * getMinorUnitsPerMajor(currency));
|
|
7262
|
+
return Math.round(resolvedAmountMinor / rate * creditsPerMinorUnit);
|
|
7263
|
+
}
|
|
7264
|
+
function estimateCurrencyMajorFromCredits(credits, currency, creditsPerMinorUnit, displayExchangeRate) {
|
|
7265
|
+
if (credits == null || credits <= 0) return null;
|
|
7266
|
+
if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
|
|
7267
|
+
const rate = displayExchangeRate ?? 1;
|
|
7268
|
+
const displayMinor = creditsToDisplayMinorUnits2({
|
|
7269
|
+
credits,
|
|
7270
|
+
creditsPerMinorUnit,
|
|
7271
|
+
displayExchangeRate: rate,
|
|
7272
|
+
displayCurrency: currency
|
|
7273
|
+
});
|
|
7274
|
+
if (displayMinor === null) return null;
|
|
7275
|
+
return displayMinor / getMinorUnitsPerMajor(currency);
|
|
7276
|
+
}
|
|
7277
|
+
|
|
7278
|
+
// src/helpers/stripe-minimums.ts
|
|
7279
|
+
var STRIPE_MINIMUM_MINOR = {
|
|
7280
|
+
USD: 50,
|
|
7281
|
+
EUR: 50,
|
|
7282
|
+
GBP: 30,
|
|
7283
|
+
SEK: 300,
|
|
7284
|
+
NOK: 300,
|
|
7285
|
+
DKK: 250,
|
|
7286
|
+
CHF: 50,
|
|
7287
|
+
CAD: 50,
|
|
7288
|
+
AUD: 50,
|
|
7289
|
+
JPY: 50,
|
|
7290
|
+
KRW: 500
|
|
7291
|
+
};
|
|
7292
|
+
var DEFAULT_MINIMUM_MINOR = 50;
|
|
7293
|
+
function getStripeMinimumMinor(currency) {
|
|
7294
|
+
return STRIPE_MINIMUM_MINOR[currency.toUpperCase()] ?? DEFAULT_MINIMUM_MINOR;
|
|
7295
|
+
}
|
|
7296
|
+
|
|
7297
|
+
// src/helpers/auto-recharge-form.ts
|
|
7298
|
+
var DEFAULT_VALIDATION_MESSAGES = {
|
|
7299
|
+
invalidThreshold: "Enter a valid balance threshold.",
|
|
7300
|
+
thresholdTooLow: "Balance threshold must be greater than zero.",
|
|
7301
|
+
minTopupAmount: "Top-up amount must be at least {amount}.",
|
|
7302
|
+
invalidMaxMonthlySpend: "Maximum monthly spend must be a positive amount.",
|
|
7303
|
+
maxMonthlySpendBelowTopup: "Maximum monthly spend must be at least your top-up amount ({amount})."
|
|
7304
|
+
};
|
|
7305
|
+
function amountAnchors(thresholdValue, topupValue, unit = "currency") {
|
|
7306
|
+
return {
|
|
7307
|
+
thresholdBaseValue: thresholdValue,
|
|
7308
|
+
thresholdBaseUnit: unit,
|
|
7309
|
+
topupBaseValue: topupValue,
|
|
7310
|
+
topupBaseUnit: unit
|
|
7311
|
+
};
|
|
7312
|
+
}
|
|
7313
|
+
function createDefaultAutoRechargeForm(currency, defaultTopupMajor, defaultThresholdMajor) {
|
|
7314
|
+
const topup = defaultTopupMajor != null && defaultTopupMajor > 0 ? String(defaultTopupMajor) : "10";
|
|
7315
|
+
const threshold = defaultThresholdMajor != null && defaultThresholdMajor >= 0 ? String(defaultThresholdMajor) : "5";
|
|
7316
|
+
return {
|
|
7317
|
+
enabled: false,
|
|
7318
|
+
thresholdAmountMajor: threshold,
|
|
7319
|
+
thresholdUnit: "currency",
|
|
7320
|
+
topupAmountMajor: topup,
|
|
7321
|
+
topupUnit: "currency",
|
|
7322
|
+
maxMonthlySpendMajor: "",
|
|
7323
|
+
...amountAnchors(threshold, topup, "currency")
|
|
7324
|
+
};
|
|
7325
|
+
}
|
|
7326
|
+
function currentSpendPeriod(now = /* @__PURE__ */ new Date()) {
|
|
7327
|
+
const year = now.getUTCFullYear();
|
|
7328
|
+
const month = now.getUTCMonth() + 1;
|
|
7329
|
+
return `${year}-${String(month).padStart(2, "0")}`;
|
|
7330
|
+
}
|
|
7331
|
+
function effectiveMonthlySpend(config, now = /* @__PURE__ */ new Date()) {
|
|
7332
|
+
if (config.monthlySpendPeriod !== currentSpendPeriod(now)) {
|
|
7333
|
+
return 0;
|
|
7334
|
+
}
|
|
7335
|
+
return config.monthlySpendMinor ?? 0;
|
|
7336
|
+
}
|
|
7337
|
+
function isMonthlySpendCapReached(config, now = /* @__PURE__ */ new Date()) {
|
|
7338
|
+
if (config.maxMonthlySpendMinor == null) return false;
|
|
7339
|
+
const effectiveSpend = effectiveMonthlySpend(config, now);
|
|
7340
|
+
return effectiveSpend + config.topup.amountMinor > config.maxMonthlySpendMinor;
|
|
7341
|
+
}
|
|
7342
|
+
function maxMonthlySpendMajorFromConfig(config, currency) {
|
|
7343
|
+
if (config.maxMonthlySpendMinor == null) return "";
|
|
7344
|
+
const minorPerMajor = getMinorUnitsPerMajor(currency);
|
|
7345
|
+
return String(config.maxMonthlySpendMinor / minorPerMajor);
|
|
7346
|
+
}
|
|
7347
|
+
function parsePositiveNumber(value) {
|
|
7348
|
+
const trimmed = value.trim();
|
|
7349
|
+
if (trimmed.length === 0) return null;
|
|
7350
|
+
const parsed = Number(trimmed);
|
|
7351
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return null;
|
|
7352
|
+
return parsed;
|
|
7353
|
+
}
|
|
7354
|
+
function parseNonNegativeNumber(value) {
|
|
7355
|
+
const trimmed = value.trim();
|
|
7356
|
+
if (trimmed.length === 0) return null;
|
|
7357
|
+
const parsed = Number(trimmed);
|
|
7358
|
+
if (!Number.isFinite(parsed) || parsed < 0) return null;
|
|
7359
|
+
return parsed;
|
|
7360
|
+
}
|
|
7361
|
+
function validateAutoRechargeForm(form, currency, conversion, messages = DEFAULT_VALIDATION_MESSAGES) {
|
|
7362
|
+
if (!form.enabled) {
|
|
7363
|
+
return {
|
|
7364
|
+
ok: true,
|
|
7365
|
+
payload: {
|
|
7366
|
+
enabled: false,
|
|
7367
|
+
triggerType: "balance",
|
|
7368
|
+
currency: currency.toUpperCase()
|
|
7369
|
+
}
|
|
7370
|
+
};
|
|
7371
|
+
}
|
|
7372
|
+
const payload = {
|
|
7373
|
+
enabled: true,
|
|
7374
|
+
triggerType: "balance",
|
|
7375
|
+
currency: currency.toUpperCase()
|
|
7376
|
+
};
|
|
7377
|
+
const minorPerMajor = getMinorUnitsPerMajor(currency);
|
|
7378
|
+
const minMinor = getStripeMinimumMinor(currency);
|
|
7379
|
+
const thresholdRaw = parseNonNegativeNumber(form.thresholdAmountMajor);
|
|
7380
|
+
if (thresholdRaw == null) {
|
|
7381
|
+
return { ok: false, error: messages.invalidThreshold };
|
|
7382
|
+
}
|
|
7383
|
+
if (form.thresholdUnit === "credits") {
|
|
7384
|
+
const major = estimateCurrencyMajorFromCredits(
|
|
7385
|
+
thresholdRaw,
|
|
7386
|
+
currency,
|
|
7387
|
+
conversion?.creditsPerMinorUnit,
|
|
7388
|
+
conversion?.displayExchangeRate
|
|
7389
|
+
);
|
|
7390
|
+
if (major == null) {
|
|
7391
|
+
return { ok: false, error: messages.invalidThreshold };
|
|
7392
|
+
}
|
|
7393
|
+
payload.thresholdAmountMajor = major;
|
|
7394
|
+
} else {
|
|
7395
|
+
payload.thresholdAmountMajor = thresholdRaw;
|
|
7396
|
+
}
|
|
7397
|
+
if (payload.thresholdAmountMajor == null || payload.thresholdAmountMajor <= 0) {
|
|
7398
|
+
return { ok: false, error: messages.thresholdTooLow };
|
|
7399
|
+
}
|
|
7400
|
+
const amountRaw = parsePositiveNumber(form.topupAmountMajor);
|
|
7401
|
+
if (amountRaw == null) {
|
|
7402
|
+
return {
|
|
7403
|
+
ok: false,
|
|
7404
|
+
error: interpolate(messages.minTopupAmount, {
|
|
7405
|
+
amount: formatPrice(minMinor, currency, { free: "" })
|
|
7406
|
+
})
|
|
7407
|
+
};
|
|
7408
|
+
}
|
|
7409
|
+
const amountMajor = form.topupUnit === "credits" ? estimateCurrencyMajorFromCredits(
|
|
7410
|
+
amountRaw,
|
|
7411
|
+
currency,
|
|
7412
|
+
conversion?.creditsPerMinorUnit,
|
|
7413
|
+
conversion?.displayExchangeRate
|
|
7414
|
+
) : amountRaw;
|
|
7415
|
+
if (amountMajor == null || Math.round(amountMajor * minorPerMajor) < minMinor) {
|
|
7416
|
+
return {
|
|
7417
|
+
ok: false,
|
|
7418
|
+
error: interpolate(messages.minTopupAmount, {
|
|
7419
|
+
amount: formatPrice(minMinor, currency, { free: "" })
|
|
7420
|
+
})
|
|
7421
|
+
};
|
|
7422
|
+
}
|
|
7423
|
+
payload.topupAmountMajor = amountMajor;
|
|
7424
|
+
if (form.maxMonthlySpendMajor.trim().length > 0) {
|
|
7425
|
+
const max = parsePositiveNumber(form.maxMonthlySpendMajor);
|
|
7426
|
+
if (max == null) {
|
|
7427
|
+
return { ok: false, error: messages.invalidMaxMonthlySpend };
|
|
7428
|
+
}
|
|
7429
|
+
if (max < amountMajor) {
|
|
7430
|
+
return {
|
|
7431
|
+
ok: false,
|
|
7432
|
+
error: interpolate(messages.maxMonthlySpendBelowTopup, {
|
|
7433
|
+
amount: formatPrice(Math.round(amountMajor * minorPerMajor), currency, { free: "" })
|
|
7434
|
+
})
|
|
7435
|
+
};
|
|
7436
|
+
}
|
|
7437
|
+
payload.maxMonthlySpendMajor = max;
|
|
7438
|
+
}
|
|
7439
|
+
return { ok: true, payload };
|
|
7440
|
+
}
|
|
7441
|
+
function triggerAmountMajorFromConfig(config) {
|
|
7442
|
+
const topupCurrency = config.topup.currency.toUpperCase();
|
|
7443
|
+
const minorPerMajor = getMinorUnitsPerMajor(topupCurrency);
|
|
7444
|
+
const { thresholdAmountMinor } = config.trigger;
|
|
7445
|
+
if (!Number.isFinite(thresholdAmountMinor) || thresholdAmountMinor < 0) {
|
|
7446
|
+
return null;
|
|
7447
|
+
}
|
|
7448
|
+
return thresholdAmountMinor / minorPerMajor;
|
|
7449
|
+
}
|
|
7450
|
+
function configToAutoRechargeInput(config, options) {
|
|
7451
|
+
if (!config.enabled) return null;
|
|
7452
|
+
const display = options?.display ?? config.display;
|
|
7453
|
+
const currency = (display?.currency ?? config.topup.currency ?? options?.currency ?? "USD").toUpperCase();
|
|
7454
|
+
if (display?.thresholdAmountMajor != null && display.topupAmountMajor != null) {
|
|
7455
|
+
return {
|
|
7456
|
+
enabled: true,
|
|
7457
|
+
triggerType: "balance",
|
|
7458
|
+
thresholdAmountMajor: display.thresholdAmountMajor,
|
|
7459
|
+
topupAmountMajor: display.topupAmountMajor,
|
|
7460
|
+
currency,
|
|
7461
|
+
...config.maxMonthlySpendMinor != null ? {
|
|
7462
|
+
maxMonthlySpendMajor: config.maxMonthlySpendMinor / getMinorUnitsPerMajor(currency)
|
|
7463
|
+
} : {}
|
|
7464
|
+
};
|
|
7465
|
+
}
|
|
7466
|
+
const thresholdMajor = triggerAmountMajorFromConfig(config);
|
|
7467
|
+
const topupAmountMajor = config.topup.amountMinor / getMinorUnitsPerMajor(currency);
|
|
7468
|
+
if (thresholdMajor == null || !Number.isFinite(topupAmountMajor) || topupAmountMajor <= 0) {
|
|
7469
|
+
return null;
|
|
7470
|
+
}
|
|
7471
|
+
return {
|
|
7472
|
+
enabled: true,
|
|
7473
|
+
triggerType: "balance",
|
|
7474
|
+
thresholdAmountMajor: Math.max(0, thresholdMajor),
|
|
7475
|
+
topupAmountMajor,
|
|
7476
|
+
currency,
|
|
7477
|
+
...config.maxMonthlySpendMinor != null ? {
|
|
7478
|
+
maxMonthlySpendMajor: config.maxMonthlySpendMinor / getMinorUnitsPerMajor(currency)
|
|
7479
|
+
} : {}
|
|
7480
|
+
};
|
|
7481
|
+
}
|
|
7482
|
+
function configToForm(config, currency) {
|
|
7483
|
+
const base = createDefaultAutoRechargeForm(currency);
|
|
7484
|
+
const display = config.display;
|
|
7485
|
+
if (display?.thresholdAmountMajor != null && display.topupAmountMajor != null) {
|
|
7486
|
+
const thresholdStr2 = String(Math.max(0, display.thresholdAmountMajor));
|
|
7487
|
+
const topupStr2 = String(display.topupAmountMajor);
|
|
7488
|
+
return {
|
|
7489
|
+
...base,
|
|
7490
|
+
enabled: config.enabled,
|
|
7491
|
+
thresholdAmountMajor: thresholdStr2,
|
|
7492
|
+
topupAmountMajor: topupStr2,
|
|
7493
|
+
maxMonthlySpendMajor: maxMonthlySpendMajorFromConfig(config, currency),
|
|
7494
|
+
...amountAnchors(thresholdStr2, topupStr2, "currency")
|
|
7495
|
+
};
|
|
7496
|
+
}
|
|
7497
|
+
const thresholdMajor = triggerAmountMajorFromConfig(config);
|
|
7498
|
+
const thresholdStr = thresholdMajor != null ? String(Math.max(0, thresholdMajor)) : "0";
|
|
7499
|
+
const topupStr = String(config.topup.amountMinor / getMinorUnitsPerMajor(currency));
|
|
7500
|
+
return {
|
|
7501
|
+
...base,
|
|
7502
|
+
enabled: config.enabled,
|
|
7503
|
+
thresholdAmountMajor: thresholdStr,
|
|
7504
|
+
topupAmountMajor: topupStr,
|
|
7505
|
+
maxMonthlySpendMajor: maxMonthlySpendMajorFromConfig(config, currency),
|
|
7506
|
+
...amountAnchors(thresholdStr, topupStr, "currency")
|
|
7507
|
+
};
|
|
7508
|
+
}
|
|
7509
|
+
function formatAmountWithUnit(value, unit, currency) {
|
|
7510
|
+
const num = Number(value);
|
|
7511
|
+
if (!value || !Number.isFinite(num)) return "\u2014";
|
|
7512
|
+
if (unit === "credits") {
|
|
7513
|
+
return `${new Intl.NumberFormat().format(num)} credits`;
|
|
7514
|
+
}
|
|
7515
|
+
return formatPrice(Math.round(num * getMinorUnitsPerMajor(currency)), currency, { free: "" });
|
|
7516
|
+
}
|
|
7517
|
+
function buildSummaryLine(form, currency) {
|
|
7518
|
+
if (!form.enabled) return null;
|
|
7519
|
+
const thresholdDisplay = formatAmountWithUnit(
|
|
7520
|
+
form.thresholdAmountMajor,
|
|
7521
|
+
form.thresholdUnit,
|
|
7522
|
+
currency
|
|
7523
|
+
);
|
|
7524
|
+
const fixedDisplay = formatAmountWithUnit(form.topupAmountMajor, form.topupUnit, currency);
|
|
7525
|
+
return `When my balance falls below ${thresholdDisplay}, add ${fixedDisplay}.`;
|
|
7526
|
+
}
|
|
7527
|
+
function convertAmountForUnitFlip(value, fromUnit, toUnit, currency, creditsPerMinorUnit, displayExchangeRate) {
|
|
7528
|
+
if (fromUnit === toUnit) return value;
|
|
7529
|
+
const parsed = Number(value);
|
|
7530
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return value;
|
|
7531
|
+
if (fromUnit === "currency" && toUnit === "credits") {
|
|
7532
|
+
const credits = estimateCredits(parsed, currency, creditsPerMinorUnit, displayExchangeRate);
|
|
7533
|
+
return credits != null ? String(credits) : value;
|
|
7534
|
+
}
|
|
7535
|
+
const major = estimateCurrencyMajorFromCredits(
|
|
7536
|
+
parsed,
|
|
7537
|
+
currency,
|
|
7538
|
+
creditsPerMinorUnit,
|
|
7539
|
+
displayExchangeRate
|
|
7540
|
+
);
|
|
7541
|
+
return major != null ? String(major) : value;
|
|
7542
|
+
}
|
|
7543
|
+
function flipUnitValue(anchor, targetUnit, currency, creditsPerMinorUnit, displayExchangeRate) {
|
|
7544
|
+
if (targetUnit === anchor.unit) {
|
|
7545
|
+
return { value: anchor.value, unit: anchor.unit };
|
|
7546
|
+
}
|
|
7547
|
+
const converted = convertAmountForUnitFlip(
|
|
7548
|
+
anchor.value,
|
|
7549
|
+
anchor.unit,
|
|
7550
|
+
targetUnit,
|
|
7551
|
+
currency,
|
|
7552
|
+
creditsPerMinorUnit,
|
|
7553
|
+
displayExchangeRate
|
|
7554
|
+
);
|
|
7555
|
+
return { value: converted, unit: targetUnit };
|
|
7556
|
+
}
|
|
7557
|
+
|
|
6560
7558
|
// src/hooks/useCheckoutFlow.ts
|
|
6561
|
-
import { useCallback as
|
|
7559
|
+
import { useCallback as useCallback22, useMemo as useMemo17, useRef as useRef11, useState as useState19 } from "react";
|
|
6562
7560
|
|
|
6563
7561
|
// src/primitives/checkout/shared.ts
|
|
6564
7562
|
import {
|
|
@@ -6566,6 +7564,7 @@ import {
|
|
|
6566
7564
|
creditsPerUnitFromBalance,
|
|
6567
7565
|
includedUnits,
|
|
6568
7566
|
meterName,
|
|
7567
|
+
planPricingShape,
|
|
6569
7568
|
usageRate
|
|
6570
7569
|
} from "@solvapay/core";
|
|
6571
7570
|
function isPayg(plan) {
|
|
@@ -6597,28 +7596,60 @@ function buildDefaultCheckoutPlanFilter(allPlans) {
|
|
|
6597
7596
|
}
|
|
6598
7597
|
function formatContinueLabel(plan, locale, pricingOption) {
|
|
6599
7598
|
if (!plan) return "Continue";
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
const priceLabel = formatPrice(option.price ?? 0, currency, { locale });
|
|
6606
|
-
const interval = planBillingInterval(plan);
|
|
6607
|
-
const cycle = interval ? `/${shortCycle(interval)}` : "";
|
|
6608
|
-
return `Continue with ${plan.name ?? "Plan"} \u2014 ${priceLabel}${cycle}`;
|
|
7599
|
+
const priceLabel = formatPlanPriceLabel(plan, locale ?? "en-US", pricingOption);
|
|
7600
|
+
return `Continue with ${plan.name ?? "Plan"} \u2014 ${priceLabel}`;
|
|
7601
|
+
}
|
|
7602
|
+
function planBillingCycle(plan) {
|
|
7603
|
+
return readBillingCycle(plan);
|
|
6609
7604
|
}
|
|
6610
7605
|
function planBillingInterval(plan) {
|
|
6611
7606
|
return readBillingCycle(plan)?.interval ?? null;
|
|
6612
7607
|
}
|
|
7608
|
+
function formatCycleSuffix(cycle) {
|
|
7609
|
+
if (!cycle) return "";
|
|
7610
|
+
const short = shortCycle(cycle.interval);
|
|
7611
|
+
if (cycle.count && cycle.count > 1) return `/${cycle.count} ${short}`;
|
|
7612
|
+
return `/${short}`;
|
|
7613
|
+
}
|
|
7614
|
+
function formatPlanPriceLabel(plan, locale, pricingOption) {
|
|
7615
|
+
const shape = planPricingShape(plan);
|
|
7616
|
+
switch (shape.shape) {
|
|
7617
|
+
case "free":
|
|
7618
|
+
return "Free";
|
|
7619
|
+
case "usage":
|
|
7620
|
+
return "Pay per use";
|
|
7621
|
+
case "recurring":
|
|
7622
|
+
case "hybrid": {
|
|
7623
|
+
const option = pricingOption ?? resolveBootstrapPlanPricing(plan);
|
|
7624
|
+
const amount = option.price ?? shape.headlineMinor;
|
|
7625
|
+
const currency = option.currency.toUpperCase();
|
|
7626
|
+
const priceLabel = formatPrice(amount, currency, { locale, free: "" });
|
|
7627
|
+
return `${priceLabel}${formatCycleSuffix(shape.cycle)}`;
|
|
7628
|
+
}
|
|
7629
|
+
case "oneTime": {
|
|
7630
|
+
const option = pricingOption ?? resolveBootstrapPlanPricing(plan);
|
|
7631
|
+
const amount = option.price ?? shape.headlineMinor;
|
|
7632
|
+
const currency = option.currency.toUpperCase();
|
|
7633
|
+
const priceLabel = formatPrice(amount, currency, { locale, free: "" });
|
|
7634
|
+
return `${priceLabel} once`;
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
}
|
|
7638
|
+
function singularMeterNoun(unit) {
|
|
7639
|
+
if (unit.endsWith("ies")) return `${unit.slice(0, -3)}y`;
|
|
7640
|
+
if (unit.endsWith("s") && !unit.endsWith("ss")) return unit.slice(0, -1);
|
|
7641
|
+
return unit;
|
|
7642
|
+
}
|
|
6613
7643
|
function formatPaygRate(plan, locale, balance) {
|
|
6614
7644
|
const rate = usageRate(plan);
|
|
6615
7645
|
if (!rate || !(rate.amountMinor > 0)) return null;
|
|
6616
7646
|
const prefix = rate.tiered ? "from " : "";
|
|
6617
7647
|
const credits = creditsPerUnitFromBalance(plan, balance);
|
|
7648
|
+
const unit = singularMeterNoun(rate.meter ?? meterName(plan) ?? "unit");
|
|
6618
7649
|
if (credits != null) {
|
|
6619
|
-
return `${prefix}${credits.toLocaleString(locale)} ${credits === 1 ? "credit" : "credits"} /
|
|
7650
|
+
return `${prefix}${credits.toLocaleString(locale)} ${credits === 1 ? "credit" : "credits"} / ${unit}`;
|
|
6620
7651
|
}
|
|
6621
|
-
return `${prefix}${formatPrice(rate.amountMinor, rate.currency.toUpperCase(), { locale })} /
|
|
7652
|
+
return `${prefix}${formatPrice(rate.amountMinor, rate.currency.toUpperCase(), { locale })} / ${unit}`;
|
|
6622
7653
|
}
|
|
6623
7654
|
function inferIncludedUnits(plan) {
|
|
6624
7655
|
const cap = includedUnits(plan);
|
|
@@ -6628,12 +7659,13 @@ function planMeterName(plan) {
|
|
|
6628
7659
|
return meterName(plan);
|
|
6629
7660
|
}
|
|
6630
7661
|
function shortCycle(cycle) {
|
|
6631
|
-
if (!cycle) return "
|
|
7662
|
+
if (!cycle) return "";
|
|
6632
7663
|
const lc = cycle.toLowerCase();
|
|
6633
|
-
if (lc
|
|
6634
|
-
if (lc.startsWith("
|
|
6635
|
-
if (lc.startsWith("
|
|
6636
|
-
return "
|
|
7664
|
+
if (lc === "week" || lc.startsWith("week")) return "wk";
|
|
7665
|
+
if (lc === "year" || lc.startsWith("year") || lc === "annually" || lc === "annual") return "yr";
|
|
7666
|
+
if (lc === "month" || lc.startsWith("month")) return "mo";
|
|
7667
|
+
if (lc === "day" || lc.startsWith("day")) return "d";
|
|
7668
|
+
return cycle;
|
|
6637
7669
|
}
|
|
6638
7670
|
|
|
6639
7671
|
// src/hooks/useCheckoutFlow.ts
|
|
@@ -6643,10 +7675,10 @@ function resolveInitialCheckoutStep(initialStep) {
|
|
|
6643
7675
|
}
|
|
6644
7676
|
function useCheckoutFlow(opts) {
|
|
6645
7677
|
const { productRef, initialStep = "plan", initialAmountMinor = null } = opts;
|
|
6646
|
-
const onPlanSelectRef =
|
|
6647
|
-
const onAmountSelectRef =
|
|
6648
|
-
const onPurchaseSuccessRef =
|
|
6649
|
-
const onErrorRef =
|
|
7678
|
+
const onPlanSelectRef = useRef11(opts.onPlanSelect);
|
|
7679
|
+
const onAmountSelectRef = useRef11(opts.onAmountSelect);
|
|
7680
|
+
const onPurchaseSuccessRef = useRef11(opts.onPurchaseSuccess);
|
|
7681
|
+
const onErrorRef = useRef11(opts.onError);
|
|
6650
7682
|
onPlanSelectRef.current = opts.onPlanSelect;
|
|
6651
7683
|
onAmountSelectRef.current = opts.onAmountSelect;
|
|
6652
7684
|
onPurchaseSuccessRef.current = opts.onPurchaseSuccess;
|
|
@@ -6659,8 +7691,8 @@ function useCheckoutFlow(opts) {
|
|
|
6659
7691
|
const { creditsPerMinorUnit, displayExchangeRate, adjustBalance } = balance;
|
|
6660
7692
|
const { refetchPurchase } = useSolvaPay();
|
|
6661
7693
|
const { merchant } = useMerchant();
|
|
6662
|
-
const [topupCurrencyOverride, setTopupCurrencyOverride] =
|
|
6663
|
-
const topupCurrencies =
|
|
7694
|
+
const [topupCurrencyOverride, setTopupCurrencyOverride] = useState19(null);
|
|
7695
|
+
const topupCurrencies = useMemo17(() => {
|
|
6664
7696
|
const fromMerchant = (merchant?.supportedTopupCurrencies ?? []).map((code) => code.toUpperCase()).filter(Boolean);
|
|
6665
7697
|
const fallback = opts.topupCurrency?.toUpperCase() ?? merchant?.defaultCurrency?.toUpperCase() ?? null;
|
|
6666
7698
|
const list = fromMerchant.length > 0 ? fromMerchant : fallback ? [fallback] : [];
|
|
@@ -6670,22 +7702,22 @@ function useCheckoutFlow(opts) {
|
|
|
6670
7702
|
const planPickerCurrency = planCtx.preferredCurrency?.toUpperCase() ?? null;
|
|
6671
7703
|
const topupCurrency = (topupCurrencyOverride && topupCurrencies.includes(topupCurrencyOverride) ? topupCurrencyOverride : null) ?? (planPickerCurrency && topupCurrencies.includes(planPickerCurrency) ? planPickerCurrency : null) ?? resolvedDefaultTopupCurrency;
|
|
6672
7704
|
const topupCurrencyReady = topupCurrency != null;
|
|
6673
|
-
const setTopupCurrency =
|
|
7705
|
+
const setTopupCurrency = useCallback22((code) => {
|
|
6674
7706
|
const normalized = code.toUpperCase();
|
|
6675
7707
|
setTopupCurrencyOverride(normalized);
|
|
6676
7708
|
}, []);
|
|
6677
|
-
const [step, setStep] =
|
|
6678
|
-
const [status, setStatus] =
|
|
6679
|
-
const [selectedAmountMinor, setSelectedAmountMinor] =
|
|
6680
|
-
const [successMeta, setSuccessMeta] =
|
|
6681
|
-
const [error, setError] =
|
|
6682
|
-
const selectedAmountMinorRef =
|
|
7709
|
+
const [step, setStep] = useState19(() => resolveInitialCheckoutStep(initialStep));
|
|
7710
|
+
const [status, setStatus] = useState19("idle");
|
|
7711
|
+
const [selectedAmountMinor, setSelectedAmountMinor] = useState19(initialAmountMinor);
|
|
7712
|
+
const [successMeta, setSuccessMeta] = useState19(null);
|
|
7713
|
+
const [error, setError] = useState19(null);
|
|
7714
|
+
const selectedAmountMinorRef = useRef11(initialAmountMinor);
|
|
6683
7715
|
const selectedPlan = planCtx.selectedPlan;
|
|
6684
7716
|
const selectedPlanRef = planCtx.selectedPlanRef;
|
|
6685
7717
|
const selectedPlanShape = toBootstrapPlanLike(selectedPlan);
|
|
6686
7718
|
const branch = selectedPlanShape ? isPayg(selectedPlanShape) ? "payg" : "recurring" : null;
|
|
6687
7719
|
const canGoBack = step === "amount" || step === "payment";
|
|
6688
|
-
const selectPlan =
|
|
7720
|
+
const selectPlan = useCallback22(
|
|
6689
7721
|
(ref) => {
|
|
6690
7722
|
planCtx.select(ref);
|
|
6691
7723
|
const plan = planCtx.plans.find((p) => p.reference === ref) ?? null;
|
|
@@ -6695,7 +7727,7 @@ function useCheckoutFlow(opts) {
|
|
|
6695
7727
|
},
|
|
6696
7728
|
[planCtx]
|
|
6697
7729
|
);
|
|
6698
|
-
const selectAmount =
|
|
7730
|
+
const selectAmount = useCallback22(
|
|
6699
7731
|
(amountMinor) => {
|
|
6700
7732
|
selectedAmountMinorRef.current = amountMinor;
|
|
6701
7733
|
setSelectedAmountMinor(amountMinor);
|
|
@@ -6704,7 +7736,7 @@ function useCheckoutFlow(opts) {
|
|
|
6704
7736
|
},
|
|
6705
7737
|
[topupCurrency]
|
|
6706
7738
|
);
|
|
6707
|
-
const runActivate =
|
|
7739
|
+
const runActivate = useCallback22(async () => {
|
|
6708
7740
|
if (!selectedPlanShape || !selectedPlanRef) return false;
|
|
6709
7741
|
setError(null);
|
|
6710
7742
|
setStatus("activating");
|
|
@@ -6736,7 +7768,7 @@ function useCheckoutFlow(opts) {
|
|
|
6736
7768
|
return false;
|
|
6737
7769
|
}
|
|
6738
7770
|
}, [balance, locale, productRef, selectedPlanRef, selectedPlanShape, transport]);
|
|
6739
|
-
const advanceFromPlan =
|
|
7771
|
+
const advanceFromPlan = useCallback22(async () => {
|
|
6740
7772
|
if (!selectedPlanShape || !selectedPlanRef) return;
|
|
6741
7773
|
if (branch === "payg") {
|
|
6742
7774
|
if (planCtx.currentPlanRef === selectedPlanRef) {
|
|
@@ -6774,7 +7806,7 @@ function useCheckoutFlow(opts) {
|
|
|
6774
7806
|
setError(null);
|
|
6775
7807
|
setStep("payment");
|
|
6776
7808
|
}, [balance, branch, locale, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
|
|
6777
|
-
const recordPaygSuccess =
|
|
7809
|
+
const recordPaygSuccess = useCallback22(
|
|
6778
7810
|
(creditsAddedFromBackend) => {
|
|
6779
7811
|
if (!selectedPlanShape || selectedAmountMinor == null) return;
|
|
6780
7812
|
const currency = topupCurrency ?? "USD";
|
|
@@ -6818,7 +7850,7 @@ function useCheckoutFlow(opts) {
|
|
|
6818
7850
|
transport
|
|
6819
7851
|
]
|
|
6820
7852
|
);
|
|
6821
|
-
const recordRecurringSuccess =
|
|
7853
|
+
const recordRecurringSuccess = useCallback22(() => {
|
|
6822
7854
|
if (!selectedPlanShape) return;
|
|
6823
7855
|
const pricingOption = selectedPlan ? resolvePlanPricingOption(selectedPlan, planSelection?.selectedCurrency) : {
|
|
6824
7856
|
currency: selectedPlanShape.currency ?? "USD",
|
|
@@ -6838,7 +7870,7 @@ function useCheckoutFlow(opts) {
|
|
|
6838
7870
|
setStep("success");
|
|
6839
7871
|
onPurchaseSuccessRef.current?.(meta);
|
|
6840
7872
|
}, [selectedPlanShape, selectedPlan, planSelection?.selectedCurrency]);
|
|
6841
|
-
const advance =
|
|
7873
|
+
const advance = useCallback22(async () => {
|
|
6842
7874
|
if (step === "plan") {
|
|
6843
7875
|
await advanceFromPlan();
|
|
6844
7876
|
return;
|
|
@@ -6865,7 +7897,7 @@ function useCheckoutFlow(opts) {
|
|
|
6865
7897
|
selectedAmountMinor,
|
|
6866
7898
|
step
|
|
6867
7899
|
]);
|
|
6868
|
-
const back =
|
|
7900
|
+
const back = useCallback22(() => {
|
|
6869
7901
|
setError(null);
|
|
6870
7902
|
if (step === "amount") {
|
|
6871
7903
|
setStep("plan");
|
|
@@ -6876,7 +7908,7 @@ function useCheckoutFlow(opts) {
|
|
|
6876
7908
|
return;
|
|
6877
7909
|
}
|
|
6878
7910
|
}, [branch, step]);
|
|
6879
|
-
const reset =
|
|
7911
|
+
const reset = useCallback22(() => {
|
|
6880
7912
|
setStep("plan");
|
|
6881
7913
|
selectedAmountMinorRef.current = null;
|
|
6882
7914
|
setSelectedAmountMinor(null);
|
|
@@ -6885,13 +7917,13 @@ function useCheckoutFlow(opts) {
|
|
|
6885
7917
|
setStatus("idle");
|
|
6886
7918
|
setTopupCurrencyOverride(null);
|
|
6887
7919
|
}, []);
|
|
6888
|
-
const retry =
|
|
7920
|
+
const retry = useCallback22(async () => {
|
|
6889
7921
|
if (status !== "error") return;
|
|
6890
7922
|
if (step === "plan" && branch === "payg") {
|
|
6891
7923
|
await runActivate();
|
|
6892
7924
|
}
|
|
6893
7925
|
}, [branch, runActivate, status, step]);
|
|
6894
|
-
const notifyPaymentSuccess =
|
|
7926
|
+
const notifyPaymentSuccess = useCallback22(
|
|
6895
7927
|
(_intent, extras) => {
|
|
6896
7928
|
if (branch === "payg") {
|
|
6897
7929
|
recordPaygSuccess(extras?.creditsAdded);
|
|
@@ -6901,7 +7933,7 @@ function useCheckoutFlow(opts) {
|
|
|
6901
7933
|
},
|
|
6902
7934
|
[branch, recordPaygSuccess, recordRecurringSuccess]
|
|
6903
7935
|
);
|
|
6904
|
-
return
|
|
7936
|
+
return useMemo17(
|
|
6905
7937
|
() => ({
|
|
6906
7938
|
step,
|
|
6907
7939
|
status,
|
|
@@ -6951,11 +7983,6 @@ function useCheckoutFlow(opts) {
|
|
|
6951
7983
|
|
|
6952
7984
|
export {
|
|
6953
7985
|
createTransportCacheKey,
|
|
6954
|
-
autoRechargeCache,
|
|
6955
|
-
CACHE_DURATION2 as CACHE_DURATION,
|
|
6956
|
-
autoRechargeCacheKeyFor,
|
|
6957
|
-
writeAutoRechargeCache,
|
|
6958
|
-
subscribeAutoRecharge,
|
|
6959
7986
|
filterPurchases,
|
|
6960
7987
|
getActivePurchases,
|
|
6961
7988
|
getCancelledPurchasesWithEndDate,
|
|
@@ -6979,6 +8006,9 @@ export {
|
|
|
6979
8006
|
composeEventHandlers,
|
|
6980
8007
|
useCopy,
|
|
6981
8008
|
useLocale,
|
|
8009
|
+
ExternalLinkProvider,
|
|
8010
|
+
useOpenExternal,
|
|
8011
|
+
useExternalLinkClick,
|
|
6982
8012
|
LegalFooter,
|
|
6983
8013
|
withPaymentElementDefaults,
|
|
6984
8014
|
MissingProviderError,
|
|
@@ -7076,7 +8106,6 @@ export {
|
|
|
7076
8106
|
PlanSelector,
|
|
7077
8107
|
usePlanSelector,
|
|
7078
8108
|
usePurchaseActions,
|
|
7079
|
-
CancelPlanButton,
|
|
7080
8109
|
usePurchaseStatus,
|
|
7081
8110
|
CancelledPlanNoticeRoot2 as CancelledPlanNoticeRoot,
|
|
7082
8111
|
CancelledPlanNoticeHeading2 as CancelledPlanNoticeHeading,
|
|
@@ -7089,8 +8118,10 @@ export {
|
|
|
7089
8118
|
CancelledPlanNotice,
|
|
7090
8119
|
useCancelledPlanNotice,
|
|
7091
8120
|
useTransport,
|
|
8121
|
+
limitsCache,
|
|
7092
8122
|
isUnlimited,
|
|
7093
8123
|
useLimits,
|
|
8124
|
+
seedUsageSnapshot,
|
|
7094
8125
|
useUsage,
|
|
7095
8126
|
Root7 as Root,
|
|
7096
8127
|
Bar,
|
|
@@ -7105,9 +8136,24 @@ export {
|
|
|
7105
8136
|
planSortByPaygFirstThenAsc,
|
|
7106
8137
|
buildDefaultCheckoutPlanFilter,
|
|
7107
8138
|
formatContinueLabel,
|
|
8139
|
+
planBillingCycle,
|
|
7108
8140
|
planBillingInterval,
|
|
8141
|
+
formatCycleSuffix,
|
|
8142
|
+
formatPlanPriceLabel,
|
|
8143
|
+
formatPaygRate,
|
|
7109
8144
|
inferIncludedUnits,
|
|
7110
8145
|
planMeterName,
|
|
7111
|
-
|
|
8146
|
+
useAutoRecharge,
|
|
8147
|
+
estimateCredits,
|
|
8148
|
+
estimateCurrencyMajorFromCredits,
|
|
8149
|
+
createDefaultAutoRechargeForm,
|
|
8150
|
+
effectiveMonthlySpend,
|
|
8151
|
+
isMonthlySpendCapReached,
|
|
8152
|
+
validateAutoRechargeForm,
|
|
8153
|
+
configToAutoRechargeInput,
|
|
8154
|
+
configToForm,
|
|
8155
|
+
formatAmountWithUnit,
|
|
8156
|
+
buildSummaryLine,
|
|
8157
|
+
flipUnitValue,
|
|
7112
8158
|
useCheckoutFlow
|
|
7113
8159
|
};
|