@schematichq/schematic-components 2.20.0 → 2.21.0

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.
@@ -4962,6 +4962,9 @@ var en_default = {
4962
4962
  "After the trial, subscribe": "After the trial, subscription starts and you will be billed.",
4963
4963
  Agreement: "Agreement",
4964
4964
  "Amount off": "{{amount}} off",
4965
+ "Applied balance towards next invoice": "Applied balance towards next invoice",
4966
+ "Discount for months_one": "{{discount}} for next month",
4967
+ "Discount for months_other": "{{discount}} for next {{count}} months",
4965
4968
  "Auto Top-up": "Auto top-up",
4966
4969
  "Auto top-up enabled": "Auto top-up enabled",
4967
4970
  "Auto top-up disabled": "Auto top-up disabled",
@@ -5057,7 +5060,7 @@ var en_default = {
5057
5060
  Proration: "Proration",
5058
5061
  Quantity: "Quantity",
5059
5062
  "Quantity to pay for in advance": "Quantity to pay for in advance",
5060
- "Remaining balance": "Remaining balance",
5063
+ "Remaining balance after next invoice": "Remaining balance after next invoice",
5061
5064
  Remove: "Remove",
5062
5065
  "Remove add-on": "Remove add-on",
5063
5066
  Resets: "Resets {{date}}",
@@ -5132,6 +5135,14 @@ var en_default = {
5132
5135
  "X units per use": "{{amount}} {{units}} per use",
5133
5136
  "X time left in trial": "{{amount}} {{units}} left in trial",
5134
5137
  "Yearly total": "Yearly total",
5138
+ "You will be billed": "You will be billed {{price}} {{usage}}for this subscription every {{period}} {{schedule}}unless you unsubscribe.",
5139
+ "You will be billed with discount window": "You will be billed {{price}} {{usage}}for this subscription every {{period}} {{schedule}}{{window}}, then {{fullPrice}} every {{period}} afterward, unless you unsubscribe.",
5140
+ "You will be billed next bill discount": "You will be billed {{price}} {{usage}}for this subscription on your next bill, then {{fullPrice}} every {{period}} {{schedule}}afterward, unless you unsubscribe.",
5141
+ "plus usage based costs": "plus usage based costs",
5142
+ "on the day": "on the {{day}}",
5143
+ "of month": "of {{month}}",
5144
+ "for the next months_one": "for the next month",
5145
+ "for the next months_other": "for the next {{count}} months",
5135
5146
  "You will be downgraded at the end of your billing period.": "You will be downgraded to the {{plan}} plan at the end of your billing period on {{date}}.",
5136
5147
  "You will retain access to your plan until the end of the billing period, on": "You will retain access to your plan until the end of the billing period, on",
5137
5148
  "$X per unit": "{{cost}} per {{unit}}",
@@ -5819,7 +5830,7 @@ var i;
5819
5830
  var c = "undefined" != typeof process && void 0 !== process.env && (process.env.REACT_APP_SC_ATTR || process.env.SC_ATTR) || "data-styled";
5820
5831
  var a = "active";
5821
5832
  var l = "data-styled-version";
5822
- var u = "6.4.3";
5833
+ var u = "6.4.4";
5823
5834
  var h = "/*!sc*/\n";
5824
5835
  var d = "undefined" != typeof window && "undefined" != typeof document;
5825
5836
  function p(e2) {
@@ -8227,6 +8238,20 @@ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
8227
8238
  return json;
8228
8239
  }
8229
8240
 
8241
+ // src/api/checkoutexternal/models/WarningTier.ts
8242
+ function WarningTierFromJSON(json) {
8243
+ return WarningTierFromJSONTyped(json, false);
8244
+ }
8245
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
8246
+ if (json == null) {
8247
+ return json;
8248
+ }
8249
+ return {
8250
+ key: json["key"],
8251
+ value: json["value"]
8252
+ };
8253
+ }
8254
+
8230
8255
  // src/api/checkoutexternal/models/FeatureEntitlement.ts
8231
8256
  function FeatureEntitlementFromJSON(json) {
8232
8257
  return FeatureEntitlementFromJSONTyped(json, false);
@@ -8253,7 +8278,8 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8253
8278
  monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
8254
8279
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
8255
8280
  usage: json["usage"] == null ? void 0 : json["usage"],
8256
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
8281
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
8282
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
8257
8283
  };
8258
8284
  }
8259
8285
 
@@ -8600,6 +8626,7 @@ function CompanyOverrideNoteResponseDataFromJSONTyped(json, ignoreDiscriminator)
8600
8626
  var FeatureType = {
8601
8627
  Boolean: "boolean",
8602
8628
  Event: "event",
8629
+ License: "license",
8603
8630
  Trait: "trait"
8604
8631
  };
8605
8632
  function FeatureTypeFromJSON(json) {
@@ -8632,13 +8659,15 @@ function FeatureResponseDataFromJSONTyped(json, ignoreDiscriminator) {
8632
8659
  featureType: FeatureTypeFromJSON(json["feature_type"]),
8633
8660
  icon: json["icon"],
8634
8661
  id: json["id"],
8662
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
8635
8663
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON(json["lifecycle_phase"]),
8636
8664
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
8637
8665
  name: json["name"],
8638
8666
  pluralName: json["plural_name"] == null ? void 0 : json["plural_name"],
8639
8667
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
8640
8668
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
8641
- updatedAt: new Date(json["updated_at"])
8669
+ updatedAt: new Date(json["updated_at"]),
8670
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
8642
8671
  };
8643
8672
  }
8644
8673
 
@@ -8990,6 +9019,7 @@ function FeatureInPlanResponseDataFromJSONTyped(json, ignoreDiscriminator) {
8990
9019
  flags: json["flags"].map(FlagInPlanResponseDataFromJSON),
8991
9020
  icon: json["icon"],
8992
9021
  id: json["id"],
9022
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
8993
9023
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON(json["lifecycle_phase"]),
8994
9024
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
8995
9025
  name: json["name"],
@@ -8998,7 +9028,8 @@ function FeatureInPlanResponseDataFromJSONTyped(json, ignoreDiscriminator) {
8998
9028
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
8999
9029
  trait: json["trait"] == null ? void 0 : EntityTraitDefinitionResponseDataFromJSON(json["trait"]),
9000
9030
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
9001
- updatedAt: new Date(json["updated_at"])
9031
+ updatedAt: new Date(json["updated_at"]),
9032
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
9002
9033
  };
9003
9034
  }
9004
9035
 
@@ -9075,6 +9106,20 @@ function PlanCreditGrantViewFromJSONTyped(json, ignoreDiscriminator) {
9075
9106
  };
9076
9107
  }
9077
9108
 
9109
+ // src/api/checkoutexternal/models/PlanCatalogMembershipResponseData.ts
9110
+ function PlanCatalogMembershipResponseDataFromJSON(json) {
9111
+ return PlanCatalogMembershipResponseDataFromJSONTyped(json, false);
9112
+ }
9113
+ function PlanCatalogMembershipResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9114
+ if (json == null) {
9115
+ return json;
9116
+ }
9117
+ return {
9118
+ id: json["id"],
9119
+ name: json["name"]
9120
+ };
9121
+ }
9122
+
9078
9123
  // src/api/checkoutexternal/models/PlanCurrencyPricesResponseData.ts
