@stigg/react-sdk 4.13.2 → 4.15.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.
Files changed (58) hide show
  1. package/dist/components/common/TiersSelectContainer.d.ts +8 -3
  2. package/dist/components/common/VolumeBulkSelect.d.ts +5 -0
  3. package/dist/components/common/VolumePerUnitInput.d.ts +5 -0
  4. package/dist/components/customerPortal/CustomerPortal.d.ts +2 -2
  5. package/dist/components/customerPortal/CustomerPortalContainer.d.ts +4 -0
  6. package/dist/components/customerPortal/index.d.ts +3 -0
  7. package/dist/components/customerPortal/subscriptionOverview/SubscriptionsOverview.d.ts +2 -1
  8. package/dist/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.d.ts +2 -1
  9. package/dist/components/customerPortal/subscriptionOverview/charges/ChargeItem.d.ts +2 -1
  10. package/dist/components/customerPortal/subscriptionOverview/charges/ChargeList.d.ts +2 -1
  11. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.d.ts +2 -1
  12. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/TrialPanel.d.ts +2 -1
  13. package/dist/components/customerPortal/types.d.ts +10 -1
  14. package/dist/components/customerPortal/usage/CustomerUsageData.d.ts +2 -1
  15. package/dist/components/customerPortal/usage/featureUsage/EntitlementCTAButton.d.ts +2 -1
  16. package/dist/components/customerPortal/usage/featureUsage/FeatureUsage.d.ts +2 -1
  17. package/dist/components/paywall/PlanOfferingButton.d.ts +2 -1
  18. package/dist/components/paywall/PlanPrice.d.ts +3 -1
  19. package/dist/components/paywall/index.d.ts +1 -1
  20. package/dist/components/paywall/paywallTextOverrides.d.ts +1 -1
  21. package/dist/components/utils/getPaidPriceText.d.ts +2 -1
  22. package/dist/components/utils/getPlanPrice.d.ts +1 -1
  23. package/dist/components/utils/priceTierUtils.d.ts +3 -2
  24. package/dist/index.d.ts +3 -3
  25. package/dist/react-sdk.cjs.development.js +555 -361
  26. package/dist/react-sdk.cjs.development.js.map +1 -1
  27. package/dist/react-sdk.cjs.production.min.js +1 -1
  28. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  29. package/dist/react-sdk.esm.js +589 -388
  30. package/dist/react-sdk.esm.js.map +1 -1
  31. package/package.json +2 -2
  32. package/src/components/checkout/hooks/usePlanStepModel.ts +3 -3
  33. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +10 -2
  34. package/src/components/common/TiersSelectContainer.tsx +33 -62
  35. package/src/components/common/VolumeBulkSelect.tsx +68 -0
  36. package/src/components/common/VolumePerUnitInput.tsx +40 -0
  37. package/src/components/customerPortal/CustomerPortal.tsx +2 -2
  38. package/src/components/customerPortal/CustomerPortalContainer.tsx +8 -3
  39. package/src/components/customerPortal/index.ts +3 -0
  40. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverview.tsx +2 -1
  41. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.tsx +7 -2
  42. package/src/components/customerPortal/subscriptionOverview/charges/ChargeItem.tsx +2 -1
  43. package/src/components/customerPortal/subscriptionOverview/charges/ChargeList.tsx +2 -1
  44. package/src/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.tsx +2 -1
  45. package/src/components/customerPortal/subscriptionOverview/subscriptionView/TrialPanel.tsx +6 -2
  46. package/src/components/customerPortal/types.ts +15 -1
  47. package/src/components/customerPortal/usage/CustomerUsageData.tsx +2 -1
  48. package/src/components/customerPortal/usage/featureUsage/EntitlementCTAButton.tsx +6 -3
  49. package/src/components/customerPortal/usage/featureUsage/FeatureUsage.tsx +2 -1
  50. package/src/components/paywall/PlanOffering.tsx +15 -6
  51. package/src/components/paywall/PlanOfferingButton.tsx +7 -1
  52. package/src/components/paywall/PlanPrice.tsx +20 -0
  53. package/src/components/paywall/index.ts +1 -1
  54. package/src/components/utils/getPaidPriceText.ts +9 -1
  55. package/src/components/utils/getPlanPrice.ts +2 -0
  56. package/src/components/utils/priceTierUtils.ts +60 -14
  57. package/src/index.ts +9 -1
  58. package/src/stories/mocks/checkout/mockCheckoutPreview.ts +1 -1
