@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 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 PRICE_PER_CREDIT = 0.08;
3805
- var MIN_USD = 40;
3806
- var MAX_USD = 1e4;
3807
- var MIN_CREDITS = Math.round(MIN_USD / PRICE_PER_CREDIT);
3808
- var MAX_CREDITS = Math.round(MAX_USD / PRICE_PER_CREDIT);
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 [credits, setCredits] = (0, import_react7.useState)(MIN_CREDITS);
3815
- const [creditsInput, setCreditsInput] = (0, import_react7.useState)(String(MIN_CREDITS));
3816
- const [priceInput, setPriceInput] = (0, import_react7.useState)(String(MIN_CREDITS * PRICE_PER_CREDIT));
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((pricedCredits * PRICE_PER_CREDIT).toFixed(2));
3822
- const isBelowMin = price < MIN_USD;
3823
- const isAboveMax = price > MAX_USD;
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(String(Number((value * PRICE_PER_CREDIT).toFixed(2))));
3849
+ setPriceInput(
3850
+ String(Number((value * topupConfig.pricePerCredit).toFixed(2)))
3851
+ );
3830
3852
  };
3831
- const syncFromPrice = (usd) => {
3832
- const derived = Math.round(usd / PRICE_PER_CREDIT);
3853
+ const syncFromPrice = (amount) => {
3854
+ const derived = Math.round(amount / topupConfig.pricePerCredit);
3833
3855
  setCredits(derived);
3834
3856
  setCreditsInput(String(derived));
3835
- setPriceInput(String(usd));
3857
+ setPriceInput(String(amount));
3836
3858
  };
3837
- const handleDecrement = () => syncFromCredits(Math.max(MIN_CREDITS, credits - STEP));
3838
- const handleIncrement = () => syncFromCredits(Math.min(MAX_CREDITS, credits + STEP));
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(String(Number((next * PRICE_PER_CREDIT).toFixed(2))));
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 / PRICE_PER_CREDIT);
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 <= MIN_CREDITS ? 0.3 : 1,
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 >= MAX_CREDITS ? 0.3 : 1,
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. ${MIN_CREDITS.toLocaleString()} credits` : `Max. ${MAX_CREDITS.toLocaleString()} credits`
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)(0);
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 (loadingBilling) return;
5777
+ if (!billingOverviewLoaded) return;
5735
5778
  setShowInitialLoader(false);
5736
- }, [showInitialLoader, initialFetchTriggered, loadingBilling]);
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 planName = isProPlan ? "Pro" : subscription?.plan?.name?.trim() || (subscription?.plan?.amount ? subscription.plan.amount > 0 ? "Pro" : "Free" : "-");
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 planAmount = subscription?.plan?.amount != null ? `${subscription?.plan?.currency == "inr" ? "\u20B9" : "$"}${(subscription.plan.amount / 100).toFixed(2)} / ${subscription?.plan?.interval}` : `${getCurrencySymbolByCountry(workspace.current?.country)}0`;
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: "usd",
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: totalCredits != null ? `${formatCredits(totalCredits)} credits` : "\u2014",
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" : "Upgrade",
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
- currencySymbol: getCurrencySymbolByCountry(workspace.current?.country),
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 PRICE_PER_CREDIT = 0.08;
3824
- var MIN_USD = 40;
3825
- var MAX_USD = 1e4;
3826
- var MIN_CREDITS = Math.round(MIN_USD / PRICE_PER_CREDIT);
3827
- var MAX_CREDITS = Math.round(MAX_USD / PRICE_PER_CREDIT);
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 [credits, setCredits] = useState6(MIN_CREDITS);
3834
- const [creditsInput, setCreditsInput] = useState6(String(MIN_CREDITS));
3835
- const [priceInput, setPriceInput] = useState6(String(MIN_CREDITS * PRICE_PER_CREDIT));
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((pricedCredits * PRICE_PER_CREDIT).toFixed(2));
3841
- const isBelowMin = price < MIN_USD;
3842
- const isAboveMax = price > MAX_USD;
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(String(Number((value * PRICE_PER_CREDIT).toFixed(2))));
3868
+ setPriceInput(
3869
+ String(Number((value * topupConfig.pricePerCredit).toFixed(2)))
3870
+ );
3849
3871
  };
3850
- const syncFromPrice = (usd) => {
3851
- const derived = Math.round(usd / PRICE_PER_CREDIT);
3872
+ const syncFromPrice = (amount) => {
3873
+ const derived = Math.round(amount / topupConfig.pricePerCredit);
3852
3874
  setCredits(derived);
3853
3875
  setCreditsInput(String(derived));
3854
- setPriceInput(String(usd));
3876
+ setPriceInput(String(amount));
3855
3877
  };
3856
- const handleDecrement = () => syncFromCredits(Math.max(MIN_CREDITS, credits - STEP));
3857
- const handleIncrement = () => syncFromCredits(Math.min(MAX_CREDITS, credits + STEP));
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(String(Number((next * PRICE_PER_CREDIT).toFixed(2))));
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 / PRICE_PER_CREDIT);
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 <= MIN_CREDITS ? 0.3 : 1,
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 >= MAX_CREDITS ? 0.3 : 1,
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. ${MIN_CREDITS.toLocaleString()} credits` : `Max. ${MAX_CREDITS.toLocaleString()} credits`
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(0);
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 (loadingBilling) return;
5796
+ if (!billingOverviewLoaded) return;
5754
5797
  setShowInitialLoader(false);
5755
- }, [showInitialLoader, initialFetchTriggered, loadingBilling]);
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 planName = isProPlan ? "Pro" : subscription?.plan?.name?.trim() || (subscription?.plan?.amount ? subscription.plan.amount > 0 ? "Pro" : "Free" : "-");
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 planAmount = subscription?.plan?.amount != null ? `${subscription?.plan?.currency == "inr" ? "\u20B9" : "$"}${(subscription.plan.amount / 100).toFixed(2)} / ${subscription?.plan?.interval}` : `${getCurrencySymbolByCountry(workspace.current?.country)}0`;
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: "usd",
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: totalCredits != null ? `${formatCredits(totalCredits)} credits` : "\u2014",
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" : "Upgrade",
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
- currencySymbol: getCurrencySymbolByCountry(workspace.current?.country),
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoid/settings",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",