9079
9124
  function PlanCurrencyPricesResponseDataFromJSON(json) {
9080
9125
  return PlanCurrencyPricesResponseDataFromJSONTyped(json, false);
@@ -9231,6 +9276,9 @@ function CompanyPlanDetailResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9231
9276
  ),
9232
9277
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON(json["billing_product"]),
9233
9278
  billingStrategy: BillingStrategyFromJSON(json["billing_strategy"]),
9279
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
9280
+ PlanCatalogMembershipResponseDataFromJSON
9281
+ ),
9234
9282
  chargeType: ChargeTypeFromJSON(json["charge_type"]),
9235
9283
  companyCanTrial: json["company_can_trial"],
9236
9284
  companyCount: json["company_count"],
@@ -9404,6 +9452,9 @@ function PlanDetailResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9404
9452
  ),
9405
9453
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON(json["billing_product"]),
9406
9454
  billingStrategy: BillingStrategyFromJSON(json["billing_strategy"]),
9455
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
9456
+ PlanCatalogMembershipResponseDataFromJSON
9457
+ ),
9407
9458
  chargeType: ChargeTypeFromJSON(json["charge_type"]),
9408
9459
  companyCount: json["company_count"],
9409
9460
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
@@ -9573,6 +9624,7 @@ function ComponentResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9573
9624
  }
9574
9625
  return {
9575
9626
  ast: json["ast"] == null ? void 0 : json["ast"],
9627
+ catalogId: json["catalog_id"] == null ? void 0 : json["catalog_id"],
9576
9628
  createdAt: new Date(json["created_at"]),
9577
9629
  id: json["id"],
9578
9630
  name: json["name"],
@@ -9809,6 +9861,29 @@ function PreviewSubscriptionUpcomingInvoiceLineItemsFromJSONTyped(json, ignoreDi
9809
9861
  };
9810
9862
  }
9811
9863
 
9864
+ // src/api/checkoutexternal/models/PreviewSubscriptionDiscountResponseData.ts
9865
+ function PreviewSubscriptionDiscountResponseDataFromJSON(json) {
9866
+ return PreviewSubscriptionDiscountResponseDataFromJSONTyped(json, false);
9867
+ }
9868
+ function PreviewSubscriptionDiscountResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9869
+ if (json == null) {
9870
+ return json;
9871
+ }
9872
+ return {
9873
+ amountOff: json["amount_off"] == null ? void 0 : json["amount_off"],
9874
+ couponName: json["coupon_name"],
9875
+ currency: json["currency"] == null ? void 0 : json["currency"],
9876
+ customerFacingCode: json["customer_facing_code"] == null ? void 0 : json["customer_facing_code"],
9877
+ duration: json["duration"],
9878
+ durationInMonths: json["duration_in_months"] == null ? void 0 : json["duration_in_months"],
9879
+ endedAt: json["ended_at"] == null ? void 0 : new Date(json["ended_at"]),
9880
+ isActive: json["is_active"],
9881
+ percentOff: json["percent_off"] == null ? void 0 : json["percent_off"],
9882
+ promoCodeExternalId: json["promo_code_external_id"] == null ? void 0 : json["promo_code_external_id"],
9883
+ startedAt: new Date(json["started_at"])
9884
+ };
9885
+ }
9886
+
9812
9887
  // src/api/checkoutexternal/models/PreviewSubscriptionFinanceResponseData.ts
9813
9888
  function PreviewSubscriptionFinanceResponseDataFromJSON(json) {
9814
9889
  return PreviewSubscriptionFinanceResponseDataFromJSONTyped(json, false);
@@ -9819,6 +9894,9 @@ function PreviewSubscriptionFinanceResponseDataFromJSONTyped(json, ignoreDiscrim
9819
9894
  }
9820
9895
  return {
9821
9896
  amountOff: json["amount_off"],
9897
+ discounts: json["discounts"].map(
9898
+ PreviewSubscriptionDiscountResponseDataFromJSON
9899
+ ),
9822
9900
  dueNow: json["due_now"],
9823
9901
  newCharges: json["new_charges"],
9824
9902
  percentOff: json["percent_off"],
@@ -11436,13 +11514,15 @@ function FeatureResponseDataFromJSONTyped5(json, ignoreDiscriminator) {
11436
11514
  featureType: FeatureTypeFromJSON2(json["feature_type"]),
11437
11515
  icon: json["icon"],
11438
11516
  id: json["id"],
11517
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
11439
11518
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON2(json["lifecycle_phase"]),
11440
11519
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
11441
11520
  name: json["name"],
11442
11521
  pluralName: json["plural_name"] == null ? void 0 : json["plural_name"],
11443
11522
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
11444
11523
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
11445
- updatedAt: new Date(json["updated_at"])
11524
+ updatedAt: new Date(json["updated_at"]),
11525
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
11446
11526
  };
11447
11527
  }
11448
11528
 
@@ -11499,6 +11579,7 @@ function FeatureInPlanResponseDataFromJSONTyped6(json, ignoreDiscriminator) {
11499
11579
  flags: json["flags"].map(FlagInPlanResponseDataFromJSON2),
11500
11580
  icon: json["icon"],
11501
11581
  id: json["id"],
11582
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
11502
11583
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON2(json["lifecycle_phase"]),
11503
11584
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
11504
11585
  name: json["name"],
@@ -11507,7 +11588,8 @@ function FeatureInPlanResponseDataFromJSONTyped6(json, ignoreDiscriminator) {
11507
11588
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
11508
11589
  trait: json["trait"] == null ? void 0 : EntityTraitDefinitionResponseDataFromJSON2(json["trait"]),
11509
11590
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
11510
- updatedAt: new Date(json["updated_at"])
11591
+ updatedAt: new Date(json["updated_at"]),
11592
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
11511
11593
  };
11512
11594
  }
11513
11595
 
@@ -11686,6 +11768,20 @@ function PlanCreditGrantViewFromJSONTyped3(json, ignoreDiscriminator) {
11686
11768
  };
11687
11769
  }
11688
11770
 
11771
+ // src/api/componentspublic/models/PlanCatalogMembershipResponseData.ts
11772
+ function PlanCatalogMembershipResponseDataFromJSON2(json) {
11773
+ return PlanCatalogMembershipResponseDataFromJSONTyped5(json, false);
11774
+ }
11775
+ function PlanCatalogMembershipResponseDataFromJSONTyped5(json, ignoreDiscriminator) {
11776
+ if (json == null) {
11777
+ return json;
11778
+ }
11779
+ return {
11780
+ id: json["id"],
11781
+ name: json["name"]
11782
+ };
11783
+ }
11784
+
11689
11785
  // src/api/componentspublic/models/PlanCurrencyPricesResponseData.ts
11690
11786
  function PlanCurrencyPricesResponseDataFromJSON2(json) {
11691
11787
  return PlanCurrencyPricesResponseDataFromJSONTyped5(json, false);
@@ -11753,6 +11849,9 @@ function PlanViewPublicResponseDataFromJSONTyped(json, ignoreDiscriminator) {
11753
11849
  ),
11754
11850
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON2(json["billing_product"]),
11755
11851
  billingStrategy: BillingStrategyFromJSON2(json["billing_strategy"]),
11852
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
11853
+ PlanCatalogMembershipResponseDataFromJSON2
11854
+ ),
11756
11855
  chargeType: ChargeTypeFromJSON2(json["charge_type"]),
