@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 l = "undefined" != typeof process && void 0 !== process.env && (process.env.REACT_APP_SC_ATTR || process.env.SC_ATTR) || "data-styled";
5820
5831
  var c = "active";
5821
5832
  var a = "data-styled-version";
5822
- var u = "6.4.3";
5833
+ var u = "6.4.4";
5823
5834
  var d = "/*!sc*/\n";
5824
5835
  var h = "undefined" != typeof window && "undefined" != typeof document;
5825
5836
  var p = void 0 === t2.createContext;
@@ -8352,6 +8363,20 @@ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
8352
8363
  return json;
8353
8364
  }
8354
8365
 
8366
+ // src/api/checkoutexternal/models/WarningTier.ts
8367
+ function WarningTierFromJSON(json) {
8368
+ return WarningTierFromJSONTyped(json, false);
8369
+ }
8370
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
8371
+ if (json == null) {
8372
+ return json;
8373
+ }
8374
+ return {
8375
+ key: json["key"],
8376
+ value: json["value"]
8377
+ };
8378
+ }
8379
+
8355
8380
  // src/api/checkoutexternal/models/FeatureEntitlement.ts
8356
8381
  function FeatureEntitlementFromJSON(json) {
8357
8382
  return FeatureEntitlementFromJSONTyped(json, false);
@@ -8378,7 +8403,8 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8378
8403
  monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
8379
8404
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
8380
8405
  usage: json["usage"] == null ? void 0 : json["usage"],
8381
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
8406
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
8407
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
8382
8408
  };
8383
8409
  }
8384
8410
 
@@ -8725,6 +8751,7 @@ function CompanyOverrideNoteResponseDataFromJSONTyped(json, ignoreDiscriminator)
8725
8751
  var FeatureType = {
8726
8752
  Boolean: "boolean",
8727
8753
  Event: "event",
8754
+ License: "license",
8728
8755
  Trait: "trait"
8729
8756
  };
8730
8757
  function FeatureTypeFromJSON(json) {
@@ -8757,13 +8784,15 @@ function FeatureResponseDataFromJSONTyped(json, ignoreDiscriminator) {
8757
8784
  featureType: FeatureTypeFromJSON(json["feature_type"]),
8758
8785
  icon: json["icon"],
8759
8786
  id: json["id"],
8787
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
8760
8788
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON(json["lifecycle_phase"]),
8761
8789
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
8762
8790
  name: json["name"],
8763
8791
  pluralName: json["plural_name"] == null ? void 0 : json["plural_name"],
8764
8792
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
8765
8793
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
8766
- updatedAt: new Date(json["updated_at"])
8794
+ updatedAt: new Date(json["updated_at"]),
8795
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
8767
8796
  };
8768
8797
  }
8769
8798
 
@@ -9115,6 +9144,7 @@ function FeatureInPlanResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9115
9144
  flags: json["flags"].map(FlagInPlanResponseDataFromJSON),
9116
9145
  icon: json["icon"],
9117
9146
  id: json["id"],
9147
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
9118
9148
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON(json["lifecycle_phase"]),
9119
9149
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
9120
9150
  name: json["name"],
@@ -9123,7 +9153,8 @@ function FeatureInPlanResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9123
9153
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
9124
9154
  trait: json["trait"] == null ? void 0 : EntityTraitDefinitionResponseDataFromJSON(json["trait"]),
9125
9155
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
9126
- updatedAt: new Date(json["updated_at"])
9156
+ updatedAt: new Date(json["updated_at"]),
9157
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
9127
9158
  };
9128
9159
  }
9129
9160
 
@@ -9200,6 +9231,20 @@ function PlanCreditGrantViewFromJSONTyped(json, ignoreDiscriminator) {
9200
9231
  };
9201
9232
  }
9202
9233
 
9234
+ // src/api/checkoutexternal/models/PlanCatalogMembershipResponseData.ts
9235
+ function PlanCatalogMembershipResponseDataFromJSON(json) {
9236
+ return PlanCatalogMembershipResponseDataFromJSONTyped(json, false);
9237
+ }
9238
+ function PlanCatalogMembershipResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9239
+ if (json == null) {
9240
+ return json;
9241
+ }
9242
+ return {
9243
+ id: json["id"],
9244
+ name: json["name"]
9245
+ };
9246
+ }
9247
+
9203
9248
  // src/api/checkoutexternal/models/PlanCurrencyPricesResponseData.ts
9204
9249
  function PlanCurrencyPricesResponseDataFromJSON(json) {
9205
9250
  return PlanCurrencyPricesResponseDataFromJSONTyped(json, false);
@@ -9356,6 +9401,9 @@ function CompanyPlanDetailResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9356
9401
  ),
9357
9402
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON(json["billing_product"]),
9358
9403
  billingStrategy: BillingStrategyFromJSON(json["billing_strategy"]),
9404
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
9405
+ PlanCatalogMembershipResponseDataFromJSON
9406
+ ),
9359
9407
  chargeType: ChargeTypeFromJSON(json["charge_type"]),
9360
9408
  companyCanTrial: json["company_can_trial"],
9361
9409
  companyCount: json["company_count"],
@@ -9529,6 +9577,9 @@ function PlanDetailResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9529
9577
  ),
9530
9578
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON(json["billing_product"]),
9531
9579
  billingStrategy: BillingStrategyFromJSON(json["billing_strategy"]),
9580
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
9581
+ PlanCatalogMembershipResponseDataFromJSON
9582
+ ),
9532
9583
  chargeType: ChargeTypeFromJSON(json["charge_type"]),
9533
9584
  companyCount: json["company_count"],
9534
9585
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
@@ -9698,6 +9749,7 @@ function ComponentResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9698
9749
  }
9699
9750
  return {
9700
9751
  ast: json["ast"] == null ? void 0 : json["ast"],
9752
+ catalogId: json["catalog_id"] == null ? void 0 : json["catalog_id"],
9701
9753
  createdAt: new Date(json["created_at"]),
9702
9754
  id: json["id"],
9703
9755
  name: json["name"],
@@ -9934,6 +9986,29 @@ function PreviewSubscriptionUpcomingInvoiceLineItemsFromJSONTyped(json, ignoreDi
9934
9986
  };
9935
9987
  }
9936
9988
 
