@solvapay/react 2.0.0 → 2.0.1-preview-fab746232bff615a7302c55ee7293205ac645de4
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 +24 -0
- package/dist/{chunk-D6TOFFNL.js → chunk-BHG7Z5XV.js} +4 -3
- package/dist/{chunk-6ABOJOEV.js → chunk-GMZU5M6R.js} +76 -31
- package/dist/{chunk-PKZJIV3G.js → chunk-ZKFTT5WD.js} +41 -36
- package/dist/{index-DomaahLG.d.ts → index-DHcgeDBy.d.ts} +6 -12
- package/dist/{index-D6KKDguz.d.cts → index-jmmZYs2K.d.cts} +6 -12
- package/dist/index.cjs +133 -79
- package/dist/index.d.cts +6 -26
- package/dist/index.d.ts +6 -26
- package/dist/index.js +9 -7
- package/dist/mcp/index.cjs +124 -73
- package/dist/mcp/index.d.cts +3 -6
- package/dist/mcp/index.d.ts +3 -6
- package/dist/mcp/index.js +21 -18
- package/dist/primitives/index.cjs +116 -67
- package/dist/primitives/index.d.cts +4 -4
- package/dist/primitives/index.d.ts +4 -4
- package/dist/primitives/index.js +2 -2
- package/dist/{shared-CAxz5wWs.d.ts → shared-BI78qUom.d.ts} +5 -4
- package/dist/{shared-A_Sg-fJE.d.cts → shared-BgyNW-D3.d.cts} +5 -4
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @solvapay/react changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.1-preview-fab746232bff615a7302c55ee7293205ac645de4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a47adff: Free plans with an included allowance now count usage and label the meter correctly.
|
|
8
|
+
|
|
9
|
+
`@solvapay/core` adds `countsUsage` (per-unit charge, tier, or limit) and `meterName`
|
|
10
|
+
(per-unit charge's meter, else the first limit's meter). A free tier with a bare
|
|
11
|
+
limit is not priced per unit, but it still needs a usage counter and a meter noun —
|
|
12
|
+
`isMetered` on the wire was the wrong question for both.
|
|
13
|
+
|
|
14
|
+
`planMeterName` uses the new reader, so a recurring allowance no longer renders the
|
|
15
|
+
literal "units". `useAutoActivateFreePlan` no longer requires deprecated `freeUnits`
|
|
16
|
+
on the plan row. Usage surfaces (`useUsage`, `getUsageCore`, plan cards) derive
|
|
17
|
+
from `options[]` instead of trusting `planSnapshot.isMetered` alone.
|
|
18
|
+
|
|
19
|
+
- 30f7021: PAYG embedded checkout now activates first, then shows the credit top-up picker only when the wallet is empty.
|
|
20
|
+
|
|
21
|
+
A funded wallet skips the amount and payment steps. `ActivationFlow` follows the same contract: API `activated` at zero credits opens the amount picker instead of firing `onSuccess`. Once the customer is on the amount or payment step, a later zero-credit balance refetch no longer rewinds them back to the picker.
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [a47adff]
|
|
24
|
+
- @solvapay/core@1.5.0-preview-fab746232bff615a7302c55ee7293205ac645de4
|
|
25
|
+
- @solvapay/mcp-core@0.3.2-preview-fab746232bff615a7302c55ee7293205ac645de4
|
|
26
|
+
|
|
3
27
|
## 2.0.0
|
|
4
28
|
|
|
5
29
|
### Major Changes
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
usePurchaseStatus,
|
|
15
15
|
useSolvaPay,
|
|
16
16
|
useTransport
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GMZU5M6R.js";
|
|
18
18
|
|
|
19
19
|
// src/components/CancelledPlanNotice.tsx
|
|
20
20
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -362,6 +362,7 @@ var UpdatePaymentMethodButton = forwardRef2(function UpdatePaymentMethodButton2(
|
|
|
362
362
|
});
|
|
363
363
|
|
|
364
364
|
// src/components/CurrentPlanCard.tsx
|
|
365
|
+
import { countsUsage } from "@solvapay/core";
|
|
365
366
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
366
367
|
function PlanTypeLine({
|
|
367
368
|
purchase,
|
|
@@ -369,7 +370,7 @@ function PlanTypeLine({
|
|
|
369
370
|
className
|
|
370
371
|
}) {
|
|
371
372
|
const copy = useCopy();
|
|
372
|
-
const isMetered = purchase.planSnapshot?.isMetered === true;
|
|
373
|
+
const isMetered = countsUsage(purchase.planSnapshot) || purchase.planSnapshot?.isMetered === true;
|
|
373
374
|
if (purchase.isRecurring) {
|
|
374
375
|
const date2 = formatDate(purchase.nextBillingDate);
|
|
375
376
|
if (!date2) return null;
|
|
@@ -429,7 +430,7 @@ var CurrentPlanCard = ({
|
|
|
429
430
|
const { formatDate, shouldShowCancelledNotice } = usePurchaseStatus();
|
|
430
431
|
const { paymentMethod } = usePaymentMethod();
|
|
431
432
|
if (!activePurchase) return null;
|
|
432
|
-
const isUsageBased = activePurchase.planSnapshot?.isMetered === true;
|
|
433
|
+
const isUsageBased = countsUsage(activePurchase.planSnapshot) || activePurchase.planSnapshot?.isMetered === true;
|
|
433
434
|
const planType = activePurchase.isRecurring ? "recurring" : isUsageBased ? "usage-based" : "one-time";
|
|
434
435
|
const amount = activePurchase.originalAmount ?? activePurchase.amount ?? 0;
|
|
435
436
|
const currency = activePurchase.currency ?? "usd";
|
|
@@ -303,10 +303,10 @@ function createHttpTransport(config) {
|
|
|
303
303
|
onErrorContext: "getUsage",
|
|
304
304
|
errorPrefix: "Failed to load usage"
|
|
305
305
|
}),
|
|
306
|
-
getLimits: async ({ productRef, meterName }) => {
|
|
306
|
+
getLimits: async ({ productRef, meterName: meterName2 }) => {
|
|
307
307
|
const base = routeFor(config, "getLimits");
|
|
308
308
|
const params = new URLSearchParams({ productRef });
|
|
309
|
-
if (
|
|
309
|
+
if (meterName2) params.set("meterName", meterName2);
|
|
310
310
|
const url = `${base}?${params.toString()}`;
|
|
311
311
|
const data = await request(config, url, {
|
|
312
312
|
method: "GET",
|
|
@@ -483,7 +483,7 @@ var enCopy = {
|
|
|
483
483
|
activateButton: "Activate",
|
|
484
484
|
activatingLabel: "Activating...",
|
|
485
485
|
topupHeading: "Add credits",
|
|
486
|
-
topupSubheading: "Top up your credits to
|
|
486
|
+
topupSubheading: "Top up your credits to start using this plan.",
|
|
487
487
|
continueToPayment: "Continue to payment",
|
|
488
488
|
changeAmountButton: "Change amount",
|
|
489
489
|
retryingHeading: "Activating your plan...",
|
|
@@ -816,7 +816,7 @@ var SolvaPayProvider = ({ config, children }) => {
|
|
|
816
816
|
setHasAttachBusinessDetails(!!transportRef.current.attachBusinessDetails);
|
|
817
817
|
}, [config]);
|
|
818
818
|
const fetchBalanceImpl = useCallback(async () => {
|
|
819
|
-
if (optimisticUntilRef.current > Date.now()) return;
|
|
819
|
+
if (optimisticUntilRef.current > Date.now()) return creditsValueRef.current;
|
|
820
820
|
if (!isAuthenticated && !internalCustomerRef) {
|
|
821
821
|
creditsValueRef.current = null;
|
|
822
822
|
setCreditsValue(null);
|
|
@@ -826,18 +826,16 @@ var SolvaPayProvider = ({ config, children }) => {
|
|
|
826
826
|
setDisplayBlockValue(null);
|
|
827
827
|
setBalanceLoading(false);
|
|
828
828
|
balanceLoadedRef.current = false;
|
|
829
|
-
return;
|
|
829
|
+
return null;
|
|
830
830
|
}
|
|
831
|
-
if (balanceInFlightRef.current) return;
|
|
831
|
+
if (balanceInFlightRef.current) return creditsValueRef.current;
|
|
832
832
|
balanceInFlightRef.current = true;
|
|
833
833
|
if (!balanceLoadedRef.current) {
|
|
834
834
|
setBalanceLoading(true);
|
|
835
835
|
}
|
|
836
836
|
try {
|
|
837
837
|
if (!transportRef.current.getBalance) {
|
|
838
|
-
|
|
839
|
-
balanceInFlightRef.current = false;
|
|
840
|
-
return;
|
|
838
|
+
return creditsValueRef.current;
|
|
841
839
|
}
|
|
842
840
|
const data = await transportRef.current.getBalance();
|
|
843
841
|
creditsValueRef.current = data.credits ?? null;
|
|
@@ -847,8 +845,10 @@ var SolvaPayProvider = ({ config, children }) => {
|
|
|
847
845
|
setDisplayExchangeRateValue(data.displayExchangeRate ?? null);
|
|
848
846
|
setDisplayBlockValue(data.display ?? null);
|
|
849
847
|
balanceLoadedRef.current = true;
|
|
848
|
+
return creditsValueRef.current;
|
|
850
849
|
} catch (error) {
|
|
851
850
|
console.error("[SolvaPayProvider] Failed to fetch balance:", error);
|
|
851
|
+
return creditsValueRef.current;
|
|
852
852
|
} finally {
|
|
853
853
|
setBalanceLoading(false);
|
|
854
854
|
balanceInFlightRef.current = false;
|
|
@@ -3010,7 +3010,8 @@ function normalizeOneTimePurchase(input) {
|
|
|
3010
3010
|
planSnapshot: {
|
|
3011
3011
|
price: input.amount,
|
|
3012
3012
|
currency: input.currency,
|
|
3013
|
-
isMetered: false
|
|
3013
|
+
isMetered: false,
|
|
3014
|
+
options: []
|
|
3014
3015
|
}
|
|
3015
3016
|
};
|
|
3016
3017
|
}
|
|
@@ -5796,12 +5797,13 @@ function usePurchaseActions() {
|
|
|
5796
5797
|
}
|
|
5797
5798
|
|
|
5798
5799
|
// src/primitives/CancelPlanButton.tsx
|
|
5800
|
+
import { countsUsage } from "@solvapay/core";
|
|
5799
5801
|
import { forwardRef as forwardRef10, useCallback as useCallback16, useContext as useContext13 } from "react";
|
|
5800
5802
|
import { Fragment as Fragment9, jsx as jsx17 } from "react/jsx-runtime";
|
|
5801
5803
|
function resolveConfirmText(confirm, purchase, defaults) {
|
|
5802
5804
|
if (confirm === false) return null;
|
|
5803
5805
|
if (typeof confirm === "string") return confirm;
|
|
5804
|
-
const isUsageBased = purchase?.planSnapshot?.isMetered === true && purchase
|
|
5806
|
+
const isUsageBased = (countsUsage(purchase?.planSnapshot) || purchase?.planSnapshot?.isMetered === true) && purchase?.isRecurring !== true;
|
|
5805
5807
|
if (isUsageBased) return defaults.usageBased;
|
|
5806
5808
|
return defaults.recurring;
|
|
5807
5809
|
}
|
|
@@ -6098,19 +6100,19 @@ import { useCallback as useCallback19, useEffect as useEffect12, useRef as useRe
|
|
|
6098
6100
|
var CACHE_TTL_MS = 1e4;
|
|
6099
6101
|
var OPTIMISTIC_GRACE_MS = 8e3;
|
|
6100
6102
|
var limitsCache = /* @__PURE__ */ new Map();
|
|
6101
|
-
function cacheKey(customerRef, productRef,
|
|
6102
|
-
return `${customerRef ?? "anonymous"}:${productRef}:${
|
|
6103
|
+
function cacheKey(customerRef, productRef, meterName2) {
|
|
6104
|
+
return `${customerRef ?? "anonymous"}:${productRef}:${meterName2}`;
|
|
6103
6105
|
}
|
|
6104
6106
|
function isUnlimited(remaining) {
|
|
6105
6107
|
return remaining < 0;
|
|
6106
6108
|
}
|
|
6107
6109
|
function useLimits(options) {
|
|
6108
6110
|
const { productRef, meterName: rawMeterName, enabled = true } = options;
|
|
6109
|
-
const
|
|
6111
|
+
const meterName2 = rawMeterName || "requests";
|
|
6110
6112
|
const transport = useTransport();
|
|
6111
6113
|
const { customerRef } = useCustomer();
|
|
6112
6114
|
const { purchase } = useSolvaPay();
|
|
6113
|
-
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef,
|
|
6115
|
+
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName2);
|
|
6114
6116
|
const [data, setData] = useState15(() => {
|
|
6115
6117
|
if (!currentKey) return null;
|
|
6116
6118
|
const cached = limitsCache.get(currentKey);
|
|
@@ -6165,7 +6167,7 @@ function useLimits(options) {
|
|
|
6165
6167
|
setLoading(false);
|
|
6166
6168
|
return;
|
|
6167
6169
|
}
|
|
6168
|
-
const key = cacheKey(customerRef, productRef,
|
|
6170
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
6169
6171
|
const cached = limitsCache.get(key);
|
|
6170
6172
|
const now = Date.now();
|
|
6171
6173
|
if (cached?.promise) {
|
|
@@ -6178,7 +6180,7 @@ function useLimits(options) {
|
|
|
6178
6180
|
setError(null);
|
|
6179
6181
|
return;
|
|
6180
6182
|
}
|
|
6181
|
-
const promise = transport.getLimits({ productRef, meterName });
|
|
6183
|
+
const promise = transport.getLimits({ productRef, meterName: meterName2 });
|
|
6182
6184
|
limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
|
|
6183
6185
|
const fresh = await attachToFetch(promise);
|
|
6184
6186
|
if (fresh !== null) {
|
|
@@ -6187,7 +6189,7 @@ function useLimits(options) {
|
|
|
6187
6189
|
limitsCache.delete(key);
|
|
6188
6190
|
}
|
|
6189
6191
|
},
|
|
6190
|
-
[transport, customerRef, productRef,
|
|
6192
|
+
[transport, customerRef, productRef, meterName2, enabled, attachToFetch]
|
|
6191
6193
|
);
|
|
6192
6194
|
useEffect12(() => {
|
|
6193
6195
|
fetchLimits(false);
|
|
@@ -6205,7 +6207,7 @@ function useLimits(options) {
|
|
|
6205
6207
|
(delta) => {
|
|
6206
6208
|
if (!productRef || !enabled) return;
|
|
6207
6209
|
if (unlimitedRef.current) return;
|
|
6208
|
-
const key = cacheKey(customerRef, productRef,
|
|
6210
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
6209
6211
|
setData((prev) => {
|
|
6210
6212
|
const cached = limitsCache.get(key);
|
|
6211
6213
|
const baseline = prev ?? cached?.data ?? null;
|
|
@@ -6232,7 +6234,7 @@ function useLimits(options) {
|
|
|
6232
6234
|
});
|
|
6233
6235
|
}, OPTIMISTIC_GRACE_MS);
|
|
6234
6236
|
},
|
|
6235
|
-
[customerRef, productRef,
|
|
6237
|
+
[customerRef, productRef, meterName2, enabled, fetchLimits]
|
|
6236
6238
|
);
|
|
6237
6239
|
return {
|
|
6238
6240
|
remaining: data?.remaining ?? null,
|
|
@@ -6248,11 +6250,14 @@ function useLimits(options) {
|
|
|
6248
6250
|
}
|
|
6249
6251
|
|
|
6250
6252
|
// src/hooks/useUsage.ts
|
|
6253
|
+
import { countsUsage as countsUsage2 } from "@solvapay/core";
|
|
6251
6254
|
import { useCallback as useCallback20, useEffect as useEffect13, useMemo as useMemo14, useState as useState16 } from "react";
|
|
6252
6255
|
function deriveUsage(purchase, limits) {
|
|
6253
6256
|
if (!purchase) return null;
|
|
6254
6257
|
const usage = purchase.usage;
|
|
6255
|
-
if (purchase.planSnapshot?.isMetered !== true && !usage)
|
|
6258
|
+
if (!countsUsage2(purchase.planSnapshot) && purchase.planSnapshot?.isMetered !== true && !usage) {
|
|
6259
|
+
return null;
|
|
6260
|
+
}
|
|
6256
6261
|
const used = typeof usage?.used === "number" ? usage.used : 0;
|
|
6257
6262
|
const hasFiniteCap = limits.unlimited === false && limits.remaining !== null;
|
|
6258
6263
|
const remaining = hasFiniteCap ? limits.remaining : null;
|
|
@@ -6275,18 +6280,18 @@ function useUsage() {
|
|
|
6275
6280
|
const [override, setOverride] = useState16(null);
|
|
6276
6281
|
const [error, setError] = useState16(null);
|
|
6277
6282
|
const [transportLoading, setTransportLoading] = useState16(false);
|
|
6278
|
-
const
|
|
6283
|
+
const usageCounted = countsUsage2(activePurchase?.planSnapshot) || activePurchase?.planSnapshot?.isMetered === true;
|
|
6279
6284
|
const {
|
|
6280
6285
|
remaining: limitRemaining,
|
|
6281
6286
|
unlimited,
|
|
6282
|
-
meterName
|
|
6287
|
+
meterName: meterName2
|
|
6283
6288
|
} = useLimits({
|
|
6284
6289
|
productRef: activePurchase?.productRef,
|
|
6285
|
-
enabled:
|
|
6290
|
+
enabled: usageCounted
|
|
6286
6291
|
});
|
|
6287
6292
|
const derived = useMemo14(
|
|
6288
|
-
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName }),
|
|
6289
|
-
[activePurchase, limitRemaining, unlimited,
|
|
6293
|
+
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName: meterName2 }),
|
|
6294
|
+
[activePurchase, limitRemaining, unlimited, meterName2]
|
|
6290
6295
|
);
|
|
6291
6296
|
const activePurchaseRef = activePurchase?.reference ?? null;
|
|
6292
6297
|
useEffect13(() => {
|
|
@@ -6547,6 +6552,7 @@ import {
|
|
|
6547
6552
|
billingCycle as readBillingCycle,
|
|
6548
6553
|
creditsPerUnitFromBalance,
|
|
6549
6554
|
includedUnits,
|
|
6555
|
+
meterName,
|
|
6550
6556
|
perUnitCharge
|
|
6551
6557
|
} from "@solvapay/core";
|
|
6552
6558
|
function isPayg(plan) {
|
|
@@ -6607,7 +6613,7 @@ function inferIncludedUnits(plan) {
|
|
|
6607
6613
|
return cap != null && cap > 0 ? cap : null;
|
|
6608
6614
|
}
|
|
6609
6615
|
function planMeterName(plan) {
|
|
6610
|
-
return
|
|
6616
|
+
return meterName(plan);
|
|
6611
6617
|
}
|
|
6612
6618
|
function shortCycle(cycle) {
|
|
6613
6619
|
if (!cycle) return "mo";
|
|
@@ -6692,8 +6698,23 @@ function useCheckoutFlow(opts) {
|
|
|
6692
6698
|
setStatus("activating");
|
|
6693
6699
|
try {
|
|
6694
6700
|
await transport.activatePlan({ productRef, planRef: selectedPlanRef });
|
|
6701
|
+
const credits = await balance.refetch() ?? balance.credits;
|
|
6702
|
+
if (credits == null) {
|
|
6703
|
+
throw new Error("Credit balance is unavailable");
|
|
6704
|
+
}
|
|
6695
6705
|
setStatus("idle");
|
|
6696
|
-
|
|
6706
|
+
if (credits === 0) {
|
|
6707
|
+
setStep("amount");
|
|
6708
|
+
} else {
|
|
6709
|
+
const meta = {
|
|
6710
|
+
branch: "payg",
|
|
6711
|
+
plan: selectedPlanShape,
|
|
6712
|
+
rateLabel: formatPaygRate(selectedPlanShape, locale, balance)
|
|
6713
|
+
};
|
|
6714
|
+
setSuccessMeta(meta);
|
|
6715
|
+
setStep("success");
|
|
6716
|
+
onPurchaseSuccessRef.current?.(meta);
|
|
6717
|
+
}
|
|
6697
6718
|
return true;
|
|
6698
6719
|
} catch (err) {
|
|
6699
6720
|
const wrapped = err instanceof Error ? err : new Error("Activation failed");
|
|
@@ -6702,13 +6723,37 @@ function useCheckoutFlow(opts) {
|
|
|
6702
6723
|
onErrorRef.current?.(wrapped, "activate");
|
|
6703
6724
|
return false;
|
|
6704
6725
|
}
|
|
6705
|
-
}, [productRef, selectedPlanRef, selectedPlanShape, transport]);
|
|
6726
|
+
}, [balance, locale, productRef, selectedPlanRef, selectedPlanShape, transport]);
|
|
6706
6727
|
const advanceFromPlan = useCallback21(async () => {
|
|
6707
6728
|
if (!selectedPlanShape || !selectedPlanRef) return;
|
|
6708
6729
|
if (branch === "payg") {
|
|
6709
6730
|
if (planCtx.currentPlanRef === selectedPlanRef) {
|
|
6710
6731
|
setError(null);
|
|
6711
|
-
|
|
6732
|
+
setStatus("activating");
|
|
6733
|
+
try {
|
|
6734
|
+
const credits = await balance.refetch() ?? balance.credits;
|
|
6735
|
+
if (credits == null) {
|
|
6736
|
+
throw new Error("Credit balance is unavailable");
|
|
6737
|
+
}
|
|
6738
|
+
setStatus("idle");
|
|
6739
|
+
if (credits === 0) {
|
|
6740
|
+
setStep("amount");
|
|
6741
|
+
} else {
|
|
6742
|
+
const meta = {
|
|
6743
|
+
branch: "payg",
|
|
6744
|
+
plan: selectedPlanShape,
|
|
6745
|
+
rateLabel: formatPaygRate(selectedPlanShape, locale, balance)
|
|
6746
|
+
};
|
|
6747
|
+
setSuccessMeta(meta);
|
|
6748
|
+
setStep("success");
|
|
6749
|
+
onPurchaseSuccessRef.current?.(meta);
|
|
6750
|
+
}
|
|
6751
|
+
} catch (err) {
|
|
6752
|
+
const wrapped = err instanceof Error ? err : new Error("Activation failed");
|
|
6753
|
+
setError(wrapped.message);
|
|
6754
|
+
setStatus("error");
|
|
6755
|
+
onErrorRef.current?.(wrapped, "activate");
|
|
6756
|
+
}
|
|
6712
6757
|
return;
|
|
6713
6758
|
}
|
|
6714
6759
|
await runActivate();
|
|
@@ -6716,7 +6761,7 @@ function useCheckoutFlow(opts) {
|
|
|
6716
6761
|
}
|
|
6717
6762
|
setError(null);
|
|
6718
6763
|
setStep("payment");
|
|
6719
|
-
}, [branch, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
|
|
6764
|
+
}, [balance, branch, locale, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
|
|
6720
6765
|
const recordPaygSuccess = useCallback21(
|
|
6721
6766
|
(creditsAddedFromBackend) => {
|
|
6722
6767
|
if (!selectedPlanShape || selectedAmountMinor == null) return;
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
useTopupAmountSelector,
|
|
41
41
|
withPaymentElementDefaults,
|
|
42
42
|
writeAutoRechargeCache
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-GMZU5M6R.js";
|
|
44
44
|
|
|
45
45
|
// src/TopupForm.tsx
|
|
46
46
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -216,12 +216,29 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
|
|
|
216
216
|
const { activate, state, error, result, reset } = useActivation();
|
|
217
217
|
const currency = plan?.currency ?? "USD";
|
|
218
218
|
const amountSelector = useTopupAmountSelector({ currency });
|
|
219
|
-
const {
|
|
219
|
+
const {
|
|
220
|
+
credits,
|
|
221
|
+
adjustBalance,
|
|
222
|
+
creditsPerMinorUnit,
|
|
223
|
+
displayExchangeRate,
|
|
224
|
+
refetch,
|
|
225
|
+
loading: balanceLoading
|
|
226
|
+
} = useBalance();
|
|
220
227
|
const [step, setStep] = useState2("summary");
|
|
221
228
|
const calledSuccessRef = useRef(false);
|
|
222
229
|
const retryTimeoutRef = useRef(null);
|
|
223
230
|
useEffect2(() => {
|
|
224
|
-
if (state
|
|
231
|
+
if (state !== "activated") return;
|
|
232
|
+
if (step === "selectAmount" || step === "topupPayment") return;
|
|
233
|
+
const isUsagePlan = plan?.type === "usage-based";
|
|
234
|
+
if (isUsagePlan && (credits === null || balanceLoading)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (isUsagePlan && credits === 0) {
|
|
238
|
+
setStep("selectAmount");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!calledSuccessRef.current) {
|
|
225
242
|
calledSuccessRef.current = true;
|
|
226
243
|
setStep("activated");
|
|
227
244
|
if (result) {
|
|
@@ -229,7 +246,7 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
|
|
|
229
246
|
onSuccess?.(activationResult);
|
|
230
247
|
}
|
|
231
248
|
}
|
|
232
|
-
}, [state, result, onSuccess]);
|
|
249
|
+
}, [state, result, onSuccess, credits, plan, balanceLoading, step]);
|
|
233
250
|
useEffect2(() => {
|
|
234
251
|
if (state === "topup_required" && (step === "summary" || step === "activating")) {
|
|
235
252
|
setStep("selectAmount");
|
|
@@ -245,7 +262,8 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
|
|
|
245
262
|
if (!resolvedPlanRef) return;
|
|
246
263
|
setStep("activating");
|
|
247
264
|
await activate({ productRef, planRef: resolvedPlanRef });
|
|
248
|
-
|
|
265
|
+
await refetch();
|
|
266
|
+
}, [activate, productRef, resolvedPlanRef, refetch]);
|
|
249
267
|
const goToTopupPayment = useCallback(() => {
|
|
250
268
|
if (amountSelector.validate()) setStep("topupPayment");
|
|
251
269
|
}, [amountSelector]);
|
|
@@ -336,16 +354,7 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
|
|
|
336
354
|
]
|
|
337
355
|
);
|
|
338
356
|
const Comp = asChild ? Slot : "div";
|
|
339
|
-
return /* @__PURE__ */ jsx4(ActivationFlowContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(
|
|
340
|
-
Comp,
|
|
341
|
-
{
|
|
342
|
-
ref: forwardedRef,
|
|
343
|
-
"data-solvapay-activation-flow": "",
|
|
344
|
-
"data-state": step,
|
|
345
|
-
...rest,
|
|
346
|
-
children
|
|
347
|
-
}
|
|
348
|
-
) });
|
|
357
|
+
return /* @__PURE__ */ jsx4(ActivationFlowContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(Comp, { ref: forwardedRef, "data-solvapay-activation-flow": "", "data-state": step, ...rest, children }) });
|
|
349
358
|
});
|
|
350
359
|
function matchStep(step, allowed) {
|
|
351
360
|
return allowed.includes(step);
|
|
@@ -435,16 +444,7 @@ var ErrorSlot2 = forwardRef3(function ActivationFlowError({ asChild, children, .
|
|
|
435
444
|
const ctx = useFlowCtx("Error");
|
|
436
445
|
if (ctx.step !== "error") return null;
|
|
437
446
|
const Comp = asChild ? Slot : "div";
|
|
438
|
-
return /* @__PURE__ */ jsx4(
|
|
439
|
-
Comp,
|
|
440
|
-
{
|
|
441
|
-
ref: forwardedRef,
|
|
442
|
-
role: "alert",
|
|
443
|
-
"data-solvapay-activation-flow-error": "",
|
|
444
|
-
...rest,
|
|
445
|
-
children: children ?? ctx.error
|
|
446
|
-
}
|
|
447
|
-
);
|
|
447
|
+
return /* @__PURE__ */ jsx4(Comp, { ref: forwardedRef, role: "alert", "data-solvapay-activation-flow-error": "", ...rest, children: children ?? ctx.error });
|
|
448
448
|
});
|
|
449
449
|
var ActivationFlowRoot2 = Root2;
|
|
450
450
|
var ActivationFlowSummary2 = Summary;
|
|
@@ -2885,22 +2885,27 @@ function Success({ className, children }) {
|
|
|
2885
2885
|
}
|
|
2886
2886
|
const meta = flow.successMeta;
|
|
2887
2887
|
if (meta.branch === "payg") {
|
|
2888
|
+
const chargedAmount = meta.amountMinor;
|
|
2889
|
+
const chargedCurrency = meta.currency;
|
|
2890
|
+
const charged = chargedAmount != null && chargedCurrency != null;
|
|
2888
2891
|
return /* @__PURE__ */ jsxs3("div", { className: className ?? "solvapay-checkout-success", "data-branch": "payg", children: [
|
|
2889
2892
|
/* @__PURE__ */ jsx7("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
|
|
2890
|
-
/* @__PURE__ */ jsx7("h2", { className: "solvapay-checkout-success-heading", children: "Credits added" }),
|
|
2893
|
+
/* @__PURE__ */ jsx7("h2", { className: "solvapay-checkout-success-heading", children: charged ? "Credits added" : "Plan activated" }),
|
|
2891
2894
|
/* @__PURE__ */ jsx7("p", { className: "solvapay-checkout-success-subheading", children: "Pay as you go plan is active." }),
|
|
2892
2895
|
/* @__PURE__ */ jsxs3("dl", { className: "solvapay-checkout-receipt", "data-variant": "payg", children: [
|
|
2893
|
-
/* @__PURE__ */ jsxs3(
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
/* @__PURE__ */
|
|
2899
|
-
|
|
2900
|
-
"
|
|
2901
|
-
|
|
2896
|
+
charged ? /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
2897
|
+
/* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
|
|
2898
|
+
/* @__PURE__ */ jsx7("dt", { children: "Amount" }),
|
|
2899
|
+
/* @__PURE__ */ jsx7("dd", { children: formatPrice(chargedAmount, chargedCurrency, { locale }) })
|
|
2900
|
+
] }),
|
|
2901
|
+
/* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
|
|
2902
|
+
/* @__PURE__ */ jsx7("dt", { children: "Credits" }),
|
|
2903
|
+
/* @__PURE__ */ jsxs3("dd", { children: [
|
|
2904
|
+
"+",
|
|
2905
|
+
(meta.creditsAdded ?? 0).toLocaleString(locale)
|
|
2906
|
+
] })
|
|
2902
2907
|
] })
|
|
2903
|
-
] }),
|
|
2908
|
+
] }) : null,
|
|
2904
2909
|
/* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
|
|
2905
2910
|
/* @__PURE__ */ jsx7("dt", { children: "Plan" }),
|
|
2906
2911
|
/* @__PURE__ */ jsx7("dd", { children: meta.plan.name ?? "Pay as you go" })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-
|
|
1
|
+
import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-BI78qUom.js';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
|
|
4
4
|
import { TaxBreakdown } from '@solvapay/core';
|
|
@@ -411,8 +411,11 @@ declare const BalanceBadge: React.ForwardRefExoticComponent<React.HTMLAttributes
|
|
|
411
411
|
* ActivationFlow compound primitive.
|
|
412
412
|
*
|
|
413
413
|
* Drives the usage-based plan activation state machine:
|
|
414
|
-
* summary → activating → (
|
|
415
|
-
* retrying) → activated | error.
|
|
414
|
+
* summary → activating → (activated + empty wallet → selectAmount →
|
|
415
|
+
* topupPayment → retrying) → activated | error.
|
|
416
|
+
*
|
|
417
|
+
* `topup_required` remains a tolerated legacy activate status that also
|
|
418
|
+
* opens the amount picker.
|
|
416
419
|
*
|
|
417
420
|
* `Root` exposes `data-state` set to the current step and publishes the
|
|
418
421
|
* shared context consumed by leaves. Leaves render only during their
|
|
@@ -527,15 +530,6 @@ declare const ActivationFlow: {
|
|
|
527
530
|
};
|
|
528
531
|
declare function useActivationFlow(): ActivationFlowContextValue;
|
|
529
532
|
|
|
530
|
-
/**
|
|
531
|
-
* CancelPlanButton leaf primitive.
|
|
532
|
-
*
|
|
533
|
-
* Cancels the active (or specified) purchase via `usePurchaseActions`.
|
|
534
|
-
* Emits `data-state=idle|cancelling` and auto-derives the confirm dialog
|
|
535
|
-
* copy from the plan type (`recurring` vs. `usage-based`) unless overridden
|
|
536
|
-
* via the `confirm` prop (`false` to skip, string to replace).
|
|
537
|
-
*/
|
|
538
|
-
|
|
539
533
|
declare const CancelPlanButton: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
540
534
|
asChild?: boolean;
|
|
541
535
|
/** Defaults to the active purchase from `usePurchase()`. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-
|
|
1
|
+
import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-BgyNW-D3.cjs';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
|
|
4
4
|
import { TaxBreakdown } from '@solvapay/core';
|
|
@@ -411,8 +411,11 @@ declare const BalanceBadge: React.ForwardRefExoticComponent<React.HTMLAttributes
|
|
|
411
411
|
* ActivationFlow compound primitive.
|
|
412
412
|
*
|
|
413
413
|
* Drives the usage-based plan activation state machine:
|
|
414
|
-
* summary → activating → (
|
|
415
|
-
* retrying) → activated | error.
|
|
414
|
+
* summary → activating → (activated + empty wallet → selectAmount →
|
|
415
|
+
* topupPayment → retrying) → activated | error.
|
|
416
|
+
*
|
|
417
|
+
* `topup_required` remains a tolerated legacy activate status that also
|
|
418
|
+
* opens the amount picker.
|
|
416
419
|
*
|
|
417
420
|
* `Root` exposes `data-state` set to the current step and publishes the
|
|
418
421
|
* shared context consumed by leaves. Leaves render only during their
|
|
@@ -527,15 +530,6 @@ declare const ActivationFlow: {
|
|
|
527
530
|
};
|
|
528
531
|
declare function useActivationFlow(): ActivationFlowContextValue;
|
|
529
532
|
|
|
530
|
-
/**
|
|
531
|
-
* CancelPlanButton leaf primitive.
|
|
532
|
-
*
|
|
533
|
-
* Cancels the active (or specified) purchase via `usePurchaseActions`.
|
|
534
|
-
* Emits `data-state=idle|cancelling` and auto-derives the confirm dialog
|
|
535
|
-
* copy from the plan type (`recurring` vs. `usage-based`) unless overridden
|
|
536
|
-
* via the `confirm` prop (`false` to skip, string to replace).
|
|
537
|
-
*/
|
|
538
|
-
|
|
539
533
|
declare const CancelPlanButton: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
540
534
|
asChild?: boolean;
|
|
541
535
|
/** Defaults to the active purchase from `usePurchase()`. */
|