11757
11856
  companyCount: json["company_count"],
11758
11857
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
@@ -12370,7 +12469,7 @@ function getMetricPeriodName(entitlement) {
12370
12469
  const name = period ? PeriodName[period] : void 0;
12371
12470
  return name;
12372
12471
  }
12373
- function getUsageDetails(entitlement, period, currency) {
12472
+ function getUsageDetails(entitlement, period, currency, options) {
12374
12473
  const billingPrice = currency ? getEntitlementPrice(entitlement, period ?? "month", currency) : period === "year" ? entitlement.yearlyUsageBasedPrice : period === "quarter" ? entitlement.quarterlyUsageBasedPrice : period === "month" ? entitlement.monthlyUsageBasedPrice : void 0;
12375
12474
  let limit;
12376
12475
  if ((!entitlement.priceBehavior || entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance) && typeof entitlement.allocation === "number") {
@@ -12418,8 +12517,21 @@ function getUsageDetails(entitlement, period, currency) {
12418
12517
  start = end + 1;
12419
12518
  }
12420
12519
  }
12520
+ if (options?.showWarningThresholdAsLimit) {
12521
+ const warningThreshold = getEntitlementWarningThreshold(
12522
+ entitlement.planEntitlement?.warningTiers
12523
+ );
12524
+ if (typeof warningThreshold === "number") {
12525
+ limit = warningThreshold;
12526
+ }
12527
+ }
12421
12528
  return { billingPrice, limit, amount, cost, currentTier };
12422
12529
  }
12530
+ var WARNING_TIER_DEFAULT_KEY = "default";
12531
+ function getEntitlementWarningThreshold(warningTiers) {
12532
+ const tier = warningTiers?.find((t3) => t3?.key === WARNING_TIER_DEFAULT_KEY);
12533
+ return typeof tier?.value === "number" ? tier.value : void 0;
12534
+ }
12423
12535
  function getCreditBasedEntitlementLimit(entitlement, credits) {
12424
12536
  const matchedCredit = credits.find(
12425
12537
  (credit) => credit.id === entitlement.valueCredit?.id
@@ -12967,85 +13079,6 @@ function modifyDate(date, days) {
12967
13079
  return copy3;
12968
13080
  }
12969
13081
 
12970
- // src/utils/error.ts
12971
- function isError(value) {
12972
- return value instanceof Error;
12973
- }
12974
- var ERROR_UNKNOWN = new Error("An unknown error occurred.");
12975
-
12976
- // src/utils/event.ts
12977
- var createKeyboardExecutionHandler = (fn) => {
12978
- const handler = (event) => {
12979
- if (event.key === "Enter" || event.key === " ") {
12980
- event.preventDefault();
12981
- fn?.(event);
12982
- }
12983
- };
12984
- return handler;
12985
- };
12986
-
12987
- // src/utils/markdown.tsx
12988
- import { Fragment as Fragment2 } from "react";
12989
- import { jsx } from "react/jsx-runtime";
12990
- var TOKEN = /(\[[^\]]+\]\([^)\s]+\))|(\*\*[^*]+\*\*)|(\*[^*]+\*)/g;
12991
- var LINK = /^\[([^\]]+)\]\(([^)\s]+)\)$/;
12992
- var isSafeUrl = (url) => {
12993
- try {
12994
- const { protocol } = new URL(url);
12995
- return protocol === "http:" || protocol === "https:";
12996
- } catch {
12997
- return false;
12998
- }
12999
- };
13000
- var renderOptInMarkdown = (text) => {
13001
- if (!text) {
13002
- return null;
13003
- }
13004
- const nodes = [];
13005
- let lastIndex = 0;
13006
- let key = 0;
13007
- TOKEN.lastIndex = 0;
13008
- let match2;
13009
- while ((match2 = TOKEN.exec(text)) !== null) {
13010
- if (match2.index > lastIndex) {
13011
- nodes.push(
13012
- /* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex, match2.index) }, key++)
13013
- );
13014
- }
13015
- const [token2, link, bold, italic] = match2;
13016
- if (link) {
13017
- const parts = LINK.exec(link);
13018
- if (parts && isSafeUrl(parts[2])) {
13019
- nodes.push(
13020
- /* @__PURE__ */ jsx(
13021
- Text,
13022
- {
13023
- as: "a",
13024
- display: "link",
13025
- href: parts[2],
13026
- target: "_blank",
13027
- rel: "noopener noreferrer",
13028
- children: parts[1]
13029
- },
13030
- key++
13031
- )
13032
- );
13033
- } else {
13034
- nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: parts ? parts[1] : token2 }, key++));
13035
- }
13036
- } else if (bold) {
13037
- nodes.push(/* @__PURE__ */ jsx("strong", { children: bold.slice(2, -2) }, key++));
13038
- } else if (italic) {
13039
- nodes.push(/* @__PURE__ */ jsx("em", { children: italic.slice(1, -1) }, key++));
13040
- }
13041
- lastIndex = match2.index + token2.length;
13042
- }
13043
- if (lastIndex < text.length) {
13044
- nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex) }, key));
13045
- }
13046
- return nodes;
13047
- };
13048
-
13049
13082
  // src/utils/string.ts
13050
13083
  var ZERO_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
13051
13084
  "BIF",
@@ -13194,6 +13227,168 @@ function getCurrencySymbol(currency) {
13194
13227
  }
13195
13228
  }
13196
13229
 