9989
+ // src/api/checkoutexternal/models/PreviewSubscriptionDiscountResponseData.ts
9990
+ function PreviewSubscriptionDiscountResponseDataFromJSON(json) {
9991
+ return PreviewSubscriptionDiscountResponseDataFromJSONTyped(json, false);
9992
+ }
9993
+ function PreviewSubscriptionDiscountResponseDataFromJSONTyped(json, ignoreDiscriminator) {
9994
+ if (json == null) {
9995
+ return json;
9996
+ }
9997
+ return {
9998
+ amountOff: json["amount_off"] == null ? void 0 : json["amount_off"],
9999
+ couponName: json["coupon_name"],
10000
+ currency: json["currency"] == null ? void 0 : json["currency"],
10001
+ customerFacingCode: json["customer_facing_code"] == null ? void 0 : json["customer_facing_code"],
10002
+ duration: json["duration"],
10003
+ durationInMonths: json["duration_in_months"] == null ? void 0 : json["duration_in_months"],
10004
+ endedAt: json["ended_at"] == null ? void 0 : new Date(json["ended_at"]),
10005
+ isActive: json["is_active"],
10006
+ percentOff: json["percent_off"] == null ? void 0 : json["percent_off"],
10007
+ promoCodeExternalId: json["promo_code_external_id"] == null ? void 0 : json["promo_code_external_id"],
10008
+ startedAt: new Date(json["started_at"])
10009
+ };
10010
+ }
10011
+
9937
10012
  // src/api/checkoutexternal/models/PreviewSubscriptionFinanceResponseData.ts
9938
10013
  function PreviewSubscriptionFinanceResponseDataFromJSON(json) {
9939
10014
  return PreviewSubscriptionFinanceResponseDataFromJSONTyped(json, false);
@@ -9944,6 +10019,9 @@ function PreviewSubscriptionFinanceResponseDataFromJSONTyped(json, ignoreDiscrim
9944
10019
  }
9945
10020
  return {
9946
10021
  amountOff: json["amount_off"],
10022
+ discounts: json["discounts"].map(
10023
+ PreviewSubscriptionDiscountResponseDataFromJSON
10024
+ ),
9947
10025
  dueNow: json["due_now"],
9948
10026
  newCharges: json["new_charges"],
9949
10027
  percentOff: json["percent_off"],
@@ -11561,13 +11639,15 @@ function FeatureResponseDataFromJSONTyped5(json, ignoreDiscriminator) {
11561
11639
  featureType: FeatureTypeFromJSON2(json["feature_type"]),
11562
11640
  icon: json["icon"],
11563
11641
  id: json["id"],
11642
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
11564
11643
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON2(json["lifecycle_phase"]),
11565
11644
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
11566
11645
  name: json["name"],
11567
11646
  pluralName: json["plural_name"] == null ? void 0 : json["plural_name"],
11568
11647
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
11569
11648
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
11570
- updatedAt: new Date(json["updated_at"])
11649
+ updatedAt: new Date(json["updated_at"]),
11650
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
11571
11651
  };
11572
11652
  }
11573
11653
 
@@ -11624,6 +11704,7 @@ function FeatureInPlanResponseDataFromJSONTyped6(json, ignoreDiscriminator) {
11624
11704
  flags: json["flags"].map(FlagInPlanResponseDataFromJSON2),
11625
11705
  icon: json["icon"],
11626
11706
  id: json["id"],
11707
+ licenseId: json["license_id"] == null ? void 0 : json["license_id"],
11627
11708
  lifecyclePhase: json["lifecycle_phase"] == null ? void 0 : FeatureLifecyclePhaseFromJSON2(json["lifecycle_phase"]),
11628
11709
  maintainerAccountMemberId: json["maintainer_account_member_id"] == null ? void 0 : json["maintainer_account_member_id"],
11629
11710
  name: json["name"],
@@ -11632,7 +11713,8 @@ function FeatureInPlanResponseDataFromJSONTyped6(json, ignoreDiscriminator) {
11632
11713
  singularName: json["singular_name"] == null ? void 0 : json["singular_name"],
11633
11714
  trait: json["trait"] == null ? void 0 : EntityTraitDefinitionResponseDataFromJSON2(json["trait"]),
11634
11715
  traitId: json["trait_id"] == null ? void 0 : json["trait_id"],
11635
- updatedAt: new Date(json["updated_at"])
11716
+ updatedAt: new Date(json["updated_at"]),
11717
+ usageLimitTraitId: json["usage_limit_trait_id"] == null ? void 0 : json["usage_limit_trait_id"]
11636
11718
  };
11637
11719
  }
11638
11720
 
@@ -11811,6 +11893,20 @@ function PlanCreditGrantViewFromJSONTyped3(json, ignoreDiscriminator) {
11811
11893
  };
11812
11894
  }
11813
11895
 
11896
+ // src/api/componentspublic/models/PlanCatalogMembershipResponseData.ts
11897
+ function PlanCatalogMembershipResponseDataFromJSON2(json) {
11898
+ return PlanCatalogMembershipResponseDataFromJSONTyped5(json, false);
11899
+ }
11900
+ function PlanCatalogMembershipResponseDataFromJSONTyped5(json, ignoreDiscriminator) {
11901
+ if (json == null) {
11902
+ return json;
11903
+ }
11904
+ return {
11905
+ id: json["id"],
11906
+ name: json["name"]
11907
+ };
11908
+ }
11909
+
11814
11910
  // src/api/componentspublic/models/PlanCurrencyPricesResponseData.ts