@@ -65,6 +65,8 @@ export const PlanPrice = ({
65
65
  locale,
66
66
  hasMonthlyPrice,
67
67
  hasAnnuallyPrice,
68
+ perUnitQuantityByFeature,
69
+ setPerUnitQuantityByFeature,
68
70
  }: {
69
71
  showStartingAt: boolean;
70
72
  withUnitPriceRow: boolean;
@@ -72,6 +74,8 @@ export const PlanPrice = ({
72
74
  withTiersRow: boolean;
73
75
  selectedTierByFeature: Record<string, PriceTierFragment>;
74
76
  setSelectedTierByFeature: React.Dispatch<React.SetStateAction<Record<string, PriceTierFragment>>>;
77
+ perUnitQuantityByFeature: Record<string, number>;
78
+ setPerUnitQuantityByFeature: React.Dispatch<React.SetStateAction<Record<string, number>>>;
75
79
  plan: PaywallPlan;
76
80
  billingPeriod: BillingPeriod;
77
81
  paywallLocale: PaywallLocalization;
@@ -86,6 +90,7 @@ export const PlanPrice = ({
86
90
  locale,
87
91
  hasMonthlyPrice,
88
92
  selectedTierByFeature,
93
+ perUnitQuantityByFeature,
89
94
  );
90
95
 
91
96
  // We currently only support prices with one tier - so we select the first one
@@ -94,6 +99,7 @@ export const PlanPrice = ({
94
99
  });
95
100
  const featureId = tieredPrice ? tieredPrice.feature!.featureId : undefined;
96
101
  const selectedTier = featureId ? selectedTierByFeature[featureId] : undefined;
102
+ const perUnitQuantity = featureId ? perUnitQuantityByFeature[featureId] : undefined;
97
103
 
98
104
  const handleTierChange = (tier: PriceTierFragment) => {
99
105
  if (!featureId) {
@@ -106,6 +112,17 @@ export const PlanPrice = ({
106
112
  }));
107
113
  };
108
114
 
115
+ const handlePerUnitQuantityChange = (quantity: number) => {
116
+ if (!featureId) {
117
+ return;
118
+ }
119
+
120
+ setPerUnitQuantityByFeature((prevState) => ({
121
+ ...prevState,
122
+ [featureId]: quantity,
123
+ }));
124
+ };
125
+
109
126
  return (
110
127
  <PlanPriceContainer as="div" className="stigg-price-text">
111
128
  <>
@@ -146,6 +163,9 @@ export const PlanPrice = ({
146
163
  tierUnits={tierUnits}
147
164
  selectedTier={selectedTier}
148
165
  handleTierChange={handleTierChange}
166
+ tiersMode={tieredPrice?.tiersMode}
167
+ handlePerUnitQuantityChange={handlePerUnitQuantityChange}
168
+ perUnitQuantity={perUnitQuantity}
149
169
  />
150
170
  ) : null}
151
171
  </>
@@ -1,3 +1,3 @@
1
1
  export { PaywallContainer as Paywall, PaywallContainerProps as PaywallProps } from './PaywallContainer';
2
- export { PaywallPlan, OnPlanSelectedCallbackFn, SubscribeIntentionType } from './types';
2
+ export * from './types';
3
3
  export { PaywallLocalization, PlanPriceText, CurrentPlanParams } from './paywallTextOverrides';
@@ -18,6 +18,7 @@ type GetPaidPriceTextParams = {
18
18
  shouldShowMonthlyPriceAmount: boolean;
19
19
  selectedTierByFeature: Record<string, PriceTierFragment>;
20
20
  paywallLocale: PaywallLocalization;
21
+ perUnitQuantityByFeature?: Record<string, number>;
21
22
  };
22
23
 
23
24
  export function getPaidPriceText({
@@ -28,6 +29,7 @@ export function getPaidPriceText({
28
29
  shouldShowMonthlyPriceAmount,
29
30
  selectedTierByFeature,
30
31
  paywallLocale,
32
+ perUnitQuantityByFeature,
31
33
  }: GetPaidPriceTextParams): PlanPriceText {
32
34
  const { amount, currency } = paywallCalculatedPrice || planPrices[0];
33
35
  const priceAmount = amount || 0;
@@ -53,7 +55,13 @@ export function getPaidPriceText({
53
55
  tierUnits = getPriceFeatureUnit(price);
54
56
  }
55
57
 
56
- priceNumber += calculateTierPrice(price, currentTier, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
58
+ priceNumber += calculateTierPrice(
59
+ price,
60
+ currentTier,
61
+ selectedBillingPeriod,
62
+ shouldShowMonthlyPriceAmount,
63
+ perUnitQuantityByFeature?.[price.feature!.featureId],
64
+ );
57
65
  }
58
66
  }
59
67
 
@@ -16,6 +16,7 @@ export function getPlanPrice(
16
16
  locale: string,
17
17
  shouldShowMonthlyPriceAmount: boolean,
18
18
  selectedTierByFeature?: Record<string, PriceTierFragment>,
19
+ perUnitQuantityByFeature?: Record<string, number>,
19
20
  ): PlanPriceText {
20
21
  switch (plan.pricingType) {
21
22
  case PricingType.Free:
@@ -48,6 +49,7 @@ export function getPlanPrice(
48
49
  paywallCalculatedPrice,
49
50
  selectedBillingPeriod: billingPeriod,
50
51
  selectedTierByFeature: selectedTierByFeature || {},
52
+ perUnitQuantityByFeature: perUnitQuantityByFeature || {},
51
53
  };
52
54
 
53
55
  return paywallLocale.price.paid
@@ -14,10 +14,12 @@ export function getTierByQuantity(tiers: PriceTierFragment[], quantity: number)
14
14
  if (!tiers) return undefined;
15
15
 
16
16
  const ascendingTiers = [...tiers];
17
- ascendingTiers.sort((a, b) => a.upTo - b.upTo);
17
+ // Sort tiers by upTo value, ascending, if upTo is not set,
18
+ // put it at the end as it represent the last infinity tier
19
+ ascendingTiers.sort((a, b) => (!a.upTo ? 1 : !b.upTo ? -1 : a.upTo - b.upTo));
18
20
 
19
21
  for (const tier of ascendingTiers) {
20
- if (quantity <= tier.upTo) {
22
+ if (tier.upTo && quantity <= tier.upTo) {
21
23
  return tier;
22
24
  }
23
25
  }
@@ -30,21 +32,52 @@ export function calculateTierPrice(
30
32
  currentTier: PriceTierFragment,
31
33
  selectedBillingPeriod: BillingPeriod,
32
34
  shouldShowMonthlyPriceAmount: boolean,
35
+ perUnitQuantity?: number,
33
36
  ): number {
37
+ const unitPrice =
38
+ selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount
39
+ ? currentTier.unitPrice.amount / 12
40
+ : currentTier.unitPrice.amount;
34
41
  switch (price.tiersMode) {
35
42
  case TiersMode.Volume: {
36
- const unitPrice =
37
- selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount
38
- ? currentTier.unitPrice.amount / 12
39
- : currentTier.unitPrice.amount;
40
-
41
- return unitPrice * currentTier.upTo;
43
+ return unitPrice * (currentTier.upTo || 1);
44
+ }
45
+ case TiersMode.VolumePerUnit: {
46
+ return unitPrice * (perUnitQuantity || 1);
42
47
  }
43
48
  default:
44
49
  return 0;
45
50
  }
46
51
  }
47
52
 
53
+ export function getSelectedTierQuantityBeFeature(
54
+ plan: PaywallPlan,
55
+ billingPeriod: BillingPeriod,
56
+ currentSubscription: Subscription | null,
57
+ ) {
58
+ const result: Record<string, number> = {};
59
+ const planTierPrices = plan.pricePoints.filter(
60
+ (price) => price.billingPeriod === billingPeriod && price.isTieredPrice,
61
+ );
62
+ if (planTierPrices.length === 1) {
63
+ const [price] = planTierPrices;
64
+ const featureId = price?.feature!.featureId;
65
+ if (currentSubscription && currentSubscription.plan.id === plan.id) {
66
+ const tieredPrice = currentSubscription?.prices.find(
67
+ (subscriptionPrice) =>
68
+ subscriptionPrice.pricingModel === BillingModel.PerUnit &&
69
+ subscriptionPrice.tiersMode &&
70
+ subscriptionPrice.feature?.featureId === featureId,
71
+ );
72
+ if (tieredPrice) {
73
+ result[featureId] = tieredPrice.feature?.unitQuantity || 1;
74
+ }
75
+ }
76
+ }
77
+
78
+ return result;
79
+ }
80
+
48
81
  export function getSelectedTier(
49
82
  plan: PaywallPlan,
50
83
  billingPeriod: BillingPeriod,
@@ -64,7 +97,7 @@ export function getSelectedTier(
64
97
 
65
98
  if (selectedTierByFeature[featureId]) {
66
99
  currentTier = price.tiers?.find((tier) => tier.upTo === selectedTierByFeature[featureId].upTo) || currentTier;
67
- } else if (currentSubscription) {
100
+ } else if (currentSubscription && currentSubscription.plan.id === plan.id) {
68
101
  const tieredPrice = currentSubscription.prices.find(
69
102
  (subscriptionPrice) =>
70
103
  subscriptionPrice.pricingModel === BillingModel.PerUnit &&
@@ -94,6 +127,7 @@ export enum PriceTierComparison {
94
127
 
95
128
  export function compareSelectedTierToCurrentTier(
96
129
  selectedTierByFeature: Record<string, PriceTierFragment>,
130
+ perUnitQuantityByFeature: Record<string, number>,
97
131
  currentSubscription: Subscription | null,
98
132
  ): PriceTierComparison {
99
133
  if (!currentSubscription || !selectedTierByFeature) {
@@ -108,22 +142,34 @@ export function compareSelectedTierToCurrentTier(
108
142
  }
109
143
 
110
144
  const { featureId, unitQuantity } = currentTierPrice.feature!;
145
+ const { tiersMode } = currentTierPrice;
111
146
 
112
147
  if (!unitQuantity) {
113
148
  return PriceTierComparison.Equal;
114
149
  }
115
150
 
116
151
  const selectedTier = selectedTierByFeature[featureId];
152
+ const selectedQuantity = perUnitQuantityByFeature[featureId];
117
153
  if (!selectedTier) {
118
154
  return PriceTierComparison.Equal;
119
155
  }
120
156
 
121
- if (selectedTier.upTo < unitQuantity) {
122
- return PriceTierComparison.Lower;
123
- }
157
+ if (tiersMode === TiersMode.Volume) {
158
+ if (selectedTier.upTo && selectedTier.upTo < unitQuantity) {
159
+ return PriceTierComparison.Lower;
160
+ }
124
161
 
125
- if (selectedTier.upTo > unitQuantity) {
126
- return PriceTierComparison.Higher;
162
+ if (selectedTier.upTo && selectedTier.upTo > unitQuantity) {
163
+ return PriceTierComparison.Higher;
164
+ }
165
+ } else if (tiersMode === TiersMode.VolumePerUnit) {
166
+ if (selectedQuantity && selectedQuantity < unitQuantity) {
167
+ return PriceTierComparison.Lower;
168
+ }
169
+
170
+ if (selectedQuantity && selectedQuantity > unitQuantity) {
171
+ return PriceTierComparison.Higher;
172
+ }
127
173
  }
128
174
 
129
175
  return PriceTierComparison.Equal;
package/src/index.ts CHANGED
@@ -10,6 +10,9 @@ export {
10
10
  PaywallLocalization,
11
11
  PlanPriceText,
12
12
  CurrentPlanParams,
13
+ PaywallData,
14
+ SelectDefaultTierIndexFn,
15
+ ShouldHidePlanFn,
13
16
  } from './components/paywall';
14
17
  export {
15
18
  CustomerPortalProvider,
@@ -24,6 +27,11 @@ export {
24
27
  SubscriptionsOverview,
25
28
  SubscriptionsOverviewProps,
26
29
  Promotions,
30
+ CustomerPortalIntentionType,
31
+ OnBuyMoreCallbackFn,
32
+ OnManageSubscriptionFn,
33
+ CustomerPortalLocalization,
34
+ CustomerPortalTheme,
27
35
  } from './components/customerPortal';
28
36
  export {
29
37
  StiggProvider,
@@ -49,5 +57,5 @@ export {
49
57
  TaxDetailsInput,
50
58
  } from './components/checkout';
51
59
  export { useWaitForCheckoutCompleted, ProvisionStatus } from './components/hooks';
52
- export { HorizontalAlignment, TextAlignment } from './theme/types';
60
+ export { HorizontalAlignment, TextAlignment, FontVariant, FontWeight, StiggTheme } from './theme/types';
53
61
  export { CustomizedTheme as Theme } from './theme/Theme';
@@ -69,7 +69,7 @@ const billableFeatureCost = (plan: Plan, billingPeriod: BillingPeriod, featureId
69
69
  const { tiers } = price;
70
70
 
71
71
  if (tiers) {
72
- const quantityTier = tiers.find((tier) => tier.upTo >= quantity);
72
+ const quantityTier = tiers.find((tier) => tier.upTo && tier.upTo >= quantity);
73
73
  const priceTier = quantityTier || tiers[tiers.length - 1];
74
74
  return quantity * priceTier.unitPrice.amount;
75
75
  }