13230
+ // src/utils/discount.ts
13231
+ function getSubscriptionDiscount(discounts, subscriptionTotal, subscriptionCurrency) {
13232
+ const activeDiscounts = (discounts || []).filter(
13233
+ (discount2) => discount2.isActive && (typeof discount2.percentOff === "number" && discount2.percentOff > 0 || typeof discount2.amountOff === "number" && discount2.amountOff > 0)
13234
+ );
13235
+ if (activeDiscounts.length !== 1) {
13236
+ return void 0;
13237
+ }
13238
+ const discount = activeDiscounts[0];
13239
+ const isPercentOff = typeof discount.percentOff === "number" && discount.percentOff > 0;
13240
+ if (!isPercentOff && discount.currency && subscriptionCurrency && discount.currency.toLowerCase() !== subscriptionCurrency.toLowerCase()) {
13241
+ return void 0;
13242
+ }
13243
+ const discountedTotal = isPercentOff ? subscriptionTotal * (1 - discount.percentOff / 100) : Math.max(0, subscriptionTotal - (discount.amountOff ?? 0));
13244
+ if (discountedTotal >= subscriptionTotal) {
13245
+ return void 0;
13246
+ }
13247
+ return {
13248
+ duration: discount.duration,
13249
+ durationInMonths: discount.durationInMonths ?? void 0,
13250
+ discountedPrice: formatCurrency(
13251
+ discountedTotal,
13252
+ subscriptionCurrency ?? void 0
13253
+ )
13254
+ };
13255
+ }
13256
+ function getBillingPreviewText({
13257
+ subscriptionPrice,
13258
+ planPeriod,
13259
+ periodStart,
13260
+ hasUsageBasedCosts,
13261
+ discount
13262
+ }, t3) {
13263
+ if (!subscriptionPrice) {
13264
+ return null;
13265
+ }
13266
+ const usage = hasUsageBasedCosts ? `${t3("plus usage based costs")} ` : "";
13267
+ const scheduleParts = [];
13268
+ if (periodStart) {
13269
+ scheduleParts.push(
13270
+ t3("on the day", { day: formatOrdinal(periodStart.getDate()) })
13271
+ );
13272
+ }
13273
+ if (planPeriod === "year" && periodStart) {
13274
+ scheduleParts.push(t3("of month", { month: getMonthName(periodStart) }));
13275
+ }
13276
+ const schedule = scheduleParts.length > 0 ? `${scheduleParts.join(" ")} ` : "";
13277
+ if (!discount) {
13278
+ return t3("You will be billed", {
13279
+ price: subscriptionPrice,
13280
+ usage,
13281
+ period: planPeriod,
13282
+ schedule
13283
+ });
13284
+ }
13285
+ const { duration, durationInMonths, discountedPrice } = discount;
13286
+ if (duration === "forever") {
13287
+ return t3("You will be billed", {
13288
+ price: discountedPrice,
13289
+ usage,
13290
+ period: planPeriod,
13291
+ schedule
13292
+ });
13293
+ }
13294
+ if (duration === "repeating" && durationInMonths) {
13295
+ return t3("You will be billed with discount window", {
13296
+ price: discountedPrice,
13297
+ usage,
13298
+ period: planPeriod,
13299
+ schedule,
13300
+ window: t3("for the next months", { count: durationInMonths }),
13301
+ fullPrice: subscriptionPrice
13302
+ });
13303
+ }
13304
+ return t3("You will be billed next bill discount", {
13305
+ price: discountedPrice,
13306
+ usage,
13307
+ period: planPeriod,
13308
+ schedule,
13309
+ fullPrice: subscriptionPrice
13310
+ });
13311
+ }
13312
+
13313
+ // src/utils/error.ts
13314
+ function isError(value) {
13315
+ return value instanceof Error;
13316
+ }
13317
+ var ERROR_UNKNOWN = new Error("An unknown error occurred.");
13318
+
13319
+ // src/utils/event.ts
13320
+ var createKeyboardExecutionHandler = (fn) => {
13321
+ const handler = (event) => {
13322
+ if (event.key === "Enter" || event.key === " ") {
13323
+ event.preventDefault();
13324
+ fn?.(event);
13325
+ }
13326
+ };
13327
+ return handler;
13328
+ };
13329
+
13330
+ // src/utils/markdown.tsx
13331
+ import { Fragment as Fragment2 } from "react";
13332
+ import { jsx } from "react/jsx-runtime";
13333
+ var TOKEN = /(\[[^\]]+\]\([^)\s]+\))|(\*\*[^*]+\*\*)|(\*[^*]+\*)/g;
13334
+ var LINK = /^\[([^\]]+)\]\(([^)\s]+)\)$/;
13335
+ var isSafeUrl = (url) => {
13336
+ try {
13337
+ const { protocol } = new URL(url);
13338
+ return protocol === "http:" || protocol === "https:";
13339
+ } catch {
13340
+ return false;
13341
+ }
13342
+ };
13343
+ var renderOptInMarkdown = (text) => {
13344
+ if (!text) {
13345
+ return null;
13346
+ }
13347
+ const nodes = [];
13348
+ let lastIndex = 0;
13349
+ let key = 0;
13350
+ TOKEN.lastIndex = 0;
13351
+ let match2;
13352
+ while ((match2 = TOKEN.exec(text)) !== null) {
13353
+ if (match2.index > lastIndex) {
13354
+ nodes.push(
13355
+ /* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex, match2.index) }, key++)
13356
+ );
13357
+ }
13358
+ const [token2, link, bold, italic] = match2;
13359
+ if (link) {
13360
+ const parts = LINK.exec(link);
13361
+ if (parts && isSafeUrl(parts[2])) {
13362
+ nodes.push(
13363
+ /* @__PURE__ */ jsx(
13364
+ Text,
13365
+ {
13366
+ as: "a",
13367
+ display: "link",
13368
+ href: parts[2],
13369
+ target: "_blank",
13370
+ rel: "noopener noreferrer",
13371
+ children: parts[1]
13372
+ },
13373
+ key++
13374
+ )
13375
+ );
13376
+ } else {
13377
+ nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: parts ? parts[1] : token2 }, key++));
13378
+ }
13379
+ } else if (bold) {
13380
+ nodes.push(/* @__PURE__ */ jsx("strong", { children: bold.slice(2, -2) }, key++));
13381
+ } else if (italic) {
13382
+ nodes.push(/* @__PURE__ */ jsx("em", { children: italic.slice(1, -1) }, key++));
13383
+ }
13384
+ lastIndex = match2.index + token2.length;
13385
+ }
13386
+ if (lastIndex < text.length) {
13387
+ nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex) }, key));
13388
+ }
13389
+ return nodes;
13390
+ };
13391
+
13197
13392
  // src/utils/style.ts