11815
11911
  function PlanCurrencyPricesResponseDataFromJSON2(json) {
11816
11912
  return PlanCurrencyPricesResponseDataFromJSONTyped5(json, false);
@@ -11878,6 +11974,9 @@ function PlanViewPublicResponseDataFromJSONTyped(json, ignoreDiscriminator) {
11878
11974
  ),
11879
11975
  billingProduct: json["billing_product"] == null ? void 0 : BillingProductDetailResponseDataFromJSON2(json["billing_product"]),
11880
11976
  billingStrategy: BillingStrategyFromJSON2(json["billing_strategy"]),
11977
+ catalogs: json["catalogs"] == null ? void 0 : json["catalogs"].map(
11978
+ PlanCatalogMembershipResponseDataFromJSON2
11979
+ ),
11881
11980
  chargeType: ChargeTypeFromJSON2(json["charge_type"]),
11882
11981
  companyCount: json["company_count"],
11883
11982
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
@@ -12495,7 +12594,7 @@ function getMetricPeriodName(entitlement) {
12495
12594
  const name = period ? PeriodName[period] : void 0;
12496
12595
  return name;
12497
12596
  }
12498
- function getUsageDetails(entitlement, period, currency) {
12597
+ function getUsageDetails(entitlement, period, currency, options) {
12499
12598
  const billingPrice = currency ? getEntitlementPrice(entitlement, period ?? "month", currency) : period === "year" ? entitlement.yearlyUsageBasedPrice : period === "quarter" ? entitlement.quarterlyUsageBasedPrice : period === "month" ? entitlement.monthlyUsageBasedPrice : void 0;
12500
12599
  let limit;
12501
12600
  if ((!entitlement.priceBehavior || entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance) && typeof entitlement.allocation === "number") {
@@ -12543,8 +12642,21 @@ function getUsageDetails(entitlement, period, currency) {
12543
12642
  start = end + 1;
12544
12643
  }
12545
12644
  }
12645
+ if (options?.showWarningThresholdAsLimit) {
12646
+ const warningThreshold = getEntitlementWarningThreshold(
12647
+ entitlement.planEntitlement?.warningTiers
12648
+ );
12649
+ if (typeof warningThreshold === "number") {
12650
+ limit = warningThreshold;
12651
+ }
12652
+ }
12546
12653
  return { billingPrice, limit, amount, cost, currentTier };
12547
12654
  }
12655
+ var WARNING_TIER_DEFAULT_KEY = "default";
12656
+ function getEntitlementWarningThreshold(warningTiers) {
12657
+ const tier = warningTiers?.find((t3) => t3?.key === WARNING_TIER_DEFAULT_KEY);
12658
+ return typeof tier?.value === "number" ? tier.value : void 0;
12659
+ }
12548
12660
  function getCreditBasedEntitlementLimit(entitlement, credits) {
12549
12661
  const matchedCredit = credits.find(
12550
12662
  (credit) => credit.id === entitlement.valueCredit?.id
@@ -13092,85 +13204,6 @@ function modifyDate(date, days) {
13092
13204
  return copy3;
13093
13205
  }
13094
13206
 
13095
- // src/utils/error.ts
13096
- function isError(value) {
13097
- return value instanceof Error;
13098
- }
13099
- var ERROR_UNKNOWN = new Error("An unknown error occurred.");
13100
-
13101
- // src/utils/event.ts
13102
- var createKeyboardExecutionHandler = (fn) => {
13103
- const handler = (event) => {
13104
- if (event.key === "Enter" || event.key === " ") {
13105
- event.preventDefault();
13106
- fn?.(event);
13107
- }
13108
- };
13109
- return handler;
13110
- };
13111
-
13112
- // src/utils/markdown.tsx
13113
- import { Fragment as Fragment2 } from "react";
13114
- import { jsx } from "react/jsx-runtime";
13115
- var TOKEN = /(\[[^\]]+\]\([^)\s]+\))|(\*\*[^*]+\*\*)|(\*[^*]+\*)/g;
13116
- var LINK = /^\[([^\]]+)\]\(([^)\s]+)\)$/;
13117
- var isSafeUrl = (url) => {
13118
- try {
13119
- const { protocol } = new URL(url);
13120
- return protocol === "http:" || protocol === "https:";
13121
- } catch {
13122
- return false;
13123
- }
13124
- };
13125
- var renderOptInMarkdown = (text) => {
13126
- if (!text) {
13127
- return null;
13128
- }
13129
- const nodes = [];
13130
- let lastIndex = 0;
13131
- let key = 0;
13132
- TOKEN.lastIndex = 0;
13133
- let match2;
13134
- while ((match2 = TOKEN.exec(text)) !== null) {
13135
- if (match2.index > lastIndex) {
13136
- nodes.push(
13137
- /* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex, match2.index) }, key++)
13138
- );
13139
- }
13140
- const [token2, link, bold, italic] = match2;
13141
- if (link) {
13142
- const parts = LINK.exec(link);
13143
- if (parts && isSafeUrl(parts[2])) {
13144
- nodes.push(
13145
- /* @__PURE__ */ jsx(
13146
- Text,
13147
- {
13148
- as: "a",
13149
- display: "link",
13150
- href: parts[2],
13151
- target: "_blank",
13152
- rel: "noopener noreferrer",
13153
- children: parts[1]
13154
- },
13155
- key++
13156
- )
13157
- );
13158
- } else {
13159
- nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: parts ? parts[1] : token2 }, key++));
13160
- }
13161
- } else if (bold) {
13162
- nodes.push(/* @__PURE__ */ jsx("strong", { children: bold.slice(2, -2) }, key++));
13163
- } else if (italic) {
13164
- nodes.push(/* @__PURE__ */ jsx("em", { children: italic.slice(1, -1) }, key++));
13165
- }
13166
- lastIndex = match2.index + token2.length;
13167
- }
13168
- if (lastIndex < text.length) {
13169
- nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex) }, key));
13170
- }
13171
- return nodes;
13172
- };
13173
-
13174
13207
  // src/utils/string.ts
13175
13208
  var ZERO_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
13176
13209
  "BIF",
@@ -13319,6 +13352,168 @@ function getCurrencySymbol(currency) {
13319
13352
  }
13320
13353
  }
13321
13354
 
