@streamoid/settings 0.3.1 → 0.3.3
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/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +102 -31
- package/dist/index.mjs +102 -31
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -265,6 +265,7 @@ interface SubscriptionPlan {
|
|
|
265
265
|
id: string;
|
|
266
266
|
name: string;
|
|
267
267
|
amount: number;
|
|
268
|
+
type?: string;
|
|
268
269
|
subscriptionEndDate?: string;
|
|
269
270
|
/** Three-letter currency code (lowercase) when known, e.g. "inr" / "usd". */
|
|
270
271
|
currency?: string;
|
|
@@ -276,6 +277,10 @@ interface BillingSubscription {
|
|
|
276
277
|
downgradeScheduled: boolean;
|
|
277
278
|
stripeCustomerId: string;
|
|
278
279
|
plan: SubscriptionPlan;
|
|
280
|
+
scheduledDowngradeEffectiveDate?: number | string;
|
|
281
|
+
preDowngradeStripePriceData?: SubscriptionPlan & {
|
|
282
|
+
credits?: string;
|
|
283
|
+
};
|
|
279
284
|
/** Stripe product id; used to look up the matching product in fetched plans. */
|
|
280
285
|
stripeProductId?: string;
|
|
281
286
|
}
|
|
@@ -659,10 +664,11 @@ declare function ConfirmDeleteModal({ open, workspaceName, onClose, onConfirm, }
|
|
|
659
664
|
|
|
660
665
|
interface BuyCreditsModalProps {
|
|
661
666
|
currencySymbol?: string;
|
|
667
|
+
country?: string;
|
|
662
668
|
onClose: () => void;
|
|
663
669
|
onBuy: (credits: number, price: number) => void;
|
|
664
670
|
}
|
|
665
|
-
declare function BuyCreditsModal({ currencySymbol, onClose, onBuy, }: BuyCreditsModalProps): react_jsx_runtime.JSX.Element;
|
|
671
|
+
declare function BuyCreditsModal({ currencySymbol, country, onClose, onBuy, }: BuyCreditsModalProps): react_jsx_runtime.JSX.Element;
|
|
666
672
|
|
|
667
673
|
interface UserPermissions {
|
|
668
674
|
artifax: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -265,6 +265,7 @@ interface SubscriptionPlan {
|
|
|
265
265
|
id: string;
|
|
266
266
|
name: string;
|
|
267
267
|
amount: number;
|
|
268
|
+
type?: string;
|
|
268
269
|
subscriptionEndDate?: string;
|
|
269
270
|
/** Three-letter currency code (lowercase) when known, e.g. "inr" / "usd". */
|
|
270
271
|
currency?: string;
|
|
@@ -276,6 +277,10 @@ interface BillingSubscription {
|
|
|
276
277
|
downgradeScheduled: boolean;
|
|
277
278
|
stripeCustomerId: string;
|
|
278
279
|
plan: SubscriptionPlan;
|
|
280
|
+
scheduledDowngradeEffectiveDate?: number | string;
|
|
281
|
+
preDowngradeStripePriceData?: SubscriptionPlan & {
|
|
282
|
+
credits?: string;
|
|
283
|
+
};
|
|
279
284
|
/** Stripe product id; used to look up the matching product in fetched plans. */
|
|
280
285
|
stripeProductId?: string;
|
|
281
286
|
}
|
|
@@ -659,10 +664,11 @@ declare function ConfirmDeleteModal({ open, workspaceName, onClose, onConfirm, }
|
|
|
659
664
|
|
|
660
665
|
interface BuyCreditsModalProps {
|
|
661
666
|
currencySymbol?: string;
|
|
667
|
+
country?: string;
|
|
662
668
|
onClose: () => void;
|
|
663
669
|
onBuy: (credits: number, price: number) => void;
|
|
664
670
|
}
|
|
665
|
-
declare function BuyCreditsModal({ currencySymbol, onClose, onBuy, }: BuyCreditsModalProps): react_jsx_runtime.JSX.Element;
|
|
671
|
+
declare function BuyCreditsModal({ currencySymbol, country, onClose, onBuy, }: BuyCreditsModalProps): react_jsx_runtime.JSX.Element;
|
|
666
672
|
|
|
667
673
|
interface UserPermissions {
|
|
668
674
|
artifax: boolean;
|
package/dist/index.js
CHANGED
|
@@ -3801,41 +3801,63 @@ var import_react7 = require("react");
|
|
|
3801
3801
|
var import_icons4 = require("@streamoid/icons");
|
|
3802
3802
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
3803
3803
|
var STEP = 500;
|
|
3804
|
-
var
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3804
|
+
var USD_TOPUP_CONFIG = {
|
|
3805
|
+
currencyCode: "usd",
|
|
3806
|
+
pricePerCredit: 0.08,
|
|
3807
|
+
minAmount: 40,
|
|
3808
|
+
maxAmount: 1e4
|
|
3809
|
+
};
|
|
3810
|
+
var INR_TOPUP_CONFIG = {
|
|
3811
|
+
currencyCode: "inr",
|
|
3812
|
+
pricePerCredit: 5,
|
|
3813
|
+
minAmount: 2500,
|
|
3814
|
+
maxAmount: 1e5
|
|
3815
|
+
};
|
|
3809
3816
|
function BuyCreditsModal({
|
|
3810
3817
|
currencySymbol = "$",
|
|
3818
|
+
country,
|
|
3811
3819
|
onClose,
|
|
3812
3820
|
onBuy
|
|
3813
3821
|
}) {
|
|
3814
|
-
const
|
|
3815
|
-
const
|
|
3816
|
-
const
|
|
3822
|
+
const normalizedCountry = country?.trim().toUpperCase();
|
|
3823
|
+
const topupConfig = normalizedCountry === "IN" ? INR_TOPUP_CONFIG : USD_TOPUP_CONFIG;
|
|
3824
|
+
const minCredits = Math.round(
|
|
3825
|
+
topupConfig.minAmount / topupConfig.pricePerCredit
|
|
3826
|
+
);
|
|
3827
|
+
const maxCredits = Math.round(
|
|
3828
|
+
topupConfig.maxAmount / topupConfig.pricePerCredit
|
|
3829
|
+
);
|
|
3830
|
+
const [credits, setCredits] = (0, import_react7.useState)(minCredits);
|
|
3831
|
+
const [creditsInput, setCreditsInput] = (0, import_react7.useState)(String(minCredits));
|
|
3832
|
+
const [priceInput, setPriceInput] = (0, import_react7.useState)(
|
|
3833
|
+
String(minCredits * topupConfig.pricePerCredit)
|
|
3834
|
+
);
|
|
3817
3835
|
const [activeField, setActiveField] = (0, import_react7.useState)("credits");
|
|
3818
3836
|
const parsedCredits = creditsInput.length ? Number(creditsInput) : credits;
|
|
3819
3837
|
const previewCredits = Number.isFinite(parsedCredits) ? parsedCredits : credits;
|
|
3820
3838
|
const pricedCredits = previewCredits > 0 ? previewCredits : 0;
|
|
3821
|
-
const price = Number(
|
|
3822
|
-
|
|
3823
|
-
|
|
3839
|
+
const price = Number(
|
|
3840
|
+
(pricedCredits * topupConfig.pricePerCredit).toFixed(2)
|
|
3841
|
+
);
|
|
3842
|
+
const isBelowMin = price < topupConfig.minAmount;
|
|
3843
|
+
const isAboveMax = price > topupConfig.maxAmount;
|
|
3824
3844
|
const isError = isBelowMin || isAboveMax;
|
|
3825
3845
|
const isInvalid = isError;
|
|
3826
3846
|
const syncFromCredits = (value) => {
|
|
3827
3847
|
setCredits(value);
|
|
3828
3848
|
setCreditsInput(String(value));
|
|
3829
|
-
setPriceInput(
|
|
3849
|
+
setPriceInput(
|
|
3850
|
+
String(Number((value * topupConfig.pricePerCredit).toFixed(2)))
|
|
3851
|
+
);
|
|
3830
3852
|
};
|
|
3831
|
-
const syncFromPrice = (
|
|
3832
|
-
const derived = Math.round(
|
|
3853
|
+
const syncFromPrice = (amount) => {
|
|
3854
|
+
const derived = Math.round(amount / topupConfig.pricePerCredit);
|
|
3833
3855
|
setCredits(derived);
|
|
3834
3856
|
setCreditsInput(String(derived));
|
|
3835
|
-
setPriceInput(String(
|
|
3857
|
+
setPriceInput(String(amount));
|
|
3836
3858
|
};
|
|
3837
|
-
const handleDecrement = () => syncFromCredits(Math.max(
|
|
3838
|
-
const handleIncrement = () => syncFromCredits(Math.min(
|
|
3859
|
+
const handleDecrement = () => syncFromCredits(Math.max(minCredits, credits - STEP));
|
|
3860
|
+
const handleIncrement = () => syncFromCredits(Math.min(maxCredits, credits + STEP));
|
|
3839
3861
|
const handleCreditsChange = (value) => {
|
|
3840
3862
|
const raw = value.replace(/[^\d]/g, "");
|
|
3841
3863
|
setCreditsInput(raw);
|
|
@@ -3844,7 +3866,9 @@ function BuyCreditsModal({
|
|
|
3844
3866
|
const next = Number(raw);
|
|
3845
3867
|
if (!Number.isNaN(next)) {
|
|
3846
3868
|
setCredits(next);
|
|
3847
|
-
setPriceInput(
|
|
3869
|
+
setPriceInput(
|
|
3870
|
+
String(Number((next * topupConfig.pricePerCredit).toFixed(2)))
|
|
3871
|
+
);
|
|
3848
3872
|
}
|
|
3849
3873
|
};
|
|
3850
3874
|
const handleCreditsBlur = () => {
|
|
@@ -3862,7 +3886,7 @@ function BuyCreditsModal({
|
|
|
3862
3886
|
if (!raw.length) return;
|
|
3863
3887
|
const next = Number(raw);
|
|
3864
3888
|
if (!Number.isNaN(next) && next >= 0) {
|
|
3865
|
-
const derived = Math.round(next /
|
|
3889
|
+
const derived = Math.round(next / topupConfig.pricePerCredit);
|
|
3866
3890
|
setCredits(derived);
|
|
3867
3891
|
setCreditsInput(String(derived));
|
|
3868
3892
|
}
|
|
@@ -3966,7 +3990,7 @@ function BuyCreditsModal({
|
|
|
3966
3990
|
style: {
|
|
3967
3991
|
width: 24,
|
|
3968
3992
|
height: 24,
|
|
3969
|
-
opacity: credits <=
|
|
3993
|
+
opacity: credits <= minCredits ? 0.3 : 1,
|
|
3970
3994
|
transition: "opacity 0.15s ease"
|
|
3971
3995
|
},
|
|
3972
3996
|
onClick: handleDecrement,
|
|
@@ -4024,7 +4048,7 @@ function BuyCreditsModal({
|
|
|
4024
4048
|
style: {
|
|
4025
4049
|
width: 24,
|
|
4026
4050
|
height: 24,
|
|
4027
|
-
opacity: credits >=
|
|
4051
|
+
opacity: credits >= maxCredits ? 0.3 : 1,
|
|
4028
4052
|
transition: "opacity 0.15s ease"
|
|
4029
4053
|
},
|
|
4030
4054
|
onClick: handleIncrement,
|
|
@@ -4111,7 +4135,7 @@ function BuyCreditsModal({
|
|
|
4111
4135
|
lineHeight: "var(--line-height-line-height-sm)",
|
|
4112
4136
|
color: "var(--alias-text---icons-error)"
|
|
4113
4137
|
},
|
|
4114
|
-
children: isBelowMin ? `Min. ${
|
|
4138
|
+
children: isBelowMin ? `Min. ${minCredits.toLocaleString()} credits` : `Max. ${maxCredits.toLocaleString()} credits`
|
|
4115
4139
|
}
|
|
4116
4140
|
) })
|
|
4117
4141
|
}
|
|
@@ -4456,6 +4480,16 @@ function formatNextBillingDateLabel(iso) {
|
|
|
4456
4480
|
year: "numeric"
|
|
4457
4481
|
});
|
|
4458
4482
|
}
|
|
4483
|
+
function formatEffectiveDateLabel(value) {
|
|
4484
|
+
if (value == null) return "";
|
|
4485
|
+
const parsed = typeof value === "number" ? new Date(value < 1e10 ? value * 1e3 : value) : new Date(value);
|
|
4486
|
+
if (Number.isNaN(parsed.getTime())) return "";
|
|
4487
|
+
return parsed.toLocaleDateString("en-US", {
|
|
4488
|
+
month: "short",
|
|
4489
|
+
day: "numeric",
|
|
4490
|
+
year: "numeric"
|
|
4491
|
+
});
|
|
4492
|
+
}
|
|
4459
4493
|
function UpdateSubscriptionModal({
|
|
4460
4494
|
open,
|
|
4461
4495
|
currentPlanName,
|
|
@@ -5509,7 +5543,7 @@ function BillingContent({
|
|
|
5509
5543
|
const [availableCredits, setAvailableCredits] = (0, import_react8.useState)(null);
|
|
5510
5544
|
const [products, setProducts] = (0, import_react8.useState)([]);
|
|
5511
5545
|
const [invoices, setInvoices] = (0, import_react8.useState)([]);
|
|
5512
|
-
const [totalCredits, setTotalCredits] = (0, import_react8.useState)(
|
|
5546
|
+
const [totalCredits, setTotalCredits] = (0, import_react8.useState)(null);
|
|
5513
5547
|
const [usageLogs, setUsageLogs] = (0, import_react8.useState)([]);
|
|
5514
5548
|
const [userMap, setUserMap] = (0, import_react8.useState)({});
|
|
5515
5549
|
const [customPlanCredits, setCustomPlanCredits] = (0, import_react8.useState)(
|
|
@@ -5520,6 +5554,7 @@ function BillingContent({
|
|
|
5520
5554
|
);
|
|
5521
5555
|
const [buyCreditsInFlight, setBuyCreditsInFlight] = (0, import_react8.useState)(false);
|
|
5522
5556
|
const [loadingBilling, setLoadingBilling] = (0, import_react8.useState)(false);
|
|
5557
|
+
const [billingOverviewLoaded, setBillingOverviewLoaded] = (0, import_react8.useState)(false);
|
|
5523
5558
|
const [loadingTable, setLoadingTable] = (0, import_react8.useState)(false);
|
|
5524
5559
|
const [showInitialLoader, setShowInitialLoader] = (0, import_react8.useState)(true);
|
|
5525
5560
|
const [initialFetchTriggered, setInitialFetchTriggered] = (0, import_react8.useState)(false);
|
|
@@ -5544,6 +5579,7 @@ function BillingContent({
|
|
|
5544
5579
|
}, [api]);
|
|
5545
5580
|
const fetchBillingOverview = (0, import_react8.useCallback)(async () => {
|
|
5546
5581
|
setLoadingBilling(true);
|
|
5582
|
+
setBillingOverviewLoaded(false);
|
|
5547
5583
|
try {
|
|
5548
5584
|
console.log("calling Billing apis");
|
|
5549
5585
|
const [subRes, creditsRes, productsRes, customRes] = await Promise.all([
|
|
@@ -5572,6 +5608,7 @@ function BillingContent({
|
|
|
5572
5608
|
} catch {
|
|
5573
5609
|
} finally {
|
|
5574
5610
|
setLoadingBilling(false);
|
|
5611
|
+
setBillingOverviewLoaded(true);
|
|
5575
5612
|
}
|
|
5576
5613
|
}, [api, workspace.current?.country]);
|
|
5577
5614
|
const fetchUserMap = (0, import_react8.useCallback)(async () => {
|
|
@@ -5713,6 +5750,12 @@ function BillingContent({
|
|
|
5713
5750
|
(0, import_react8.useEffect)(() => {
|
|
5714
5751
|
setShowInitialLoader(true);
|
|
5715
5752
|
setInitialFetchTriggered(false);
|
|
5753
|
+
setBillingOverviewLoaded(false);
|
|
5754
|
+
setSubscription(null);
|
|
5755
|
+
setAvailableCredits(null);
|
|
5756
|
+
setProducts([]);
|
|
5757
|
+
setTotalCredits(null);
|
|
5758
|
+
setCustomPlanCredits(null);
|
|
5716
5759
|
}, [workspaceId]);
|
|
5717
5760
|
(0, import_react8.useEffect)(() => {
|
|
5718
5761
|
setInitialFetchTriggered(true);
|
|
@@ -5731,17 +5774,39 @@ function BillingContent({
|
|
|
5731
5774
|
(0, import_react8.useEffect)(() => {
|
|
5732
5775
|
if (!showInitialLoader) return;
|
|
5733
5776
|
if (!initialFetchTriggered) return;
|
|
5734
|
-
if (
|
|
5777
|
+
if (!billingOverviewLoaded) return;
|
|
5735
5778
|
setShowInitialLoader(false);
|
|
5736
|
-
}, [showInitialLoader, initialFetchTriggered,
|
|
5779
|
+
}, [showInitialLoader, initialFetchTriggered, billingOverviewLoaded]);
|
|
5737
5780
|
console.log("subscription", subscription);
|
|
5738
5781
|
const isProPlan = products.some(
|
|
5739
5782
|
(product) => product.id == subscription?.stripeProductId && product.name == "Paid"
|
|
5740
5783
|
);
|
|
5741
5784
|
console.log("isProPlan", isProPlan);
|
|
5742
|
-
const
|
|
5785
|
+
const currentPlanPrice = (() => {
|
|
5786
|
+
if (products.length > 0 && subscription?.plan?.id) {
|
|
5787
|
+
for (const product of products) {
|
|
5788
|
+
const price = product.prices.find((p) => p.id === subscription.plan.id);
|
|
5789
|
+
if (price) return price;
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
return null;
|
|
5793
|
+
})();
|
|
5794
|
+
const preDowngradePlan = subscription?.downgradeScheduled && subscription.preDowngradeStripePriceData ? subscription.preDowngradeStripePriceData : null;
|
|
5795
|
+
const resolvedPlanName = (preDowngradePlan?.name?.trim() || currentPlanPrice?.metadata?.name?.trim() || subscription?.plan?.name?.trim() || (subscription?.plan?.amount != null ? subscription.plan.amount > 0 ? "Pro" : "Free" : "")).trim();
|
|
5796
|
+
const planName = isProPlan && resolvedPlanName !== "-" ? "Pro" : resolvedPlanName;
|
|
5743
5797
|
const isFreePlan = subscription?.plan?.amount == null || subscription.plan.amount === 0;
|
|
5744
|
-
const
|
|
5798
|
+
const hasResolvedPlanAmount = (preDowngradePlan?.amount ?? subscription?.plan?.amount) != null && Boolean(preDowngradePlan?.currency ?? subscription?.plan?.currency) && Boolean(preDowngradePlan?.interval ?? subscription?.plan?.interval);
|
|
5799
|
+
const planAmount = hasResolvedPlanAmount ? `${(preDowngradePlan?.currency ?? subscription?.plan?.currency) == "inr" ? "\u20B9" : "$"}${((preDowngradePlan?.amount ?? subscription.plan.amount) / 100).toFixed(2)} / ${preDowngradePlan?.interval ?? subscription?.plan?.interval}` : "";
|
|
5800
|
+
const planCreditsFromPrice = Number(
|
|
5801
|
+
preDowngradePlan?.credits ?? currentPlanPrice?.metadata?.credits
|
|
5802
|
+
);
|
|
5803
|
+
const currentPlanCredits = Number.isFinite(planCreditsFromPrice) ? planCreditsFromPrice : customPlanCredits;
|
|
5804
|
+
const planCreditsText = currentPlanCredits != null ? `${formatCredits(currentPlanCredits)} credits` : "";
|
|
5805
|
+
const scheduledDowngradeDateLabel = formatEffectiveDateLabel(
|
|
5806
|
+
subscription?.scheduledDowngradeEffectiveDate
|
|
5807
|
+
);
|
|
5808
|
+
const scheduledDowngradeText = subscription?.downgradeScheduled && subscription.plan?.name ? `Downgrades to ${subscription.plan.name}${scheduledDowngradeDateLabel ? ` ${scheduledDowngradeDateLabel}` : ""}` : void 0;
|
|
5809
|
+
const isPlanDetailsLoading = !billingOverviewLoaded || loadingBilling || subscription?.plan == null || !planName || planName === "-" || !planAmount || currentPlanCredits == null;
|
|
5745
5810
|
const usedCredits = availableCredits != null && totalCredits != null ? Math.max(0, totalCredits - availableCredits) : null;
|
|
5746
5811
|
const progressPct = usedCredits != null && totalCredits != null && totalCredits > 0 ? Math.min(100, Math.round(usedCredits / totalCredits * 100)) : 0;
|
|
5747
5812
|
const remainingPct = 100 - progressPct;
|
|
@@ -5838,12 +5903,13 @@ function BillingContent({
|
|
|
5838
5903
|
}
|
|
5839
5904
|
);
|
|
5840
5905
|
try {
|
|
5906
|
+
const topupCurrency = workspace.current?.country?.trim().toUpperCase() === "IN" ? "inr" : "usd";
|
|
5841
5907
|
const res = await api.buyCredits({
|
|
5842
5908
|
serviceName: DEFAULT_TOPUP_SERVICE,
|
|
5843
5909
|
credits,
|
|
5844
5910
|
unitAmount: price,
|
|
5845
5911
|
itemCount: 1,
|
|
5846
|
-
currency:
|
|
5912
|
+
currency: topupCurrency,
|
|
5847
5913
|
successUrl: resolveReturnUrl("success"),
|
|
5848
5914
|
cancelUrl: resolveReturnUrl("cancel"),
|
|
5849
5915
|
metadata: { source: "self-serve" }
|
|
@@ -5958,11 +6024,13 @@ function BillingContent({
|
|
|
5958
6024
|
import_ui5.ScPlanDetailsCard,
|
|
5959
6025
|
{
|
|
5960
6026
|
planName,
|
|
5961
|
-
planCredits:
|
|
6027
|
+
planCredits: planCreditsText,
|
|
5962
6028
|
planPrice: planAmount,
|
|
5963
6029
|
badgeText: "Active",
|
|
6030
|
+
badgeSubText: scheduledDowngradeText,
|
|
5964
6031
|
currentPlanLabel: "Current plan",
|
|
5965
|
-
upgradeButtonText: subscription?.downgradeScheduled ? "Cancel downgrade" : "
|
|
6032
|
+
upgradeButtonText: subscription?.downgradeScheduled ? "Cancel downgrade" : "Manage Plan",
|
|
6033
|
+
isLoading: isPlanDetailsLoading,
|
|
5966
6034
|
className: "flex-1 min-w-0",
|
|
5967
6035
|
onUpgrade: () => {
|
|
5968
6036
|
void logBillingEvent("billing_plans_opened", "Plans opened", {
|
|
@@ -6058,7 +6126,10 @@ function BillingContent({
|
|
|
6058
6126
|
showBuyCreditsModal && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6059
6127
|
BuyCreditsModal,
|
|
6060
6128
|
{
|
|
6061
|
-
|
|
6129
|
+
country: workspace.current?.country,
|
|
6130
|
+
currencySymbol: getCurrencySymbolByCountry(
|
|
6131
|
+
workspace.current?.country
|
|
6132
|
+
),
|
|
6062
6133
|
onClose: () => setShowBuyCreditsModal(false),
|
|
6063
6134
|
onBuy: (credits, price) => {
|
|
6064
6135
|
handleBuyCredits(credits, price);
|
package/dist/index.mjs
CHANGED
|
@@ -3820,41 +3820,63 @@ import { useState as useState6 } from "react";
|
|
|
3820
3820
|
import { SiconClose as SiconClose3, SiconPlus, SiconMinus } from "@streamoid/icons";
|
|
3821
3821
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3822
3822
|
var STEP = 500;
|
|
3823
|
-
var
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3823
|
+
var USD_TOPUP_CONFIG = {
|
|
3824
|
+
currencyCode: "usd",
|
|
3825
|
+
pricePerCredit: 0.08,
|
|
3826
|
+
minAmount: 40,
|
|
3827
|
+
maxAmount: 1e4
|
|
3828
|
+
};
|
|
3829
|
+
var INR_TOPUP_CONFIG = {
|
|
3830
|
+
currencyCode: "inr",
|
|
3831
|
+
pricePerCredit: 5,
|
|
3832
|
+
minAmount: 2500,
|
|
3833
|
+
maxAmount: 1e5
|
|
3834
|
+
};
|
|
3828
3835
|
function BuyCreditsModal({
|
|
3829
3836
|
currencySymbol = "$",
|
|
3837
|
+
country,
|
|
3830
3838
|
onClose,
|
|
3831
3839
|
onBuy
|
|
3832
3840
|
}) {
|
|
3833
|
-
const
|
|
3834
|
-
const
|
|
3835
|
-
const
|
|
3841
|
+
const normalizedCountry = country?.trim().toUpperCase();
|
|
3842
|
+
const topupConfig = normalizedCountry === "IN" ? INR_TOPUP_CONFIG : USD_TOPUP_CONFIG;
|
|
3843
|
+
const minCredits = Math.round(
|
|
3844
|
+
topupConfig.minAmount / topupConfig.pricePerCredit
|
|
3845
|
+
);
|
|
3846
|
+
const maxCredits = Math.round(
|
|
3847
|
+
topupConfig.maxAmount / topupConfig.pricePerCredit
|
|
3848
|
+
);
|
|
3849
|
+
const [credits, setCredits] = useState6(minCredits);
|
|
3850
|
+
const [creditsInput, setCreditsInput] = useState6(String(minCredits));
|
|
3851
|
+
const [priceInput, setPriceInput] = useState6(
|
|
3852
|
+
String(minCredits * topupConfig.pricePerCredit)
|
|
3853
|
+
);
|
|
3836
3854
|
const [activeField, setActiveField] = useState6("credits");
|
|
3837
3855
|
const parsedCredits = creditsInput.length ? Number(creditsInput) : credits;
|
|
3838
3856
|
const previewCredits = Number.isFinite(parsedCredits) ? parsedCredits : credits;
|
|
3839
3857
|
const pricedCredits = previewCredits > 0 ? previewCredits : 0;
|
|
3840
|
-
const price = Number(
|
|
3841
|
-
|
|
3842
|
-
|
|
3858
|
+
const price = Number(
|
|
3859
|
+
(pricedCredits * topupConfig.pricePerCredit).toFixed(2)
|
|
3860
|
+
);
|
|
3861
|
+
const isBelowMin = price < topupConfig.minAmount;
|
|
3862
|
+
const isAboveMax = price > topupConfig.maxAmount;
|
|
3843
3863
|
const isError = isBelowMin || isAboveMax;
|
|
3844
3864
|
const isInvalid = isError;
|
|
3845
3865
|
const syncFromCredits = (value) => {
|
|
3846
3866
|
setCredits(value);
|
|
3847
3867
|
setCreditsInput(String(value));
|
|
3848
|
-
setPriceInput(
|
|
3868
|
+
setPriceInput(
|
|
3869
|
+
String(Number((value * topupConfig.pricePerCredit).toFixed(2)))
|
|
3870
|
+
);
|
|
3849
3871
|
};
|
|
3850
|
-
const syncFromPrice = (
|
|
3851
|
-
const derived = Math.round(
|
|
3872
|
+
const syncFromPrice = (amount) => {
|
|
3873
|
+
const derived = Math.round(amount / topupConfig.pricePerCredit);
|
|
3852
3874
|
setCredits(derived);
|
|
3853
3875
|
setCreditsInput(String(derived));
|
|
3854
|
-
setPriceInput(String(
|
|
3876
|
+
setPriceInput(String(amount));
|
|
3855
3877
|
};
|
|
3856
|
-
const handleDecrement = () => syncFromCredits(Math.max(
|
|
3857
|
-
const handleIncrement = () => syncFromCredits(Math.min(
|
|
3878
|
+
const handleDecrement = () => syncFromCredits(Math.max(minCredits, credits - STEP));
|
|
3879
|
+
const handleIncrement = () => syncFromCredits(Math.min(maxCredits, credits + STEP));
|
|
3858
3880
|
const handleCreditsChange = (value) => {
|
|
3859
3881
|
const raw = value.replace(/[^\d]/g, "");
|
|
3860
3882
|
setCreditsInput(raw);
|
|
@@ -3863,7 +3885,9 @@ function BuyCreditsModal({
|
|
|
3863
3885
|
const next = Number(raw);
|
|
3864
3886
|
if (!Number.isNaN(next)) {
|
|
3865
3887
|
setCredits(next);
|
|
3866
|
-
setPriceInput(
|
|
3888
|
+
setPriceInput(
|
|
3889
|
+
String(Number((next * topupConfig.pricePerCredit).toFixed(2)))
|
|
3890
|
+
);
|
|
3867
3891
|
}
|
|
3868
3892
|
};
|
|
3869
3893
|
const handleCreditsBlur = () => {
|
|
@@ -3881,7 +3905,7 @@ function BuyCreditsModal({
|
|
|
3881
3905
|
if (!raw.length) return;
|
|
3882
3906
|
const next = Number(raw);
|
|
3883
3907
|
if (!Number.isNaN(next) && next >= 0) {
|
|
3884
|
-
const derived = Math.round(next /
|
|
3908
|
+
const derived = Math.round(next / topupConfig.pricePerCredit);
|
|
3885
3909
|
setCredits(derived);
|
|
3886
3910
|
setCreditsInput(String(derived));
|
|
3887
3911
|
}
|
|
@@ -3985,7 +4009,7 @@ function BuyCreditsModal({
|
|
|
3985
4009
|
style: {
|
|
3986
4010
|
width: 24,
|
|
3987
4011
|
height: 24,
|
|
3988
|
-
opacity: credits <=
|
|
4012
|
+
opacity: credits <= minCredits ? 0.3 : 1,
|
|
3989
4013
|
transition: "opacity 0.15s ease"
|
|
3990
4014
|
},
|
|
3991
4015
|
onClick: handleDecrement,
|
|
@@ -4043,7 +4067,7 @@ function BuyCreditsModal({
|
|
|
4043
4067
|
style: {
|
|
4044
4068
|
width: 24,
|
|
4045
4069
|
height: 24,
|
|
4046
|
-
opacity: credits >=
|
|
4070
|
+
opacity: credits >= maxCredits ? 0.3 : 1,
|
|
4047
4071
|
transition: "opacity 0.15s ease"
|
|
4048
4072
|
},
|
|
4049
4073
|
onClick: handleIncrement,
|
|
@@ -4130,7 +4154,7 @@ function BuyCreditsModal({
|
|
|
4130
4154
|
lineHeight: "var(--line-height-line-height-sm)",
|
|
4131
4155
|
color: "var(--alias-text---icons-error)"
|
|
4132
4156
|
},
|
|
4133
|
-
children: isBelowMin ? `Min. ${
|
|
4157
|
+
children: isBelowMin ? `Min. ${minCredits.toLocaleString()} credits` : `Max. ${maxCredits.toLocaleString()} credits`
|
|
4134
4158
|
}
|
|
4135
4159
|
) })
|
|
4136
4160
|
}
|
|
@@ -4475,6 +4499,16 @@ function formatNextBillingDateLabel(iso) {
|
|
|
4475
4499
|
year: "numeric"
|
|
4476
4500
|
});
|
|
4477
4501
|
}
|
|
4502
|
+
function formatEffectiveDateLabel(value) {
|
|
4503
|
+
if (value == null) return "";
|
|
4504
|
+
const parsed = typeof value === "number" ? new Date(value < 1e10 ? value * 1e3 : value) : new Date(value);
|
|
4505
|
+
if (Number.isNaN(parsed.getTime())) return "";
|
|
4506
|
+
return parsed.toLocaleDateString("en-US", {
|
|
4507
|
+
month: "short",
|
|
4508
|
+
day: "numeric",
|
|
4509
|
+
year: "numeric"
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4478
4512
|
function UpdateSubscriptionModal({
|
|
4479
4513
|
open,
|
|
4480
4514
|
currentPlanName,
|
|
@@ -5528,7 +5562,7 @@ function BillingContent({
|
|
|
5528
5562
|
const [availableCredits, setAvailableCredits] = useState7(null);
|
|
5529
5563
|
const [products, setProducts] = useState7([]);
|
|
5530
5564
|
const [invoices, setInvoices] = useState7([]);
|
|
5531
|
-
const [totalCredits, setTotalCredits] = useState7(
|
|
5565
|
+
const [totalCredits, setTotalCredits] = useState7(null);
|
|
5532
5566
|
const [usageLogs, setUsageLogs] = useState7([]);
|
|
5533
5567
|
const [userMap, setUserMap] = useState7({});
|
|
5534
5568
|
const [customPlanCredits, setCustomPlanCredits] = useState7(
|
|
@@ -5539,6 +5573,7 @@ function BillingContent({
|
|
|
5539
5573
|
);
|
|
5540
5574
|
const [buyCreditsInFlight, setBuyCreditsInFlight] = useState7(false);
|
|
5541
5575
|
const [loadingBilling, setLoadingBilling] = useState7(false);
|
|
5576
|
+
const [billingOverviewLoaded, setBillingOverviewLoaded] = useState7(false);
|
|
5542
5577
|
const [loadingTable, setLoadingTable] = useState7(false);
|
|
5543
5578
|
const [showInitialLoader, setShowInitialLoader] = useState7(true);
|
|
5544
5579
|
const [initialFetchTriggered, setInitialFetchTriggered] = useState7(false);
|
|
@@ -5563,6 +5598,7 @@ function BillingContent({
|
|
|
5563
5598
|
}, [api]);
|
|
5564
5599
|
const fetchBillingOverview = useCallback3(async () => {
|
|
5565
5600
|
setLoadingBilling(true);
|
|
5601
|
+
setBillingOverviewLoaded(false);
|
|
5566
5602
|
try {
|
|
5567
5603
|
console.log("calling Billing apis");
|
|
5568
5604
|
const [subRes, creditsRes, productsRes, customRes] = await Promise.all([
|
|
@@ -5591,6 +5627,7 @@ function BillingContent({
|
|
|
5591
5627
|
} catch {
|
|
5592
5628
|
} finally {
|
|
5593
5629
|
setLoadingBilling(false);
|
|
5630
|
+
setBillingOverviewLoaded(true);
|
|
5594
5631
|
}
|
|
5595
5632
|
}, [api, workspace.current?.country]);
|
|
5596
5633
|
const fetchUserMap = useCallback3(async () => {
|
|
@@ -5732,6 +5769,12 @@ function BillingContent({
|
|
|
5732
5769
|
useEffect4(() => {
|
|
5733
5770
|
setShowInitialLoader(true);
|
|
5734
5771
|
setInitialFetchTriggered(false);
|
|
5772
|
+
setBillingOverviewLoaded(false);
|
|
5773
|
+
setSubscription(null);
|
|
5774
|
+
setAvailableCredits(null);
|
|
5775
|
+
setProducts([]);
|
|
5776
|
+
setTotalCredits(null);
|
|
5777
|
+
setCustomPlanCredits(null);
|
|
5735
5778
|
}, [workspaceId]);
|
|
5736
5779
|
useEffect4(() => {
|
|
5737
5780
|
setInitialFetchTriggered(true);
|
|
@@ -5750,17 +5793,39 @@ function BillingContent({
|
|
|
5750
5793
|
useEffect4(() => {
|
|
5751
5794
|
if (!showInitialLoader) return;
|
|
5752
5795
|
if (!initialFetchTriggered) return;
|
|
5753
|
-
if (
|
|
5796
|
+
if (!billingOverviewLoaded) return;
|
|
5754
5797
|
setShowInitialLoader(false);
|
|
5755
|
-
}, [showInitialLoader, initialFetchTriggered,
|
|
5798
|
+
}, [showInitialLoader, initialFetchTriggered, billingOverviewLoaded]);
|
|
5756
5799
|
console.log("subscription", subscription);
|
|
5757
5800
|
const isProPlan = products.some(
|
|
5758
5801
|
(product) => product.id == subscription?.stripeProductId && product.name == "Paid"
|
|
5759
5802
|
);
|
|
5760
5803
|
console.log("isProPlan", isProPlan);
|
|
5761
|
-
const
|
|
5804
|
+
const currentPlanPrice = (() => {
|
|
5805
|
+
if (products.length > 0 && subscription?.plan?.id) {
|
|
5806
|
+
for (const product of products) {
|
|
5807
|
+
const price = product.prices.find((p) => p.id === subscription.plan.id);
|
|
5808
|
+
if (price) return price;
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
return null;
|
|
5812
|
+
})();
|
|
5813
|
+
const preDowngradePlan = subscription?.downgradeScheduled && subscription.preDowngradeStripePriceData ? subscription.preDowngradeStripePriceData : null;
|
|
5814
|
+
const resolvedPlanName = (preDowngradePlan?.name?.trim() || currentPlanPrice?.metadata?.name?.trim() || subscription?.plan?.name?.trim() || (subscription?.plan?.amount != null ? subscription.plan.amount > 0 ? "Pro" : "Free" : "")).trim();
|
|
5815
|
+
const planName = isProPlan && resolvedPlanName !== "-" ? "Pro" : resolvedPlanName;
|
|
5762
5816
|
const isFreePlan = subscription?.plan?.amount == null || subscription.plan.amount === 0;
|
|
5763
|
-
const
|
|
5817
|
+
const hasResolvedPlanAmount = (preDowngradePlan?.amount ?? subscription?.plan?.amount) != null && Boolean(preDowngradePlan?.currency ?? subscription?.plan?.currency) && Boolean(preDowngradePlan?.interval ?? subscription?.plan?.interval);
|
|
5818
|
+
const planAmount = hasResolvedPlanAmount ? `${(preDowngradePlan?.currency ?? subscription?.plan?.currency) == "inr" ? "\u20B9" : "$"}${((preDowngradePlan?.amount ?? subscription.plan.amount) / 100).toFixed(2)} / ${preDowngradePlan?.interval ?? subscription?.plan?.interval}` : "";
|
|
5819
|
+
const planCreditsFromPrice = Number(
|
|
5820
|
+
preDowngradePlan?.credits ?? currentPlanPrice?.metadata?.credits
|
|
5821
|
+
);
|
|
5822
|
+
const currentPlanCredits = Number.isFinite(planCreditsFromPrice) ? planCreditsFromPrice : customPlanCredits;
|
|
5823
|
+
const planCreditsText = currentPlanCredits != null ? `${formatCredits(currentPlanCredits)} credits` : "";
|
|
5824
|
+
const scheduledDowngradeDateLabel = formatEffectiveDateLabel(
|
|
5825
|
+
subscription?.scheduledDowngradeEffectiveDate
|
|
5826
|
+
);
|
|
5827
|
+
const scheduledDowngradeText = subscription?.downgradeScheduled && subscription.plan?.name ? `Downgrades to ${subscription.plan.name}${scheduledDowngradeDateLabel ? ` ${scheduledDowngradeDateLabel}` : ""}` : void 0;
|
|
5828
|
+
const isPlanDetailsLoading = !billingOverviewLoaded || loadingBilling || subscription?.plan == null || !planName || planName === "-" || !planAmount || currentPlanCredits == null;
|
|
5764
5829
|
const usedCredits = availableCredits != null && totalCredits != null ? Math.max(0, totalCredits - availableCredits) : null;
|
|
5765
5830
|
const progressPct = usedCredits != null && totalCredits != null && totalCredits > 0 ? Math.min(100, Math.round(usedCredits / totalCredits * 100)) : 0;
|
|
5766
5831
|
const remainingPct = 100 - progressPct;
|
|
@@ -5857,12 +5922,13 @@ function BillingContent({
|
|
|
5857
5922
|
}
|
|
5858
5923
|
);
|
|
5859
5924
|
try {
|
|
5925
|
+
const topupCurrency = workspace.current?.country?.trim().toUpperCase() === "IN" ? "inr" : "usd";
|
|
5860
5926
|
const res = await api.buyCredits({
|
|
5861
5927
|
serviceName: DEFAULT_TOPUP_SERVICE,
|
|
5862
5928
|
credits,
|
|
5863
5929
|
unitAmount: price,
|
|
5864
5930
|
itemCount: 1,
|
|
5865
|
-
currency:
|
|
5931
|
+
currency: topupCurrency,
|
|
5866
5932
|
successUrl: resolveReturnUrl("success"),
|
|
5867
5933
|
cancelUrl: resolveReturnUrl("cancel"),
|
|
5868
5934
|
metadata: { source: "self-serve" }
|
|
@@ -5977,11 +6043,13 @@ function BillingContent({
|
|
|
5977
6043
|
ScPlanDetailsCard,
|
|
5978
6044
|
{
|
|
5979
6045
|
planName,
|
|
5980
|
-
planCredits:
|
|
6046
|
+
planCredits: planCreditsText,
|
|
5981
6047
|
planPrice: planAmount,
|
|
5982
6048
|
badgeText: "Active",
|
|
6049
|
+
badgeSubText: scheduledDowngradeText,
|
|
5983
6050
|
currentPlanLabel: "Current plan",
|
|
5984
|
-
upgradeButtonText: subscription?.downgradeScheduled ? "Cancel downgrade" : "
|
|
6051
|
+
upgradeButtonText: subscription?.downgradeScheduled ? "Cancel downgrade" : "Manage Plan",
|
|
6052
|
+
isLoading: isPlanDetailsLoading,
|
|
5985
6053
|
className: "flex-1 min-w-0",
|
|
5986
6054
|
onUpgrade: () => {
|
|
5987
6055
|
void logBillingEvent("billing_plans_opened", "Plans opened", {
|
|
@@ -6077,7 +6145,10 @@ function BillingContent({
|
|
|
6077
6145
|
showBuyCreditsModal && /* @__PURE__ */ jsx11(
|
|
6078
6146
|
BuyCreditsModal,
|
|
6079
6147
|
{
|
|
6080
|
-
|
|
6148
|
+
country: workspace.current?.country,
|
|
6149
|
+
currencySymbol: getCurrencySymbolByCountry(
|
|
6150
|
+
workspace.current?.country
|
|
6151
|
+
),
|
|
6081
6152
|
onClose: () => setShowBuyCreditsModal(false),
|
|
6082
6153
|
onBuy: (credits, price) => {
|
|
6083
6154
|
handleBuyCredits(credits, price);
|