13198
13393
  function attr(key, value) {
13199
13394
  if (typeof value !== "undefined") {
@@ -13449,7 +13644,7 @@ var reducer = (state, action) => {
13449
13644
  // src/context/EmbedProvider.tsx
13450
13645
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
13451
13646
  var getCustomHeaders = (sessionId) => ({
13452
- "X-Schematic-Components-Version": "2.20.0",
13647
+ "X-Schematic-Components-Version": "2.21.0",
13453
13648
  "X-Schematic-Session-ID": sessionId
13454
13649
  });
13455
13650
  var normalizeCurrencyFilter = (filter2) => {
@@ -13473,6 +13668,7 @@ var EmbedProvider = ({
13473
13668
  apiKey,
13474
13669
  apiConfig,
13475
13670
  currencyFilter,
13671
+ warningThresholdConfig,
13476
13672
  checkoutPrefill,
13477
13673
  ...options
13478
13674
  }) => {
@@ -13488,6 +13684,7 @@ var EmbedProvider = ({
13488
13684
  const providedState = {
13489
13685
  settings: opts.settings || {},
13490
13686
  currencyFilter: normalizeCurrencyFilter(currencyFilter),
13687
+ warningThresholdConfig,
13491
13688
  checkoutPrefill: normalizeCheckoutPrefill(checkoutPrefill)
13492
13689
  };
13493
13690
  const resolvedState = (0, import_merge2.default)({}, initialState, providedState);
@@ -13916,6 +14113,7 @@ var EmbedProvider = ({
13916
14113
  layout: state.layout,
13917
14114
  checkoutState: state.checkoutState,
13918
14115
  currencyFilter: state.currencyFilter,
14116
+ warningThresholdConfig: state.warningThresholdConfig,
13919
14117
  checkoutPrefill: state.checkoutPrefill,
13920
14118
  hydratePublic: debouncedHydratePublic,
13921
14119
  hydrate: debouncedHydrate,
@@ -15864,7 +16062,8 @@ var Entitlement = ({
15864
16062
  currency: selectedCurrency
15865
16063
  }) => {
15866
16064
  const { t: t3 } = useTranslation();
15867
- const { data, settings } = useEmbed();
16065
+ const { data, settings, warningThresholdConfig } = useEmbed();
16066
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
15868
16067
  const isLightBackground = useIsLightBackground();
15869
16068
  const showCredits = data?.displaySettings?.showCredits ?? true;
15870
16069
  const showFeatureDescription = data?.displaySettings?.showFeatureDescription ?? false;
@@ -15888,7 +16087,8 @@ var Entitlement = ({
15888
16087
  return;
15889
16088
  }
15890
16089
  const hasNumericValue = entitlement.valueType === EntitlementValueType.Numeric || entitlement.valueType === EntitlementValueType.Unlimited || entitlement.valueType === EntitlementValueType.Trait;
15891
- const limit = entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
16090
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
16091
+ const limit = typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
15892
16092
  const creditBasedEntitlementLimit = getCreditBasedEntitlementLimit(
15893
16093
  entitlement,
15894
16094
  credits
@@ -15981,7 +16181,8 @@ var Entitlement = ({
15981
16181
  currency,
15982
16182
  packageSize,
15983
16183
  tiered,
15984
- selectedCurrency
16184
+ selectedCurrency,
16185
+ showWarningThresholdAsLimit
15985
16186
  ]);
15986
16187
  const usageText = useMemo10(() => {
15987
16188
  if (!entitlement.feature) {
@@ -16712,7 +16913,8 @@ var AddOns = ({
16712
16913
  currency
16713
16914
  }) => {
16714
16915
  const { t: t3 } = useTranslation();
16715
- const { settings } = useEmbed();
16916
+ const { settings, warningThresholdConfig } = useEmbed();
16917
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
16716
16918
  const isLightBackground = useIsLightBackground();
16717
16919
  const periodKey = period === "year" ? "yearlyPrice" : period === "quarter" ? "quarterlyPrice" : "monthlyPrice";
16718
16920
  const cardPadding = settings.theme.card.padding / TEXT_BASE_SIZE;
@@ -16744,10 +16946,14 @@ var AddOns = ({
16744
16946
  period,
16745
16947
  currency
16746
16948
  );
16949
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
16747
16950
  return {
16748
16951
  isUnlimited: false,
16749
16952
  priceBehavior: entitlement.priceBehavior,
16750
16953
  softLimit: entitlement.softLimit,
16954
+ // The limit shown next to the feature: the warning threshold when
16955
+ // the option is on and one is configured, else the overage soft limit.
16956
+ limit: typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage ? entitlement.softLimit : void 0,
16751
16957
  price: priceData?.price ?? 0,
16752
16958
  currency: priceData?.currency || addOnCurrency,
16753
16959
  featureName: entitlement.feature?.name,
@@ -16896,7 +17102,7 @@ var AddOns = ({
16896
17102
  {
16897
17103
  $flexDirection: "column",
16898
17104
  $justifyContent: "center",
16899
- children: /* @__PURE__ */ jsx21(Text, { children: meteredEntitlement.priceBehavior === EntitlementPriceBehavior.Overage && meteredEntitlement.softLimit ? `${meteredEntitlement.softLimit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) })
17105
+ children: /* @__PURE__ */ jsx21(Text, { children: typeof meteredEntitlement.limit === "number" ? `${meteredEntitlement.limit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) })
16900
17106
  }
16901
17107
  )
16902
17108
  ] }),
@@ -20200,7 +20406,7 @@ var SubscriptionSidebar = forwardRef7(
20200
20406
  );
20201
20407
  return { payAsYouGoEntitlements, payInAdvanceEntitlements: payInAdvanceEntitlements2 };
20202
20408
  }, [usageBasedEntitlements]);
20203
- const subscriptionPrice = useMemo18(() => {
20409
+ const { subscriptionPrice, subscriptionTotal, subscriptionCurrency } = useMemo18(() => {
20204
20410
  let planPrice;
20205
20411
  let resolvedCurrency;
20206
20412
  if (selectedPlan) {
@@ -20236,7 +20442,11 @@ var SubscriptionSidebar = forwardRef7(
20236
20442
  0
20237
20443
  );
20238
20444
  total += addOnPayInAdvanceCost;
20239
- return formatCurrency(total, resolvedCurrency);
20445
+ return {
20446
+ subscriptionPrice: formatCurrency(total, resolvedCurrency),
20447
+ subscriptionTotal: total,
20448
+ subscriptionCurrency: resolvedCurrency
20449
+ };
20240
20450
  }, [
20241
20451
  selectedPlan,
20242
20452
  currentPlan,
@@ -20363,6 +20573,14 @@ var SubscriptionSidebar = forwardRef7(
20363
20573
  () => promoCode && (amountOff > 0 || percentOff > 0),
20364
20574
  [promoCode, amountOff, percentOff]
20365
20575
  );
20576
+ const subscriptionDiscount = useMemo18(
20577
+ () => getSubscriptionDiscount(
20578
+ charges?.discounts,
20579
+ subscriptionTotal,
20580
+ subscriptionCurrency
20581
+ ),
20582
+ [charges?.discounts, subscriptionTotal, subscriptionCurrency]
20583
+ );
20366
20584
  const handleCheckout = useCallback10(async () => {
20367
20585
  const planId = selectedPlan?.id;
20368
20586
  const currencyPrice = selectedPlan ? getPlanPrice(
@@ -20609,6 +20827,16 @@ var SubscriptionSidebar = forwardRef7(
20609
20827
  if (isSelectedPlanTrialable && selectedPlan.trialDays) {
20610
20828
  trialEndsOn.setDate(trialEndsOn.getDate() + selectedPlan.trialDays);
20611
20829
  }
20830
+ const billingPreviewText = getBillingPreviewText(
20831
+ {
20832
+ subscriptionPrice,
20833
+ planPeriod,
20834
+ periodStart: renewDate,
20835
+ hasUsageBasedCosts: usageBasedEntitlements.length > 0,
20836
+ discount: subscriptionDiscount
20837
+ },
20838
+ t3
20839
+ );
20612
20840
  return /* @__PURE__ */ jsxs29(
20613
20841
  Flex,
20614
20842
  {
@@ -21157,9 +21385,7 @@ var SubscriptionSidebar = forwardRef7(
21157
21385
  }
21158
21386
  )
21159
21387
  }
21160
- ) : subscriptionPrice && // TODO: localize
21161
- `You will be billed ${subscriptionPrice} ${usageBasedEntitlements.length > 0 ? "plus usage based costs" : ""} for this subscription
21162
- every ${planPeriod} ${renewDate ? `on the ${formatOrdinal(renewDate.getDate())}` : ""} ${planPeriod === "year" && renewDate ? `of ${getMonthName(renewDate)}` : ""} unless you unsubscribe.` }) })
21388
+ ) : billingPreviewText }) })
21163
21389
  ]
21164
21390
  }
21165
21391
  )
@@ -21679,7 +21905,8 @@ var UsageDetails = ({ entitlement, layout }) => {
21679
21905
  metricResetAt
21680
21906
  } = entitlement;
21681
21907
  const { t: t3 } = useTranslation();
21682
- const { data } = useEmbed();
21908
+ const { data, warningThresholdConfig } = useEmbed();
21909
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
21683
21910
  const period = getSubscriptionPeriod(data?.company?.billingSubscription) ?? data?.company?.plan?.planPeriod ?? void 0;
21684
21911
  const showCredits = data?.displaySettings?.showCredits ?? true;
21685
21912
  const {
@@ -21695,7 +21922,9 @@ var UsageDetails = ({ entitlement, layout }) => {
21695
21922
  } = useMemo21(() => {
21696
21923
  const { billingPrice, amount, limit: limit2, cost: cost2, currentTier: currentTier2 } = getUsageDetails(
21697
21924
  entitlement,
21698
- period
21925
+ period,
21926
+ void 0,
21927
+ { showWarningThresholdAsLimit }
21699
21928
  );
21700
21929
  const {
21701
21930
  price: price2,
@@ -21716,7 +21945,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21716
21945
  tiersMode: tiersMode2,
21717
21946
  tiered: priceBehavior === EntitlementPriceBehavior.PayInAdvance && isTieredPrice(billingPrice)
21718
21947
  };
21719
- }, [entitlement, period, priceBehavior]);
21948
+ }, [entitlement, period, priceBehavior, showWarningThresholdAsLimit]);
21720
21949
  const text = useMemo21(() => {
21721
21950
  if (!feature || feature.featureType !== FeatureType.Event && feature.featureType !== FeatureType.Trait) {
21722
21951
  return;
@@ -21766,9 +21995,10 @@ var UsageDetails = ({ entitlement, layout }) => {
21766
21995
  });
21767
21996
  }
21768
21997
  if (!priceBehavior && typeof allocation === "number") {
21998
+ const numericLimit = limit ?? allocation;
21769
21999
  return t3("X units", {
21770
- amount: formatNumber(allocation),
21771
- units: getFeatureName(feature, allocation)
22000
+ amount: formatNumber(numericLimit),
22001
+ units: getFeatureName(feature, numericLimit)
21772
22002
  });
21773
22003
  }
21774
22004
  if (!priceBehavior && allocationType === "unlimited") {
@@ -21854,7 +22084,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21854
22084
  if (typeof usage === "number") {
21855
22085
  return typeof allocation === "number" ? t3("usage.limited", {
21856
22086
  amount: formatNumber(usage),
21857
- allocation: formatNumber(allocation)
22087
+ allocation: formatNumber(limit ?? allocation)
21858
22088
  }) : t3("usage.unlimited", {
21859
22089
  amount: formatNumber(usage)
21860
22090
  });
@@ -21868,6 +22098,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21868
22098
  priceBehavior,
21869
22099
  packageSize,
21870
22100
  allocation,
22101
+ limit,
21871
22102
  usage,
21872
22103
  metricResetAt,
21873
22104
  cost,
@@ -22299,7 +22530,12 @@ import { forwardRef as forwardRef12, useCallback as useCallback13, useMemo as us
22299
22530
  import { jsx as jsx50 } from "react/jsx-runtime";
22300
22531
  var Meter = ({ entitlement }) => {
22301
22532
  const { allocation, priceBehavior, softLimit, usage } = entitlement;
22302
- const limit = softLimit ?? allocation;
22533
+ const { warningThresholdConfig } = useEmbed();
22534
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
22535
+ const warningThreshold = getEntitlementWarningThreshold(
22536
+ entitlement.planEntitlement?.warningTiers
22537
+ );
22538
+ const limit = showWarningThresholdAsLimit && typeof warningThreshold === "number" ? warningThreshold : softLimit ?? allocation;
22303
22539
  if (typeof usage !== "number" || typeof limit !== "number") {
22304
22540
  return null;
22305
22541
  }
@@ -22438,14 +22674,7 @@ import { Fragment as Fragment22, jsx as jsx52, jsxs as jsxs38 } from "react/jsx-
22438
22674
  var Limit = ({ entitlement, usageDetails, fontStyle }) => {
22439
22675
  const { t: t3 } = useTranslation();
22440
22676
  const { data } = useEmbed();
22441
- const {
22442
- feature,
22443
- planEntitlement,
22444
- priceBehavior,
22445
- allocation,
22446
- usage,
22447
- metricResetAt
22448
- } = entitlement;
22677
+ const { feature, planEntitlement, priceBehavior, usage, metricResetAt } = entitlement;
22449
22678
  const { billingPrice, limit, cost, currentTier } = usageDetails;
22450
22679
  const acc = [];
22451
22680
  acc.push(
@@ -22467,8 +22696,8 @@ var Limit = ({ entitlement, usageDetails, fontStyle }) => {
22467
22696
  }) : priceBehavior === EntitlementPriceBehavior.CreditBurndown && typeof feature !== "undefined" && typeof limit === "number" ? t3("X units remaining", {
22468
22697
  amount: formatNumber(limit),
22469
22698
  units: getFeatureName(feature, limit)
22470
- }) : typeof allocation === "number" ? t3("Limit of", {
22471
- amount: formatNumber(allocation)
22699
+ }) : typeof limit === "number" ? t3("Limit of", {
22700
+ amount: formatNumber(limit)
22472
22701
  }) : t3("No limit")
22473
22702
  );
22474
22703
  if (metricResetAt) {
@@ -22523,7 +22752,8 @@ var MeteredFeatures = forwardRef12(({ className, ...rest }, ref) => {
22523
22752
  const elementsRef = useRef12([]);
22524
22753
  const shouldWrapChildren = useWrapChildren(elementsRef);
22525
22754
  const { t: t3 } = useTranslation();
22526
- const { data, settings, setCheckoutState } = useEmbed();
22755
+ const { data, settings, setCheckoutState, warningThresholdConfig } = useEmbed();
22756
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
22527
22757
  const isLightBackground = useIsLightBackground();
22528
22758
  const meteredFeatures = useMemo23(() => {
22529
22759
  const orderedFeatureUsage = props.visibleFeatures?.reduce(
@@ -22577,7 +22807,9 @@ var MeteredFeatures = forwardRef12(({ className, ...rest }, ref) => {
22577
22807
  return acc;
22578
22808
  }
22579
22809
  const { feature, priceBehavior, usage } = entitlement;
22580
- const usageDetails = getUsageDetails(entitlement, period);
22810
+ const usageDetails = getUsageDetails(entitlement, period, void 0, {
22811
+ showWarningThresholdAsLimit
22812
+ });
22581
22813
  const { limit } = usageDetails;
22582
22814
  acc.push(
22583
22815
  /* @__PURE__ */ jsxs38(Element, { as: Flex, $flexDirection: "column", $gap: "1.5rem", children: [
@@ -23195,7 +23427,7 @@ var registerWrapper = function registerWrapper2(stripe, startTime) {
23195
23427
  }
23196
23428
  stripe._registerWrapper({
23197
23429
  name: "stripe-js",
23198
- version: "9.9.0",
23430
+ version: "9.12.0",
23199
23431
  startTime
23200
23432
  });
23201
23433
  };
@@ -23273,7 +23505,7 @@ var initStripe = function initStripe2(maybeStripe, args, startTime) {
23273
23505
  var version = runtimeVersionToUrlVersion(maybeStripe.version);
23274
23506
  var expectedVersion = RELEASE_TRAIN;
23275
23507
  if (isTestKey && version !== expectedVersion) {
23276
- console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("9.9.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
23508
+ console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("9.12.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
23277
23509
  }
23278
23510
  var stripe = maybeStripe.apply(void 0, args);
23279
23511
  registerWrapper(stripe, startTime);
@@ -23687,14 +23919,17 @@ var UsageDetails2 = ({
23687
23919
  layout
23688
23920
  }) => {
23689
23921
  const { t: t3 } = useTranslation();
23690
- const { settings } = useEmbed();
23922
+ const { settings, warningThresholdConfig } = useEmbed();
23923
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
23691
23924
  const {
23692
23925
  billingPrice,
23693
23926
  limit,
23694
23927
  cost = 0
23695
23928
  } = useMemo27(
23696
- () => getUsageDetails(entitlement, period, currency),
23697
- [entitlement, period, currency]
23929
+ () => getUsageDetails(entitlement, period, currency, {
23930
+ showWarningThresholdAsLimit
23931
+ }),
23932
+ [entitlement, period, currency, showWarningThresholdAsLimit]
23698
23933
  );
23699
23934
  const description = useMemo27(() => {
23700
23935
  const acc = [];
@@ -24463,7 +24698,8 @@ var AddOn2 = ({
24463
24698
  }) => {
24464
24699
  const { layout } = sharedProps;
24465
24700
  const { t: t3 } = useTranslation();
24466
- const { data, settings, setCheckoutState } = useEmbed();
24701
+ const { data, settings, setCheckoutState, warningThresholdConfig } = useEmbed();
24702
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
24467
24703
  const isLightBackground = useIsLightBackground();
24468
24704
  const { currentAddOns, canCheckout, isStandalone } = useMemo29(() => {
24469
24705
  const isStandalone2 = typeof data?.component === "undefined";
@@ -24492,12 +24728,16 @@ var AddOn2 = ({
24492
24728
  selectedPeriod,
24493
24729
  currency
24494
24730
  );
24731
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
24495
24732
  return {
24496
24733
  isUnlimited: false,
24497
24734
  featureName: entitlement.feature?.name,
24498
24735
  feature: entitlement.feature,
24499
24736
  priceBehavior: entitlement.priceBehavior,
24500
24737
  softLimit: entitlement.softLimit,
24738
+ // The limit shown next to the feature: the warning threshold when the
24739
+ // option is on and one is configured, else the overage soft limit.
24740
+ limit: typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage ? entitlement.softLimit : void 0,
24501
24741
  price: priceData?.price ?? 0,
24502
24742
  currency: priceData?.currency || addOnCurrency,
24503
24743
  packageSize: priceData?.packageSize ?? 1,
@@ -24667,7 +24907,7 @@ var AddOn2 = ({
24667
24907
  rounded: true
24668
24908
  }
24669
24909
  ),
24670
- /* @__PURE__ */ jsx59(Flex, { $flexDirection: "column", $justifyContent: "center", children: /* @__PURE__ */ jsx59(Text, { children: meteredEntitlement.priceBehavior === EntitlementPriceBehavior.Overage && meteredEntitlement.softLimit ? `${meteredEntitlement.softLimit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) }) })
24910
+ /* @__PURE__ */ jsx59(Flex, { $flexDirection: "column", $justifyContent: "center", children: /* @__PURE__ */ jsx59(Text, { children: typeof meteredEntitlement.limit === "number" ? `${meteredEntitlement.limit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) }) })
24671
24911
  ] }),
24672
24912
  /* @__PURE__ */ jsx59(
24673
24913
  Text,
@@ -24738,7 +24978,8 @@ var Entitlement2 = ({
24738
24978
  }) => {
24739
24979
  const { layout } = sharedProps;
24740
24980
  const { t: t3 } = useTranslation();
24741
- const { settings } = useEmbed();
24981
+ const { settings, warningThresholdConfig } = useEmbed();
24982
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
24742
24983
  const isLightBackground = useIsLightBackground();
24743
24984
  const entitlementBillingPrice = getEntitlementPrice(
24744
24985
  entitlement,
@@ -24753,7 +24994,8 @@ var Entitlement2 = ({
24753
24994
  tiersMode: entitlementTiersMode
24754
24995
  } = entitlementBillingPrice || {};
24755
24996
  const tiered = entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance && isTieredPrice(entitlementBillingPrice);
24756
- const limit = entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
24997
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
24998
+ const limit = typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
24757
24999
  const metricPeriodName = getMetricPeriodName(entitlement);
24758
25000
  const creditBasedEntitlementLimit = getCreditBasedEntitlementLimit(
24759
25001
  entitlement,
@@ -25643,20 +25885,27 @@ function resolveDesignProps11(props) {
25643
25885
  var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25644
25886
  const props = resolveDesignProps11(rest);
25645
25887
  const { t: t3 } = useTranslation();
25646
- const { data, settings, debug, getUpcomingInvoice, getCustomerBalance } = useEmbed();
25888
+ const { data, settings, getUpcomingInvoice } = useEmbed();
25647
25889
  const isLightBackground = useIsLightBackground();
25648
25890
  const [isLoading, setIsLoading] = useState22(false);
25649
25891
  const [error, setError] = useState22();
25650
25892
  const [upcomingInvoice, setUpcomingInvoice] = useState22(data?.upcomingInvoice);
25651
- const [balances, setBalances] = useState22([]);
25652
25893
  const discounts = useMemo32(() => {
25653
- return (data?.subscription?.discounts || []).map((discount) => ({
25894
+ return (data?.subscription?.discounts || []).filter(
25895
+ (discount) => (
25896
+ // Only surface discounts that are currently active and actually
25897
+ // reduce the bill; the API computes `isActive` at read time, so an
25898
+ // expired coupon must not linger in the account summary.
25899
+ discount.isActive && (typeof discount.percentOff === "number" && discount.percentOff > 0 || typeof discount.amountOff === "number" && discount.amountOff > 0)
25900
+ )
25901
+ ).map((discount) => ({
25654
25902
  couponId: discount.couponId,
25655
25903
  customerFacingCode: discount.customerFacingCode || void 0,
25656
25904
  currency: discount.currency || void 0,
25657
25905
  amountOff: discount.amountOff ?? void 0,
25658
25906
  percentOff: discount.percentOff ?? void 0,
25659
- isActive: discount.isActive
25907
+ duration: discount.duration,
25908
+ durationInMonths: discount.durationInMonths ?? void 0
25660
25909
  }));
25661
25910
  }, [data?.subscription?.discounts]);
25662
25911
  const getInvoice = useCallback16(async () => {
@@ -25675,27 +25924,30 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25675
25924
  }
25676
25925
  }
25677
25926
  }, [data?.component?.id, data?.subscription, getUpcomingInvoice]);
25678
- const getBalances = useCallback16(async () => {
25679
- try {
25680
- const response = await getCustomerBalance();
25681
- if (response) {
25682
- setBalances(response.data.balances);
25683
- }
25684
- } catch (err) {
25685
- debug("Failed to fetch customer balance.", err);
25686
- }
25687
- }, [debug, getCustomerBalance]);
25688
25927
  useEffect9(() => {
25689
25928
  getInvoice();
25690
25929
  }, [getInvoice]);
25691
- useEffect9(() => {
25692
- getBalances();
25693
- }, [getBalances]);
25694
25930
  useEffect9(() => {
25695
25931
  if (data?.upcomingInvoice) {
25696
25932
  setUpcomingInvoice(data.upcomingInvoice);
25697
25933
  }
25698
25934
  }, [data?.upcomingInvoice]);
25935
+ const { currency, applied, remaining } = useMemo32(() => {
25936
+ const currency2 = upcomingInvoice?.currency;
25937
+ const startingBalance = upcomingInvoice?.startingBalance ?? 0;
25938
+ const endingBalance = upcomingInvoice?.endingBalance ?? 0;
25939
+ const credit = Math.max(0, -startingBalance);
25940
+ const subtotal = Math.max(0, upcomingInvoice?.subtotal ?? 0);
25941
+ const applied2 = endingBalance < 0 ? credit + endingBalance : Math.min(credit, subtotal);
25942
+ return { currency: currency2, applied: applied2, remaining: credit - applied2 };
25943
+ }, [
25944
+ upcomingInvoice?.currency,
25945
+ upcomingInvoice?.startingBalance,
25946
+ upcomingInvoice?.endingBalance,
25947
+ upcomingInvoice?.subtotal
25948
+ ]);
25949
+ const hasApplied = applied > 0;
25950
+ const hasBalance = remaining > 0 || applied > 0;
25699
25951
  if (!data?.subscription || data.subscription.cancelAt) {
25700
25952
  return null;
25701
25953
  }
@@ -25745,7 +25997,7 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25745
25997
  ]
25746
25998
  }
25747
25999
  ),
25748
- balances.length > 0 && /* @__PURE__ */ jsxs48(
26000
+ hasApplied && /* @__PURE__ */ jsxs48(
25749
26001
  Flex,
25750
26002
  {
25751
26003
  as: TransitionBox,
@@ -25753,8 +26005,21 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25753
26005
  $alignItems: "start",
25754
26006
  $gap: "1rem",
25755
26007
  children: [
25756
- /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Remaining balance") }),
25757
- /* @__PURE__ */ jsx65(Flex, { $flexDirection: "column", $gap: "0.5rem", children: balances.map((item, idx) => /* @__PURE__ */ jsx65(Text, { children: formatCurrency(item.balance, item.currency) }, idx)) })
26008
+ /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Applied balance towards next invoice") }),
26009
+ /* @__PURE__ */ jsx65(Text, { children: formatCurrency(-applied, currency) })
26010
+ ]
26011
+ }
26012
+ ),
26013
+ hasBalance && /* @__PURE__ */ jsxs48(
26014
+ Flex,
26015
+ {
26016
+ as: TransitionBox,
26017
+ $justifyContent: "space-between",
26018
+ $alignItems: "start",
26019
+ $gap: "1rem",
26020
+ children: [
26021
+ /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Remaining balance after next invoice") }),
26022
+ /* @__PURE__ */ jsx65(Text, { children: formatCurrency(remaining, currency) })
25758
26023
  ]
25759
26024
  }
25760
26025
  ),
@@ -25772,54 +26037,50 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25772
26037
  $flexDirection: "column",
25773
26038
  $alignItems: "end",
25774
26039
  $gap: "0.5rem",
25775
- children: discounts.reduce(
25776
- (acc, discount) => {
25777
- if (typeof discount.percentOff === "number" || typeof discount.amountOff === "number") {
25778
- acc.push(
25779
- /* @__PURE__ */ jsxs48(
26040
+ children: discounts.map((discount) => {
26041
+ const label = typeof discount.percentOff === "number" && discount.percentOff > 0 ? t3("Percent off", {
26042
+ percent: discount.percentOff
26043
+ }) : t3("Amount off", {
26044
+ amount: formatCurrency(
26045
+ discount.amountOff,
26046
+ // active discounts always carry a positive amount or percent
26047
+ discount?.currency
26048
+ )
26049
+ });
26050
+ return /* @__PURE__ */ jsxs48(
26051
+ Flex,
26052
+ {
26053
+ $alignItems: "center",
26054
+ $gap: "0.5rem",
26055
+ children: [
26056
+ discount.customerFacingCode && /* @__PURE__ */ jsx65(
25780
26057
  Flex,
25781
26058
  {
25782
26059
  $alignItems: "center",
25783
- $gap: "0.5rem",
25784
- children: [
25785
- discount.customerFacingCode && /* @__PURE__ */ jsx65(
25786
- Flex,
25787
- {
25788
- $alignItems: "center",
25789
- $padding: "0.1875rem 0.375rem",
25790
- $borderWidth: "1px",
25791
- $borderStyle: "solid",
25792
- $borderColor: isLightBackground ? "hsla(0, 0%, 0%, 0.15)" : "hsla(0, 0%, 100%, 0.15)",
25793
- $borderRadius: "0.3125rem",
25794
- children: /* @__PURE__ */ jsx65(
25795
- Text,
25796
- {
25797
- $size: 0.75 * settings.theme.typography.text.fontSize,
25798
- style: { textTransform: "uppercase" },
25799
- children: discount.customerFacingCode
25800
- }
25801
- )
25802
- }
25803
- ),
25804
- /* @__PURE__ */ jsx65(Box, { children: /* @__PURE__ */ jsx65(Text, { children: typeof discount.percentOff === "number" ? t3("Percent off", {
25805
- percent: discount.percentOff
25806
- }) : t3("Amount off", {
25807
- amount: formatCurrency(
25808
- discount.amountOff,
25809
- // we already checked for `number` type
25810
- discount?.currency
25811
- )
25812
- }) }) })
25813
- ]
25814
- },
25815
- discount.couponId
25816
- )
25817
- );
25818
- }
25819
- return acc;
25820
- },
25821
- []
25822
- )
26060
+ $padding: "0.1875rem 0.375rem",
26061
+ $borderWidth: "1px",
26062
+ $borderStyle: "solid",
26063
+ $borderColor: isLightBackground ? "hsla(0, 0%, 0%, 0.15)" : "hsla(0, 0%, 100%, 0.15)",
26064
+ $borderRadius: "0.3125rem",
26065
+ children: /* @__PURE__ */ jsx65(
26066
+ Text,
26067
+ {
26068
+ $size: 0.75 * settings.theme.typography.text.fontSize,
26069
+ style: { textTransform: "uppercase" },
26070
+ children: discount.customerFacingCode
26071
+ }
26072
+ )
26073
+ }
26074
+ ),
26075
+ /* @__PURE__ */ jsx65(Box, { children: /* @__PURE__ */ jsx65(Text, { children: discount.duration === "repeating" && discount.durationInMonths ? t3("Discount for months", {
26076
+ discount: label,
26077
+ count: discount.durationInMonths
26078
+ }) : label }) })
26079
+ ]
26080
+ },
26081
+ discount.couponId
26082
+ );
26083
+ })
25823
26084
  }
25824
26085
  )
25825
26086
  ]