13355
+ // src/utils/discount.ts
13356
+ function getSubscriptionDiscount(discounts, subscriptionTotal, subscriptionCurrency) {
13357
+ const activeDiscounts = (discounts || []).filter(
13358
+ (discount2) => discount2.isActive && (typeof discount2.percentOff === "number" && discount2.percentOff > 0 || typeof discount2.amountOff === "number" && discount2.amountOff > 0)
13359
+ );
13360
+ if (activeDiscounts.length !== 1) {
13361
+ return void 0;
13362
+ }
13363
+ const discount = activeDiscounts[0];
13364
+ const isPercentOff = typeof discount.percentOff === "number" && discount.percentOff > 0;
13365
+ if (!isPercentOff && discount.currency && subscriptionCurrency && discount.currency.toLowerCase() !== subscriptionCurrency.toLowerCase()) {
13366
+ return void 0;
13367
+ }
13368
+ const discountedTotal = isPercentOff ? subscriptionTotal * (1 - discount.percentOff / 100) : Math.max(0, subscriptionTotal - (discount.amountOff ?? 0));
13369
+ if (discountedTotal >= subscriptionTotal) {
13370
+ return void 0;
13371
+ }
13372
+ return {
13373
+ duration: discount.duration,
13374
+ durationInMonths: discount.durationInMonths ?? void 0,
13375
+ discountedPrice: formatCurrency(
13376
+ discountedTotal,
13377
+ subscriptionCurrency ?? void 0
13378
+ )
13379
+ };
13380
+ }
13381
+ function getBillingPreviewText({
13382
+ subscriptionPrice,
13383
+ planPeriod,
13384
+ periodStart,
13385
+ hasUsageBasedCosts,
13386
+ discount
13387
+ }, t3) {
13388
+ if (!subscriptionPrice) {
13389
+ return null;
13390
+ }
13391
+ const usage = hasUsageBasedCosts ? `${t3("plus usage based costs")} ` : "";
13392
+ const scheduleParts = [];
13393
+ if (periodStart) {
13394
+ scheduleParts.push(
13395
+ t3("on the day", { day: formatOrdinal(periodStart.getDate()) })
13396
+ );
13397
+ }
13398
+ if (planPeriod === "year" && periodStart) {
13399
+ scheduleParts.push(t3("of month", { month: getMonthName(periodStart) }));
13400
+ }
13401
+ const schedule = scheduleParts.length > 0 ? `${scheduleParts.join(" ")} ` : "";
13402
+ if (!discount) {
13403
+ return t3("You will be billed", {
13404
+ price: subscriptionPrice,
13405
+ usage,
13406
+ period: planPeriod,
13407
+ schedule
13408
+ });
13409
+ }
13410
+ const { duration, durationInMonths, discountedPrice } = discount;
13411
+ if (duration === "forever") {
13412
+ return t3("You will be billed", {
13413
+ price: discountedPrice,
13414
+ usage,
13415
+ period: planPeriod,
13416
+ schedule
13417
+ });
13418
+ }
13419
+ if (duration === "repeating" && durationInMonths) {
13420
+ return t3("You will be billed with discount window", {
13421
+ price: discountedPrice,
13422
+ usage,
13423
+ period: planPeriod,
13424
+ schedule,
13425
+ window: t3("for the next months", { count: durationInMonths }),
13426
+ fullPrice: subscriptionPrice
13427
+ });
13428
+ }
13429
+ return t3("You will be billed next bill discount", {
13430
+ price: discountedPrice,
13431
+ usage,
13432
+ period: planPeriod,
13433
+ schedule,
13434
+ fullPrice: subscriptionPrice
13435
+ });
13436
+ }
13437
+
13438
+ // src/utils/error.ts
13439
+ function isError(value) {
13440
+ return value instanceof Error;
13441
+ }
13442
+ var ERROR_UNKNOWN = new Error("An unknown error occurred.");
13443
+
13444
+ // src/utils/event.ts
13445
+ var createKeyboardExecutionHandler = (fn) => {
13446
+ const handler = (event) => {
13447
+ if (event.key === "Enter" || event.key === " ") {
13448
+ event.preventDefault();
13449
+ fn?.(event);
13450
+ }
13451
+ };
13452
+ return handler;
13453
+ };
13454
+
13455
+ // src/utils/markdown.tsx
13456
+ import { Fragment as Fragment2 } from "react";
13457
+ import { jsx } from "react/jsx-runtime";
13458
+ var TOKEN = /(\[[^\]]+\]\([^)\s]+\))|(\*\*[^*]+\*\*)|(\*[^*]+\*)/g;
13459
+ var LINK = /^\[([^\]]+)\]\(([^)\s]+)\)$/;
13460
+ var isSafeUrl = (url) => {
13461
+ try {
13462
+ const { protocol } = new URL(url);
13463
+ return protocol === "http:" || protocol === "https:";
13464
+ } catch {
13465
+ return false;
13466
+ }
13467
+ };
13468
+ var renderOptInMarkdown = (text) => {
13469
+ if (!text) {
13470
+ return null;
13471
+ }
13472
+ const nodes = [];
13473
+ let lastIndex = 0;
13474
+ let key = 0;
13475
+ TOKEN.lastIndex = 0;
13476
+ let match2;
13477
+ while ((match2 = TOKEN.exec(text)) !== null) {
13478
+ if (match2.index > lastIndex) {
13479
+ nodes.push(
13480
+ /* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex, match2.index) }, key++)
13481
+ );
13482
+ }
13483
+ const [token2, link, bold, italic] = match2;
13484
+ if (link) {
13485
+ const parts = LINK.exec(link);
13486
+ if (parts && isSafeUrl(parts[2])) {
13487
+ nodes.push(
13488
+ /* @__PURE__ */ jsx(
13489
+ Text,
13490
+ {
13491
+ as: "a",
13492
+ display: "link",
13493
+ href: parts[2],
13494
+ target: "_blank",
13495
+ rel: "noopener noreferrer",
13496
+ children: parts[1]
13497
+ },
13498
+ key++
13499
+ )
13500
+ );
13501
+ } else {
13502
+ nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: parts ? parts[1] : token2 }, key++));
13503
+ }
13504
+ } else if (bold) {
13505
+ nodes.push(/* @__PURE__ */ jsx("strong", { children: bold.slice(2, -2) }, key++));
13506
+ } else if (italic) {
13507
+ nodes.push(/* @__PURE__ */ jsx("em", { children: italic.slice(1, -1) }, key++));
13508
+ }
13509
+ lastIndex = match2.index + token2.length;
13510
+ }
13511
+ if (lastIndex < text.length) {
13512
+ nodes.push(/* @__PURE__ */ jsx(Fragment2, { children: text.slice(lastIndex) }, key));
13513
+ }
13514
+ return nodes;
13515
+ };
13516
+
13322
13517
  // src/utils/style.ts
13323
13518
  function attr(key, value) {
13324
13519
  if (typeof value !== "undefined") {
@@ -13574,7 +13769,7 @@ var reducer = (state, action) => {
13574
13769
  // src/context/EmbedProvider.tsx
13575
13770
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
13576
13771
  var getCustomHeaders = (sessionId) => ({
13577
- "X-Schematic-Components-Version": "2.20.0",
13772
+ "X-Schematic-Components-Version": "2.21.0",
13578
13773
  "X-Schematic-Session-ID": sessionId
13579
13774
  });
13580
13775
  var normalizeCurrencyFilter = (filter2) => {
@@ -13598,6 +13793,7 @@ var EmbedProvider = ({
13598
13793
  apiKey,
13599
13794
  apiConfig,
13600
13795
  currencyFilter,
13796
+ warningThresholdConfig,
13601
13797
  checkoutPrefill,
13602
13798
  ...options
13603
13799
  }) => {
@@ -13613,6 +13809,7 @@ var EmbedProvider = ({
13613
13809
  const providedState = {
13614
13810
  settings: opts.settings || {},
13615
13811
  currencyFilter: normalizeCurrencyFilter(currencyFilter),
13812
+ warningThresholdConfig,
13616
13813
  checkoutPrefill: normalizeCheckoutPrefill(checkoutPrefill)
13617
13814
  };
13618
13815
  const resolvedState = (0, import_merge2.default)({}, initialState, providedState);
@@ -14041,6 +14238,7 @@ var EmbedProvider = ({
14041
14238
  layout: state.layout,
14042
14239
  checkoutState: state.checkoutState,
14043
14240
  currencyFilter: state.currencyFilter,
14241
+ warningThresholdConfig: state.warningThresholdConfig,
14044
14242
  checkoutPrefill: state.checkoutPrefill,
14045
14243
  hydratePublic: debouncedHydratePublic,
14046
14244
  hydrate: debouncedHydrate,
@@ -15989,7 +16187,8 @@ var Entitlement = ({
15989
16187
  currency: selectedCurrency
15990
16188
  }) => {
15991
16189
  const { t: t3 } = useTranslation();
15992
- const { data, settings } = useEmbed();
16190
+ const { data, settings, warningThresholdConfig } = useEmbed();
16191
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
15993
16192
  const isLightBackground = useIsLightBackground();
15994
16193
  const showCredits = data?.displaySettings?.showCredits ?? true;
15995
16194
  const showFeatureDescription = data?.displaySettings?.showFeatureDescription ?? false;
@@ -16013,7 +16212,8 @@ var Entitlement = ({
16013
16212
  return;
16014
16213
  }
16015
16214
  const hasNumericValue = entitlement.valueType === EntitlementValueType.Numeric || entitlement.valueType === EntitlementValueType.Unlimited || entitlement.valueType === EntitlementValueType.Trait;
16016
- const limit = entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
16215
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
16216
+ const limit = typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
16017
16217
  const creditBasedEntitlementLimit = getCreditBasedEntitlementLimit(
16018
16218
  entitlement,
16019
16219
  credits
@@ -16106,7 +16306,8 @@ var Entitlement = ({
16106
16306
  currency,
16107
16307
  packageSize,
16108
16308
  tiered,
16109
- selectedCurrency
16309
+ selectedCurrency,
16310
+ showWarningThresholdAsLimit
16110
16311
  ]);
16111
16312
  const usageText = useMemo10(() => {
16112
16313
  if (!entitlement.feature) {
@@ -16837,7 +17038,8 @@ var AddOns = ({
16837
17038
  currency
16838
17039
  }) => {
16839
17040
  const { t: t3 } = useTranslation();
16840
- const { settings } = useEmbed();
17041
+ const { settings, warningThresholdConfig } = useEmbed();
17042
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
16841
17043
  const isLightBackground = useIsLightBackground();
16842
17044
  const periodKey = period === "year" ? "yearlyPrice" : period === "quarter" ? "quarterlyPrice" : "monthlyPrice";
16843
17045
  const cardPadding = settings.theme.card.padding / TEXT_BASE_SIZE;
@@ -16869,10 +17071,14 @@ var AddOns = ({
16869
17071
  period,
16870
17072
  currency
16871
17073
  );
17074
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
16872
17075
  return {
16873
17076
  isUnlimited: false,
16874
17077
  priceBehavior: entitlement.priceBehavior,
16875
17078
  softLimit: entitlement.softLimit,
17079
+ // The limit shown next to the feature: the warning threshold when
17080
+ // the option is on and one is configured, else the overage soft limit.
17081
+ limit: typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage ? entitlement.softLimit : void 0,
16876
17082
  price: priceData?.price ?? 0,
16877
17083
  currency: priceData?.currency || addOnCurrency,
16878
17084
  featureName: entitlement.feature?.name,
@@ -17021,7 +17227,7 @@ var AddOns = ({
17021
17227
  {
17022
17228
  $flexDirection: "column",
17023
17229
  $justifyContent: "center",
17024
- children: /* @__PURE__ */ jsx21(Text, { children: meteredEntitlement.priceBehavior === EntitlementPriceBehavior.Overage && meteredEntitlement.softLimit ? `${meteredEntitlement.softLimit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) })
17230
+ children: /* @__PURE__ */ jsx21(Text, { children: typeof meteredEntitlement.limit === "number" ? `${meteredEntitlement.limit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) })
17025
17231
  }
17026
17232
  )
17027
17233
  ] }),
@@ -20325,7 +20531,7 @@ var SubscriptionSidebar = forwardRef7(
20325
20531
  );
20326
20532
  return { payAsYouGoEntitlements, payInAdvanceEntitlements: payInAdvanceEntitlements2 };
20327
20533
  }, [usageBasedEntitlements]);
20328
- const subscriptionPrice = useMemo18(() => {
20534
+ const { subscriptionPrice, subscriptionTotal, subscriptionCurrency } = useMemo18(() => {
20329
20535
  let planPrice;
20330
20536
  let resolvedCurrency;
20331
20537
  if (selectedPlan) {
@@ -20361,7 +20567,11 @@ var SubscriptionSidebar = forwardRef7(
20361
20567
  0
20362
20568
  );
20363
20569
  total += addOnPayInAdvanceCost;
20364
- return formatCurrency(total, resolvedCurrency);
20570
+ return {
20571
+ subscriptionPrice: formatCurrency(total, resolvedCurrency),
20572
+ subscriptionTotal: total,
20573
+ subscriptionCurrency: resolvedCurrency
20574
+ };
20365
20575
  }, [
20366
20576
  selectedPlan,
20367
20577
  currentPlan,
@@ -20488,6 +20698,14 @@ var SubscriptionSidebar = forwardRef7(
20488
20698
  () => promoCode && (amountOff > 0 || percentOff > 0),
20489
20699
  [promoCode, amountOff, percentOff]
20490
20700
  );
20701
+ const subscriptionDiscount = useMemo18(
20702
+ () => getSubscriptionDiscount(
20703
+ charges?.discounts,
20704
+ subscriptionTotal,
20705
+ subscriptionCurrency
20706
+ ),
20707
+ [charges?.discounts, subscriptionTotal, subscriptionCurrency]
20708
+ );
20491
20709
  const handleCheckout = useCallback10(async () => {
20492
20710
  const planId = selectedPlan?.id;
20493
20711
  const currencyPrice = selectedPlan ? getPlanPrice(
@@ -20734,6 +20952,16 @@ var SubscriptionSidebar = forwardRef7(
20734
20952
  if (isSelectedPlanTrialable && selectedPlan.trialDays) {
20735
20953
  trialEndsOn.setDate(trialEndsOn.getDate() + selectedPlan.trialDays);
20736
20954
  }
20955
+ const billingPreviewText = getBillingPreviewText(
20956
+ {
20957
+ subscriptionPrice,
20958
+ planPeriod,
20959
+ periodStart: renewDate,
20960
+ hasUsageBasedCosts: usageBasedEntitlements.length > 0,
20961
+ discount: subscriptionDiscount
20962
+ },
20963
+ t3
20964
+ );
20737
20965
  return /* @__PURE__ */ jsxs29(
20738
20966
  Flex,
20739
20967
  {
@@ -21282,9 +21510,7 @@ var SubscriptionSidebar = forwardRef7(
21282
21510
  }
21283
21511
  )
21284
21512
  }
21285
- ) : subscriptionPrice && // TODO: localize
21286
- `You will be billed ${subscriptionPrice} ${usageBasedEntitlements.length > 0 ? "plus usage based costs" : ""} for this subscription
21287
- every ${planPeriod} ${renewDate ? `on the ${formatOrdinal(renewDate.getDate())}` : ""} ${planPeriod === "year" && renewDate ? `of ${getMonthName(renewDate)}` : ""} unless you unsubscribe.` }) })
21513
+ ) : billingPreviewText }) })
21288
21514
  ]
21289
21515
  }
21290
21516
  )
@@ -21804,7 +22030,8 @@ var UsageDetails = ({ entitlement, layout }) => {
21804
22030
  metricResetAt
21805
22031
  } = entitlement;
21806
22032
  const { t: t3 } = useTranslation();
21807
- const { data } = useEmbed();
22033
+ const { data, warningThresholdConfig } = useEmbed();
22034
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
21808
22035
  const period = getSubscriptionPeriod(data?.company?.billingSubscription) ?? data?.company?.plan?.planPeriod ?? void 0;
21809
22036
  const showCredits = data?.displaySettings?.showCredits ?? true;
21810
22037
  const {
@@ -21820,7 +22047,9 @@ var UsageDetails = ({ entitlement, layout }) => {
21820
22047
  } = useMemo21(() => {
21821
22048
  const { billingPrice, amount, limit: limit2, cost: cost2, currentTier: currentTier2 } = getUsageDetails(
21822
22049
  entitlement,
21823
- period
22050
+ period,
22051
+ void 0,
22052
+ { showWarningThresholdAsLimit }
21824
22053
  );
21825
22054
  const {
21826
22055
  price: price2,
@@ -21841,7 +22070,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21841
22070
  tiersMode: tiersMode2,
21842
22071
  tiered: priceBehavior === EntitlementPriceBehavior.PayInAdvance && isTieredPrice(billingPrice)
21843
22072
  };
21844
- }, [entitlement, period, priceBehavior]);
22073
+ }, [entitlement, period, priceBehavior, showWarningThresholdAsLimit]);
21845
22074
  const text = useMemo21(() => {
21846
22075
  if (!feature || feature.featureType !== FeatureType.Event && feature.featureType !== FeatureType.Trait) {
21847
22076
  return;
@@ -21891,9 +22120,10 @@ var UsageDetails = ({ entitlement, layout }) => {
21891
22120
  });
21892
22121
  }
21893
22122
  if (!priceBehavior && typeof allocation === "number") {
22123
+ const numericLimit = limit ?? allocation;
21894
22124
  return t3("X units", {
21895
- amount: formatNumber(allocation),
21896
- units: getFeatureName(feature, allocation)
22125
+ amount: formatNumber(numericLimit),
22126
+ units: getFeatureName(feature, numericLimit)
21897
22127
  });
21898
22128
  }
21899
22129
  if (!priceBehavior && allocationType === "unlimited") {
@@ -21979,7 +22209,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21979
22209
  if (typeof usage === "number") {
21980
22210
  return typeof allocation === "number" ? t3("usage.limited", {
21981
22211
  amount: formatNumber(usage),
21982
- allocation: formatNumber(allocation)
22212
+ allocation: formatNumber(limit ?? allocation)
21983
22213
  }) : t3("usage.unlimited", {
21984
22214
  amount: formatNumber(usage)
21985
22215
  });
@@ -21993,6 +22223,7 @@ var UsageDetails = ({ entitlement, layout }) => {
21993
22223
  priceBehavior,
21994
22224
  packageSize,
21995
22225
  allocation,
22226
+ limit,
21996
22227
  usage,
21997
22228
  metricResetAt,
21998
22229
  cost,
@@ -22424,7 +22655,12 @@ import { forwardRef as forwardRef12, useCallback as useCallback13, useMemo as us
22424
22655
  import { jsx as jsx50 } from "react/jsx-runtime";
22425
22656
  var Meter = ({ entitlement }) => {
22426
22657
  const { allocation, priceBehavior, softLimit, usage } = entitlement;
22427
- const limit = softLimit ?? allocation;
22658
+ const { warningThresholdConfig } = useEmbed();
22659
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
22660
+ const warningThreshold = getEntitlementWarningThreshold(
22661
+ entitlement.planEntitlement?.warningTiers
22662
+ );
22663
+ const limit = showWarningThresholdAsLimit && typeof warningThreshold === "number" ? warningThreshold : softLimit ?? allocation;
22428
22664
  if (typeof usage !== "number" || typeof limit !== "number") {
22429
22665
  return null;
22430
22666
  }
@@ -22563,14 +22799,7 @@ import { Fragment as Fragment22, jsx as jsx52, jsxs as jsxs38 } from "react/jsx-
22563
22799
  var Limit = ({ entitlement, usageDetails, fontStyle }) => {
22564
22800
  const { t: t3 } = useTranslation();
22565
22801
  const { data } = useEmbed();
22566
- const {
22567
- feature,
22568
- planEntitlement,
22569
- priceBehavior,
22570
- allocation,
22571
- usage,
22572
- metricResetAt
22573
- } = entitlement;
22802
+ const { feature, planEntitlement, priceBehavior, usage, metricResetAt } = entitlement;
22574
22803
  const { billingPrice, limit, cost, currentTier } = usageDetails;
22575
22804
  const acc = [];
22576
22805
  acc.push(
@@ -22592,8 +22821,8 @@ var Limit = ({ entitlement, usageDetails, fontStyle }) => {
22592
22821
  }) : priceBehavior === EntitlementPriceBehavior.CreditBurndown && typeof feature !== "undefined" && typeof limit === "number" ? t3("X units remaining", {
22593
22822
  amount: formatNumber(limit),
22594
22823
  units: getFeatureName(feature, limit)
22595
- }) : typeof allocation === "number" ? t3("Limit of", {
22596
- amount: formatNumber(allocation)
22824
+ }) : typeof limit === "number" ? t3("Limit of", {
22825
+ amount: formatNumber(limit)
22597
22826
  }) : t3("No limit")
22598
22827
  );
22599
22828
  if (metricResetAt) {
@@ -22648,7 +22877,8 @@ var MeteredFeatures = forwardRef12(({ className, ...rest }, ref) => {
22648
22877
  const elementsRef = useRef12([]);
22649
22878
  const shouldWrapChildren = useWrapChildren(elementsRef);
22650
22879
  const { t: t3 } = useTranslation();
22651
- const { data, settings, setCheckoutState } = useEmbed();
22880
+ const { data, settings, setCheckoutState, warningThresholdConfig } = useEmbed();
22881
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
22652
22882
  const isLightBackground = useIsLightBackground();
22653
22883
  const meteredFeatures = useMemo23(() => {
22654
22884
  const orderedFeatureUsage = props.visibleFeatures?.reduce(
@@ -22702,7 +22932,9 @@ var MeteredFeatures = forwardRef12(({ className, ...rest }, ref) => {
22702
22932
  return acc;
22703
22933
  }
22704
22934
  const { feature, priceBehavior, usage } = entitlement;
22705
- const usageDetails = getUsageDetails(entitlement, period);
22935
+ const usageDetails = getUsageDetails(entitlement, period, void 0, {
22936
+ showWarningThresholdAsLimit
22937
+ });
22706
22938
  const { limit } = usageDetails;
22707
22939
  acc.push(
22708
22940
  /* @__PURE__ */ jsxs38(Element, { as: Flex, $flexDirection: "column", $gap: "1.5rem", children: [
@@ -23320,7 +23552,7 @@ var registerWrapper = function registerWrapper2(stripe, startTime) {
23320
23552
  }
23321
23553
  stripe._registerWrapper({
23322
23554
  name: "stripe-js",
23323
- version: "9.9.0",
23555
+ version: "9.12.0",
23324
23556
  startTime
23325
23557
  });
23326
23558
  };
@@ -23398,7 +23630,7 @@ var initStripe = function initStripe2(maybeStripe, args, startTime) {
23398
23630
  var version = runtimeVersionToUrlVersion(maybeStripe.version);
23399
23631
  var expectedVersion = RELEASE_TRAIN;
23400
23632
  if (isTestKey && version !== expectedVersion) {
23401
- 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"));
23633
+ 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"));
23402
23634
  }
23403
23635
  var stripe = maybeStripe.apply(void 0, args);
23404
23636
  registerWrapper(stripe, startTime);
@@ -23812,14 +24044,17 @@ var UsageDetails2 = ({
23812
24044
  layout
23813
24045
  }) => {
23814
24046
  const { t: t3 } = useTranslation();
23815
- const { settings } = useEmbed();
24047
+ const { settings, warningThresholdConfig } = useEmbed();
24048
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
23816
24049
  const {
23817
24050
  billingPrice,
23818
24051
  limit,
23819
24052
  cost = 0
23820
24053
  } = useMemo27(
23821
- () => getUsageDetails(entitlement, period, currency),
23822
- [entitlement, period, currency]
24054
+ () => getUsageDetails(entitlement, period, currency, {
24055
+ showWarningThresholdAsLimit
24056
+ }),
24057
+ [entitlement, period, currency, showWarningThresholdAsLimit]
23823
24058
  );
23824
24059
  const description = useMemo27(() => {
23825
24060
  const acc = [];
@@ -24588,7 +24823,8 @@ var AddOn2 = ({
24588
24823
  }) => {
24589
24824
  const { layout } = sharedProps;
24590
24825
  const { t: t3 } = useTranslation();
24591
- const { data, settings, setCheckoutState } = useEmbed();
24826
+ const { data, settings, setCheckoutState, warningThresholdConfig } = useEmbed();
24827
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
24592
24828
  const isLightBackground = useIsLightBackground();
24593
24829
  const { currentAddOns, canCheckout, isStandalone } = useMemo29(() => {
24594
24830
  const isStandalone2 = typeof data?.component === "undefined";
@@ -24617,12 +24853,16 @@ var AddOn2 = ({
24617
24853
  selectedPeriod,
24618
24854
  currency
24619
24855
  );
24856
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
24620
24857
  return {
24621
24858
  isUnlimited: false,
24622
24859
  featureName: entitlement.feature?.name,
24623
24860
  feature: entitlement.feature,
24624
24861
  priceBehavior: entitlement.priceBehavior,
24625
24862
  softLimit: entitlement.softLimit,
24863
+ // The limit shown next to the feature: the warning threshold when the
24864
+ // option is on and one is configured, else the overage soft limit.
24865
+ limit: typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage ? entitlement.softLimit : void 0,
24626
24866
  price: priceData?.price ?? 0,
24627
24867
  currency: priceData?.currency || addOnCurrency,
24628
24868
  packageSize: priceData?.packageSize ?? 1,
@@ -24792,7 +25032,7 @@ var AddOn2 = ({
24792
25032
  rounded: true
24793
25033
  }
24794
25034
  ),
24795
- /* @__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) }) })
25035
+ /* @__PURE__ */ jsx59(Flex, { $flexDirection: "column", $justifyContent: "center", children: /* @__PURE__ */ jsx59(Text, { children: typeof meteredEntitlement.limit === "number" ? `${meteredEntitlement.limit} ${getEntitlementFeatureName(meteredEntitlement, "units")}` : getEntitlementFeatureName(meteredEntitlement) }) })
24796
25036
  ] }),
24797
25037
  /* @__PURE__ */ jsx59(
24798
25038
  Text,
@@ -24863,7 +25103,8 @@ var Entitlement2 = ({
24863
25103
  }) => {
24864
25104
  const { layout } = sharedProps;
24865
25105
  const { t: t3 } = useTranslation();
24866
- const { settings } = useEmbed();
25106
+ const { settings, warningThresholdConfig } = useEmbed();
25107
+ const showWarningThresholdAsLimit = warningThresholdConfig?.showAsLimit ?? false;
24867
25108
  const isLightBackground = useIsLightBackground();
24868
25109
  const entitlementBillingPrice = getEntitlementPrice(
24869
25110
  entitlement,
@@ -24878,7 +25119,8 @@ var Entitlement2 = ({
24878
25119
  tiersMode: entitlementTiersMode
24879
25120
  } = entitlementBillingPrice || {};
24880
25121
  const tiered = entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance && isTieredPrice(entitlementBillingPrice);
24881
- const limit = entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
25122
+ const warningThreshold = showWarningThresholdAsLimit ? getEntitlementWarningThreshold(entitlement.warningTiers) : void 0;
25123
+ const limit = typeof warningThreshold === "number" ? warningThreshold : entitlement.priceBehavior === EntitlementPriceBehavior.Overage && typeof entitlement.softLimit === "number" ? entitlement.softLimit : entitlement.valueNumeric ?? void 0;
24882
25124
  const metricPeriodName = getMetricPeriodName(entitlement);
24883
25125
  const creditBasedEntitlementLimit = getCreditBasedEntitlementLimit(
24884
25126
  entitlement,
@@ -25768,20 +26010,27 @@ function resolveDesignProps11(props) {
25768
26010
  var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25769
26011
  const props = resolveDesignProps11(rest);
25770
26012
  const { t: t3 } = useTranslation();
25771
- const { data, settings, debug, getUpcomingInvoice, getCustomerBalance } = useEmbed();
26013
+ const { data, settings, getUpcomingInvoice } = useEmbed();
25772
26014
  const isLightBackground = useIsLightBackground();
25773
26015
  const [isLoading, setIsLoading] = useState22(false);
25774
26016
  const [error, setError] = useState22();
25775
26017
  const [upcomingInvoice, setUpcomingInvoice] = useState22(data?.upcomingInvoice);
25776
- const [balances, setBalances] = useState22([]);
25777
26018
  const discounts = useMemo32(() => {
25778
- return (data?.subscription?.discounts || []).map((discount) => ({
26019
+ return (data?.subscription?.discounts || []).filter(
26020
+ (discount) => (
26021
+ // Only surface discounts that are currently active and actually
26022
+ // reduce the bill; the API computes `isActive` at read time, so an
26023
+ // expired coupon must not linger in the account summary.
26024
+ discount.isActive && (typeof discount.percentOff === "number" && discount.percentOff > 0 || typeof discount.amountOff === "number" && discount.amountOff > 0)
26025
+ )
26026
+ ).map((discount) => ({
25779
26027
  couponId: discount.couponId,
25780
26028
  customerFacingCode: discount.customerFacingCode || void 0,
25781
26029
  currency: discount.currency || void 0,
25782
26030
  amountOff: discount.amountOff ?? void 0,
25783
26031
  percentOff: discount.percentOff ?? void 0,
25784
- isActive: discount.isActive
26032
+ duration: discount.duration,
26033
+ durationInMonths: discount.durationInMonths ?? void 0
25785
26034
  }));
25786
26035
  }, [data?.subscription?.discounts]);
25787
26036
  const getInvoice = useCallback16(async () => {
@@ -25800,27 +26049,30 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25800
26049
  }
25801
26050
  }
25802
26051
  }, [data?.component?.id, data?.subscription, getUpcomingInvoice]);
25803
- const getBalances = useCallback16(async () => {
25804
- try {
25805
- const response = await getCustomerBalance();
25806
- if (response) {
25807
- setBalances(response.data.balances);
25808
- }
25809
- } catch (err) {
25810
- debug("Failed to fetch customer balance.", err);
25811
- }
25812
- }, [debug, getCustomerBalance]);
25813
26052
  useEffect9(() => {
25814
26053
  getInvoice();
25815
26054
  }, [getInvoice]);
25816
- useEffect9(() => {
25817
- getBalances();
25818
- }, [getBalances]);
25819
26055
  useEffect9(() => {
25820
26056
  if (data?.upcomingInvoice) {
25821
26057
  setUpcomingInvoice(data.upcomingInvoice);
25822
26058
  }
25823
26059
  }, [data?.upcomingInvoice]);
26060
+ const { currency, applied, remaining } = useMemo32(() => {
26061
+ const currency2 = upcomingInvoice?.currency;
26062
+ const startingBalance = upcomingInvoice?.startingBalance ?? 0;
26063
+ const endingBalance = upcomingInvoice?.endingBalance ?? 0;
26064
+ const credit = Math.max(0, -startingBalance);
26065
+ const subtotal = Math.max(0, upcomingInvoice?.subtotal ?? 0);
26066
+ const applied2 = endingBalance < 0 ? credit + endingBalance : Math.min(credit, subtotal);
26067
+ return { currency: currency2, applied: applied2, remaining: credit - applied2 };
26068
+ }, [
26069
+ upcomingInvoice?.currency,
26070
+ upcomingInvoice?.startingBalance,
26071
+ upcomingInvoice?.endingBalance,
26072
+ upcomingInvoice?.subtotal
26073
+ ]);
26074
+ const hasApplied = applied > 0;
26075
+ const hasBalance = remaining > 0 || applied > 0;
25824
26076
  if (!data?.subscription || data.subscription.cancelAt) {
25825
26077
  return null;
25826
26078
  }
@@ -25870,7 +26122,7 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25870
26122
  ]
25871
26123
  }
25872
26124
  ),
25873
- balances.length > 0 && /* @__PURE__ */ jsxs48(
26125
+ hasApplied && /* @__PURE__ */ jsxs48(
25874
26126
  Flex,
25875
26127
  {
25876
26128
  as: TransitionBox,
@@ -25878,8 +26130,21 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25878
26130
  $alignItems: "start",
25879
26131
  $gap: "1rem",
25880
26132
  children: [
25881
- /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Remaining balance") }),
25882
- /* @__PURE__ */ jsx65(Flex, { $flexDirection: "column", $gap: "0.5rem", children: balances.map((item, idx) => /* @__PURE__ */ jsx65(Text, { children: formatCurrency(item.balance, item.currency) }, idx)) })
26133
+ /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Applied balance towards next invoice") }),
26134
+ /* @__PURE__ */ jsx65(Text, { children: formatCurrency(-applied, currency) })
26135
+ ]
26136
+ }
26137
+ ),
26138
+ hasBalance && /* @__PURE__ */ jsxs48(
26139
+ Flex,
26140
+ {
26141
+ as: TransitionBox,
26142
+ $justifyContent: "space-between",
26143
+ $alignItems: "start",
26144
+ $gap: "1rem",
26145
+ children: [
26146
+ /* @__PURE__ */ jsx65(Text, { $weight: 600, children: t3("Remaining balance after next invoice") }),
26147
+ /* @__PURE__ */ jsx65(Text, { children: formatCurrency(remaining, currency) })
25883
26148
  ]
25884
26149
  }
25885
26150
  ),
@@ -25897,54 +26162,50 @@ var UpcomingBill = forwardRef18(({ className, ...rest }, ref) => {
25897
26162
  $flexDirection: "column",
25898
26163
  $alignItems: "end",
25899
26164
  $gap: "0.5rem",
25900
- children: discounts.reduce(
25901
- (acc, discount) => {
25902
- if (typeof discount.percentOff === "number" || typeof discount.amountOff === "number") {
25903
- acc.push(
25904
- /* @__PURE__ */ jsxs48(
26165
+ children: discounts.map((discount) => {
26166
+ const label = typeof discount.percentOff === "number" && discount.percentOff > 0 ? t3("Percent off", {
26167
+ percent: discount.percentOff
26168
+ }) : t3("Amount off", {
26169
+ amount: formatCurrency(
26170
+ discount.amountOff,
26171
+ // active discounts always carry a positive amount or percent
26172
+ discount?.currency
26173
+ )
26174
+ });
26175
+ return /* @__PURE__ */ jsxs48(
26176
+ Flex,
26177
+ {
26178
+ $alignItems: "center",
26179
+ $gap: "0.5rem",
26180
+ children: [
26181
+ discount.customerFacingCode && /* @__PURE__ */ jsx65(
25905
26182
  Flex,
25906
26183
  {
25907
26184
  $alignItems: "center",
25908
- $gap: "0.5rem",
25909
- children: [
25910
- discount.customerFacingCode && /* @__PURE__ */ jsx65(
25911
- Flex,
25912
- {
25913
- $alignItems: "center",
25914
- $padding: "0.1875rem 0.375rem",
25915
- $borderWidth: "1px",
25916
- $borderStyle: "solid",
25917
- $borderColor: isLightBackground ? "hsla(0, 0%, 0%, 0.15)" : "hsla(0, 0%, 100%, 0.15)",
25918
- $borderRadius: "0.3125rem",
25919
- children: /* @__PURE__ */ jsx65(
25920
- Text,
25921
- {
25922
- $size: 0.75 * settings.theme.typography.text.fontSize,
25923
- style: { textTransform: "uppercase" },
25924
- children: discount.customerFacingCode
25925
- }
25926
- )
25927
- }
25928
- ),
25929
- /* @__PURE__ */ jsx65(Box, { children: /* @__PURE__ */ jsx65(Text, { children: typeof discount.percentOff === "number" ? t3("Percent off", {
25930
- percent: discount.percentOff
25931
- }) : t3("Amount off", {
25932
- amount: formatCurrency(
25933
- discount.amountOff,
25934
- // we already checked for `number` type
25935
- discount?.currency
25936
- )
25937
- }) }) })
25938
- ]
25939
- },
25940
- discount.couponId
25941
- )
25942
- );
25943
- }
25944
- return acc;
25945
- },
25946
- []
25947
- )
26185
+ $padding: "0.1875rem 0.375rem",
26186
+ $borderWidth: "1px",
26187
+ $borderStyle: "solid",
26188
+ $borderColor: isLightBackground ? "hsla(0, 0%, 0%, 0.15)" : "hsla(0, 0%, 100%, 0.15)",
26189
+ $borderRadius: "0.3125rem",
26190
+ children: /* @__PURE__ */ jsx65(
26191
+ Text,
26192
+ {
26193
+ $size: 0.75 * settings.theme.typography.text.fontSize,
26194
+ style: { textTransform: "uppercase" },
26195
+ children: discount.customerFacingCode
26196
+ }
26197
+ )
26198
+ }
26199
+ ),
26200
+ /* @__PURE__ */ jsx65(Box, { children: /* @__PURE__ */ jsx65(Text, { children: discount.duration === "repeating" && discount.durationInMonths ? t3("Discount for months", {
26201
+ discount: label,
26202
+ count: discount.durationInMonths
26203
+ }) : label }) })
26204
+ ]
26205
+ },
26206
+ discount.couponId
26207
+ );
26208
+ })
25948
26209
  }
25949
26210
  )
25950
26211
  ]