@stigg/react-sdk 4.14.0 → 5.0.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 (46) hide show
  1. package/dist/components/customerPortal/CustomerPortal.d.ts +2 -2
  2. package/dist/components/customerPortal/CustomerPortalContainer.d.ts +4 -0
  3. package/dist/components/customerPortal/index.d.ts +3 -0
  4. package/dist/components/customerPortal/subscriptionOverview/SubscriptionsOverview.d.ts +2 -1
  5. package/dist/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.d.ts +2 -1
  6. package/dist/components/customerPortal/subscriptionOverview/charges/ChargeItem.d.ts +2 -1
  7. package/dist/components/customerPortal/subscriptionOverview/charges/ChargeList.d.ts +2 -1
  8. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.d.ts +2 -1
  9. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/TrialPanel.d.ts +2 -1
  10. package/dist/components/customerPortal/types.d.ts +10 -1
  11. package/dist/components/customerPortal/usage/CustomerUsageData.d.ts +2 -1
  12. package/dist/components/customerPortal/usage/featureUsage/EntitlementCTAButton.d.ts +2 -1
  13. package/dist/components/customerPortal/usage/featureUsage/FeatureUsage.d.ts +2 -1
  14. package/dist/components/paywall/index.d.ts +1 -1
  15. package/dist/components/paywall/paywallTextOverrides.d.ts +6 -1
  16. package/dist/components/utils/priceTierUtils.d.ts +3 -1
  17. package/dist/index.d.ts +3 -3
  18. package/dist/react-sdk.cjs.development.js +82 -55
  19. package/dist/react-sdk.cjs.development.js.map +1 -1
  20. package/dist/react-sdk.cjs.production.min.js +1 -1
  21. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  22. package/dist/react-sdk.esm.js +87 -58
  23. package/dist/react-sdk.esm.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/components/checkout/hooks/usePlanStepModel.ts +3 -3
  26. package/src/components/checkout/summary/components/LineItems.tsx +7 -3
  27. package/src/components/common/TiersSelectContainer.tsx +7 -14
  28. package/src/components/customerPortal/CustomerPortal.tsx +2 -2
  29. package/src/components/customerPortal/CustomerPortalContainer.tsx +8 -3
  30. package/src/components/customerPortal/index.ts +3 -0
  31. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverview.tsx +2 -1
  32. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.tsx +7 -2
  33. package/src/components/customerPortal/subscriptionOverview/charges/ChargeItem.tsx +2 -1
  34. package/src/components/customerPortal/subscriptionOverview/charges/ChargeList.tsx +2 -1
  35. package/src/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.tsx +2 -1
  36. package/src/components/customerPortal/subscriptionOverview/subscriptionView/TrialPanel.tsx +6 -2
  37. package/src/components/customerPortal/types.ts +15 -1
  38. package/src/components/customerPortal/usage/CustomerUsageData.tsx +2 -1
  39. package/src/components/customerPortal/usage/featureUsage/EntitlementCTAButton.tsx +6 -3
  40. package/src/components/customerPortal/usage/featureUsage/FeatureUsage.tsx +2 -1
  41. package/src/components/paywall/index.ts +1 -1
  42. package/src/components/utils/calculateDiscountRate.ts +2 -1
  43. package/src/components/utils/getPaidPriceText.ts +1 -1
  44. package/src/components/utils/priceTierUtils.ts +41 -21
  45. package/src/index.ts +9 -1
  46. package/src/stories/mocks/checkout/mockCheckoutState.ts +4 -4
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.14.0",
2
+ "version": "5.0.0",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -112,7 +112,7 @@
112
112
  "@emotion/react": "^11.10.5",
113
113
  "@emotion/styled": "^11.10.5",
114
114
  "@mui/material": "^5.12.0",
115
- "@stigg/js-client-sdk": "2.25.0",
115
+ "@stigg/js-client-sdk": "3.0.0",
116
116
  "@stripe/react-stripe-js": "^2.1.1",
117
117
  "@stripe/stripe-js": "^1.54.1",
118
118
  "@types/styled-components": "^5.1.26",
@@ -1,9 +1,9 @@
1
1
  import keyBy from 'lodash/keyBy';
2
2
  import compact from 'lodash/compact';
3
- import { BillableFeatureInput, BillingPeriod, TiersMode } from '@stigg/api-client-js/src/generated/sdk';
3
+ import { BillableFeatureInput, BillingPeriod } from '@stigg/api-client-js/src/generated/sdk';
4
4
  import { BillableFeature, BillingModel, Plan, Price, Subscription } from '@stigg/js-client-sdk';
5
5
  import { useCheckoutContext } from '../CheckoutProvider';
6
- import { getTierByQuantity } from '../../utils/priceTierUtils';
6
+ import { getTierByQuantity, hasTierWithUnitPrice } from '../../utils/priceTierUtils';
7
7
  import { getValidPriceQuantity } from '../../utils/priceUtils';
8
8
 
9
9
  export type PlanStepState = {
@@ -73,7 +73,7 @@ function getBillableFeatures(
73
73
 
74
74
  quantity = getValidPriceQuantity(price, preconfiguredQuantity || 1);
75
75
 
76
- if (price.isTieredPrice && price.tiersMode === TiersMode.Volume) {
76
+ if (price.isTieredPrice && !hasTierWithUnitPrice(price.tiers)) {
77
77
  const tier = getTierByQuantity(price.tiers!, quantity);
78
78
  quantity = tier!.upTo!;
79
79
  }
@@ -10,7 +10,7 @@ import {
10
10
  } from '@stigg/js-client-sdk';
11
11
  import { Typography } from '../../../common/Typography';
12
12
  import { currencyPriceFormatter } from '../../../utils/currencyUtils';
13
- import { getTierByQuantity } from '../../../utils/priceTierUtils';
13
+ import { calculateTierPriceVolume, getTierByQuantity } from '../../../utils/priceTierUtils';
14
14
  import { WithSkeleton } from './WithSkeleton';
15
15
  import { Skeleton } from '../../components/Skeletons.style';
16
16
  import { CheckoutLocalization } from '../../configurations/textOverrides';
@@ -33,6 +33,10 @@ export const getPriceString = ({ amount, price, quantity }: { amount: number; pr
33
33
  const { billingPeriod } = price;
34
34
  let billingPeriodString = null;
35
35
 
36
+ if (quantity) {
37
+ amount /= quantity;
38
+ }
39
+
36
40
  if (billingPeriod === BillingPeriod.Annually) {
37
41
  amount /= 12;
38
42
  billingPeriodString = '12 months';
@@ -71,7 +75,7 @@ export const BilledPriceLineItem = ({
71
75
  let amount;
72
76
  if (price.isTieredPrice) {
73
77
  const tier = getTierByQuantity(price.tiers!, quantity);
74
- amount = tier!.unitPrice.amount!;
78
+ amount = calculateTierPriceVolume(tier!, quantity);
75
79
  } else {
76
80
  amount = price.amount!;
77
81
  }
@@ -92,7 +96,7 @@ export const BilledPriceLineItem = ({
92
96
  <Grid item display="flex" gap={1} alignItems="center">
93
97
  {isPayAsYouGo && <PayAsYouGoPriceTooltip checkoutLocalization={checkoutLocalization} />}
94
98
  <Typography variant="body1" color="secondary" style={{ wordBreak: 'break-word' }}>
95
- {currencyPriceFormatter({ amount: quantity * amount, currency: price.currency, minimumFractionDigits: 2 })}
99
+ {currencyPriceFormatter({ amount, currency: price.currency, minimumFractionDigits: 2 })}
96
100
  {isPayAsYouGo && ' / unit'}
97
101
  </Typography>
98
102
  </Grid>
@@ -1,7 +1,7 @@
1
1
  import { PriceTierFragment, TiersMode } from '@stigg/js-client-sdk';
2
2
  import React from 'react';
3
3
  import styled from '@emotion/styled/macro';
4
- import { getTierByQuantity } from '../utils/priceTierUtils';
4
+ import { getTierByQuantity, hasTierWithUnitPrice } from '../utils/priceTierUtils';
5
5
  import { Typography } from './Typography';
6
6
  import { VolumePerUnitInput } from './VolumePerUnitInput';
7
7
  import { VolumeBulkSelect } from './VolumeBulkSelect';
@@ -23,27 +23,20 @@ const TiersSelectLayout = styled(Typography)`
23
23
  `;
24
24
 
25
25
  export function TiersSelectContainer(props: TiersSelectContainerProps) {
26
- const { tiers, tiersMode, handleTierChange } = props;
26
+ const { tiers, handleTierChange } = props;
27
27
  const handleChange = (quantity: number) => {
28
28
  if (!tiers) return;
29
29
 
30
30
  handleTierChange(getTierByQuantity(tiers, quantity)!);
31
31
  };
32
32
 
33
- const getContent = () => {
34
- switch (tiersMode) {
35
- case TiersMode.VolumePerUnit:
36
- return <VolumePerUnitInput handleChange={handleChange} {...props} />;
37
- case TiersMode.Volume:
38
- return <VolumeBulkSelect handleChange={handleChange} {...props} />;
39
- default:
40
- return <div />;
41
- }
42
- };
43
-
44
33
  return (
45
34
  <TiersSelectLayout as="div" className="stigg-price-tier-select">
46
- {getContent()}
35
+ {hasTierWithUnitPrice(tiers) ? (
36
+ <VolumePerUnitInput handleChange={handleChange} {...props} />
37
+ ) : (
38
+ <VolumeBulkSelect handleChange={handleChange} {...props} />
39
+ )}
47
40
  </TiersSelectLayout>
48
41
  );
49
42
  }
@@ -5,7 +5,7 @@ import { CustomerPortalContainer } from './CustomerPortalContainer';
5
5
  import { DeepPartial } from '../../types';
6
6
  import { CustomerPortalLocalization } from './customerPortalTextOverrides';
7
7
  import { CustomerPortalTheme } from './customerPortalTheme';
8
- import { OnBuyMoreCallbackFn } from './types';
8
+ import { OnBuyMoreCallbackFn, OnManageSubscriptionFn } from './types';
9
9
 
10
10
  export type CustomerPortalSection =
11
11
  | 'usage'
@@ -16,7 +16,7 @@ export type CustomerPortalSection =
16
16
  | 'invoices';
17
17
 
18
18
  export type CustomerPortalProps = {
19
- onManageSubscription?: () => Promise<void> | void;
19
+ onManageSubscription?: OnManageSubscriptionFn;
20
20
  onBuyMore?: OnBuyMoreCallbackFn;
21
21
  onCancelScheduledUpdates?: (subscription: CustomerPortalSubscription) => Promise<void> | void;
22
22
  onContactSupport?: () => Promise<void> | void;
@@ -8,6 +8,9 @@ import { CustomerPortalLayout, CustomerPortalSections } from './CustomerPortal.s
8
8
  import { CustomerPortalProps } from './CustomerPortal';
9
9
  import { InvoicesSection, useStiggContext } from '../..';
10
10
  import { CustomerUsageData } from './usage/CustomerUsageData';
11
+ import { CustomerPortalIntentionType } from './types';
12
+
13
+ export type OnManageClick = ({ intentionType }: { intentionType: CustomerPortalIntentionType }) => void;
11
14
 
12
15
  export function CustomerPortalContainer({
13
16
  onManageSubscription,
@@ -21,10 +24,12 @@ export function CustomerPortalContainer({
21
24
  const { customerPortal, textOverrides, theme, isLoading } = useCustomerPortalContext();
22
25
  const customerPortalSectionRef = useRef<HTMLDivElement>(null);
23
26
 
24
- const onManageClick = () => {
27
+ const onManageClick: OnManageClick = ({ intentionType }: { intentionType: CustomerPortalIntentionType }) => {
25
28
  if (onManageSubscription) {
26
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
27
- onManageSubscription();
29
+ void onManageSubscription({
30
+ intentionType,
31
+ customerSubscriptions: customerPortal?.subscriptions ?? [],
32
+ });
28
33
  } else {
29
34
  customerPortalSectionRef?.current?.scrollIntoView({ behavior: 'smooth' });
30
35
  }
@@ -6,3 +6,6 @@ export { CustomerUsageData, CustomerUsageDataProps } from './usage/CustomerUsage
6
6
  export { AddonsList } from './subscriptionOverview/tabs/AddonsList';
7
7
  export { Promotions } from './subscriptionOverview/tabs/Promotions';
8
8
  export { CustomerPortalProvider } from './CustomerPortalProvider';
9
+ export { CustomerPortalLocalization } from './customerPortalTextOverrides';
10
+ export { CustomerPortalTheme } from './customerPortalTheme';
11
+ export * from './types';
@@ -11,9 +11,10 @@ import { UpcomingBilling } from './upcomingBilling/UpcomingBilling';
11
11
  import { SubscriptionView } from './subscriptionView/SubscriptionView';
12
12
  import { ChargeList } from './charges/ChargeList';
13
13
  import { OnBuyMoreCallbackFn } from '../types';
14
+ import { OnManageClick } from '../CustomerPortalContainer';
14
15
 
15
16
  export type SubscriptionsOverviewProps = {
16
- onManageSubscription: () => void;
17
+ onManageSubscription: OnManageClick;
17
18
  onBuyMore?: OnBuyMoreCallbackFn;
18
19
  onCancelScheduledUpdates?: (subscription: CustomerPortalSubscription) => void;
19
20
  onContactSupport?: () => void;
@@ -6,9 +6,11 @@ import EditIcon from '../../../assets/edit-icon.svg';
6
6
  import { CustomerPortalLocalization } from '../customerPortalTextOverrides';
7
7
  import { SectionHeader } from '../common/SectionHeader';
8
8
  import { SectionTitle } from '../common/SectionTitle';
9
+ import { OnManageClick } from '../CustomerPortalContainer';
10
+ import { CustomerPortalIntentionType } from '../types';
9
11
 
10
12
  type SubscriptionsOverviewHeaderProps = {
11
- onManageSubscription: () => void;
13
+ onManageSubscription: OnManageClick;
12
14
  hideManageButton: boolean;
13
15
  textOverrides: CustomerPortalLocalization;
14
16
  };
@@ -28,7 +30,10 @@ export function SubscriptionsOverviewHeader({
28
30
  <SectionHeader className="stigg-customer-portal-overview-header" $disableMargin>
29
31
  <SectionTitle title="Subscription" className="stigg-overview-title" />
30
32
  {!hideManageButton && (
31
- <StyledButton className="stigg-manage-subscription-button" variant="outlined" onClick={onManageSubscription}>
33
+ <StyledButton
34
+ className="stigg-manage-subscription-button"
35
+ variant="outlined"
36
+ onClick={() => onManageSubscription({ intentionType: CustomerPortalIntentionType.MANAGE_SUBSCRIPTION })}>
32
37
  <StyledEditIcon className="stigg-manage-subscription-button-image" />
33
38
  <Typography
34
39
  className="stigg-manage-subscription-button-text"
@@ -7,6 +7,7 @@ import { FeatureUsageProgressBar } from '../../usage/featureUsage/FeatureUsagePr
7
7
  import { LongText } from '../../../common/LongText';
8
8
  import { EntitlementCtaButton } from '../../usage/featureUsage/EntitlementCTAButton';
9
9
  import { OnBuyMoreCallbackFn } from '../../types';
10
+ import { OnManageClick } from '../../CustomerPortalContainer';
10
11
 
11
12
  export type UsageBasedChargeProps = {
12
13
  entitlement: Exclude<CustomerPortalEntitlement, 'feature'>;
@@ -14,7 +15,7 @@ export type UsageBasedChargeProps = {
14
15
  amount: number;
15
16
  currency: Currency;
16
17
  onBuyMore?: OnBuyMoreCallbackFn;
17
- onManageSubscription: () => void;
18
+ onManageSubscription: OnManageClick;
18
19
  canUpgradeSubscription: boolean;
19
20
  hasCustomSubscription: boolean;
20
21
  hideChargePrice?: boolean;
@@ -3,12 +3,13 @@ import React from 'react';
3
3
  import { keyBy } from 'lodash';
4
4
  import { ChargeItem } from './ChargeItem';
5
5
  import { OnBuyMoreCallbackFn } from '../../types';
6
+ import { OnManageClick } from '../../CustomerPortalContainer';
6
7
 
7
8
  export type ChargesProps = {
8
9
  subscription: CustomerPortalSubscription;
9
10
  entitlements: CustomerPortalEntitlement[];
10
11
  onBuyMore?: OnBuyMoreCallbackFn;
11
- onManageSubscription: () => void;
12
+ onManageSubscription: OnManageClick;
12
13
  canUpgradeSubscription: boolean;
13
14
  hasCustomSubscription: boolean;
14
15
  };
@@ -3,11 +3,12 @@ import { CustomerPortalSubscription } from '@stigg/js-client-sdk';
3
3
  import { Typography } from '../../../common/Typography';
4
4
  import { TrialPanel } from './TrialPanel';
5
5
  import { CustomerPortalTheme } from '../../customerPortalTheme';
6
+ import { OnManageClick } from '../../CustomerPortalContainer';
6
7
 
7
8
  type SubscriptionViewProps = {
8
9
  mainSubscription: CustomerPortalSubscription;
9
10
  trialSubscription: CustomerPortalSubscription | undefined;
10
- onManageSubscription: () => void;
11
+ onManageSubscription: OnManageClick;
11
12
  theme: CustomerPortalTheme;
12
13
  };
13
14
 
@@ -5,6 +5,8 @@ import Link from '@mui/material/Link';
5
5
  import SandClockIcon from '../../../../assets/sand-clock.svg';
6
6
  import { Typography } from '../../../common/Typography';
7
7
  import { LongText } from '../../../common/LongText';
8
+ import { OnManageClick } from '../../CustomerPortalContainer';
9
+ import { CustomerPortalIntentionType } from '../../types';
8
10
 
9
11
  const OnTrialBadge = styled.div`
10
12
  width: 100%;
@@ -30,7 +32,7 @@ export function TrialPanel({
30
32
  }: {
31
33
  subscription: CustomerPortalSubscription | undefined;
32
34
  includePlanName: boolean;
33
- onManageSubscription?: () => void;
35
+ onManageSubscription: OnManageClick;
34
36
  }) {
35
37
  if (subscription?.status !== SubscriptionStatus.InTrial) {
36
38
  return null;
@@ -47,7 +49,9 @@ export function TrialPanel({
47
49
  </LongText>
48
50
  </div>
49
51
 
50
- <StyledLink className="stigg-subscription-trial-upgrade-button" onClick={onManageSubscription}>
52
+ <StyledLink
53
+ className="stigg-subscription-trial-upgrade-button"
54
+ onClick={() => onManageSubscription({ intentionType: CustomerPortalIntentionType.UPGRADE_TRIAL_PLAN })}>
51
55
  <Typography color="white">Upgrade plan</Typography>
52
56
  </StyledLink>
53
57
  </OnTrialBadge>
@@ -1,4 +1,18 @@
1
- import { CustomerPortalEntitlement } from '@stigg/js-client-sdk';
1
+ import { CustomerPortalEntitlement, CustomerPortalSubscription } from '@stigg/js-client-sdk';
2
2
  import { FeatureFragment } from '@stigg/api-client-js/src/generated/sdk';
3
3
 
4
4
  export type OnBuyMoreCallbackFn = (feature: FeatureFragment, entitlement: CustomerPortalEntitlement) => void;
5
+
6
+ export enum CustomerPortalIntentionType {
7
+ MANAGE_SUBSCRIPTION = 'MANAGE_SUBSCRIPTION',
8
+ UPGRADE_PLAN = 'UPGRADE_PLAN',
9
+ UPGRADE_TRIAL_PLAN = 'UPGRADE_TRIAL_PLAN',
10
+ }
11
+
12
+ export type OnManageSubscriptionFn = ({
13
+ intentionType,
14
+ customerSubscriptions,
15
+ }: {
16
+ intentionType: CustomerPortalIntentionType;
17
+ customerSubscriptions: CustomerPortalSubscription[];
18
+ }) => Promise<void> | void;
@@ -11,11 +11,12 @@ import { SectionHeader } from '../common/SectionHeader';
11
11
  import { SectionTitle } from '../common/SectionTitle';
12
12
  import { StyledButton } from '../common/StyledButton';
13
13
  import { OnBuyMoreCallbackFn } from '../types';
14
+ import { OnManageClick } from '../CustomerPortalContainer';
14
15
 
15
16
  const MAX_BOXES = 6;
16
17
 
17
18
  export type CustomerUsageDataProps = {
18
- onManageSubscription?: () => void;
19
+ onManageSubscription?: OnManageClick;
19
20
  onBuyMore?: OnBuyMoreCallbackFn;
20
21
  };
21
22
 
@@ -5,7 +5,8 @@ import React from 'react';
5
5
  import styled from 'styled-components';
6
6
  import { getUsagePercentage, USAGE_PERCENTAGE_WARNING_THRESHOLD } from './FeatureUsage.helper';
7
7
  import { Typography } from '../../../common/Typography';
8
- import { OnBuyMoreCallbackFn } from '../../types';
8
+ import { CustomerPortalIntentionType, OnBuyMoreCallbackFn } from '../../types';
9
+ import { OnManageClick } from '../../CustomerPortalContainer';
9
10
 
10
11
  const StyledButton = styled(Button)`
11
12
  text-transform: none;
@@ -16,7 +17,7 @@ const StyledButton = styled(Button)`
16
17
  export type EntitlementCtaButtonProps = {
17
18
  entitlement: Exclude<CustomerPortalEntitlement, 'feature'>;
18
19
  feature: FeatureFragment;
19
- onManageSubscription: (() => void) | undefined;
20
+ onManageSubscription: OnManageClick | undefined;
20
21
  onBuyMore?: OnBuyMoreCallbackFn;
21
22
  canBuyMore: boolean;
22
23
  canUpgradeSubscription: boolean;
@@ -50,7 +51,9 @@ export function EntitlementCtaButton({
50
51
 
51
52
  if (canUpgradeSubscription) {
52
53
  return onManageSubscription ? (
53
- <StyledButton variant="text" onClick={onManageSubscription}>
54
+ <StyledButton
55
+ variant="text"
56
+ onClick={() => onManageSubscription({ intentionType: CustomerPortalIntentionType.UPGRADE_PLAN })}>
54
57
  <Typography color="primary.main">Upgrade</Typography>
55
58
  </StyledButton>
56
59
  ) : null;
@@ -13,11 +13,12 @@ import { InformationTooltip } from '../../../common/InformationTooltip';
13
13
  import { LongText } from '../../../common/LongText';
14
14
  import { EntitlementCtaButton } from './EntitlementCTAButton';
15
15
  import { OnBuyMoreCallbackFn } from '../../types';
16
+ import { OnManageClick } from '../../CustomerPortalContainer';
16
17
 
17
18
  export type UsageBoxProps = {
18
19
  entitlement: CustomerPortalEntitlement;
19
20
  subscriptionPrice: CustomerPortalSubscriptionPriceFragment | undefined;
20
- onManageSubscription: (() => void) | undefined;
21
+ onManageSubscription: OnManageClick | undefined;
21
22
  onBuyMore?: OnBuyMoreCallbackFn;
22
23
  hasCustomSubscription: boolean;
23
24
  canUpgradeSubscription: boolean;
@@ -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';
@@ -1,6 +1,7 @@
1
1
  import { BillingPeriod, PaywallCalculatedPricePoint, Price } from '@stigg/js-client-sdk';
2
2
  import isNil from 'lodash/isNil';
3
3
  import { PaywallPlan } from '../paywall';
4
+ import { calculateTierPriceVolume } from './priceTierUtils';
4
5
 
5
6
  export function calculateDiscountRate(monthlyPrice?: number | null, annuallyPrice?: number | null) {
6
7
  if (!isNil(monthlyPrice) && !isNil(annuallyPrice)) {
@@ -26,7 +27,7 @@ function getPlanBillingPeriodAmount(plan: PaywallPlan, billingPeriod: BillingPer
26
27
  });
27
28
 
28
29
  if (tieredPrice) {
29
- return tieredPrice.tiers![0].unitPrice.amount;
30
+ return calculateTierPriceVolume(tieredPrice.tiers![0], 1);
30
31
  }
31
32
  }
32
33
 
@@ -60,7 +60,7 @@ export function getPaidPriceText({
60
60
  currentTier,
61
61
  selectedBillingPeriod,
62
62
  shouldShowMonthlyPriceAmount,
63
- perUnitQuantityByFeature?.[price.feature!.featureId],
63
+ perUnitQuantityByFeature?.[price.feature!.featureId] || 1,
64
64
  );
65
65
  }
66
66
  }
@@ -1,4 +1,5 @@
1
1
  import { BillingModel, TiersMode, BillingPeriod, Price, PriceTierFragment, Subscription } from '@stigg/js-client-sdk';
2
+ import isNil from 'lodash/isNil';
2
3
  import { PaywallPlan } from '../paywall';
3
4
  import { SelectDefaultTierIndexFn } from '../paywall/types';
4
5
 
@@ -27,23 +28,45 @@ export function getTierByQuantity(tiers: PriceTierFragment[], quantity: number)
27
28
  return ascendingTiers[ascendingTiers.length - 1];
28
29
  }
29
30
 
31
+ function getAmount(amount: number, selectedBillingPeriod?: BillingPeriod, shouldShowMonthlyPriceAmount?: boolean) {
32
+ return selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount ? amount / 12 : amount;
33
+ }
34
+
35
+ export function calculateTierPriceVolume(
36
+ currentTier: PriceTierFragment,
37
+ perUnitQuantity: number,
38
+ selectedBillingPeriod?: BillingPeriod,
39
+ shouldShowMonthlyPriceAmount?: boolean,
40
+ ): number {
41
+ let amount = 0;
42
+
43
+ if (currentTier.unitPrice) {
44
+ const unitPrice = getAmount(currentTier.unitPrice.amount, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
45
+ amount += unitPrice * perUnitQuantity;
46
+ }
47
+
48
+ if (currentTier.flatPrice) {
49
+ amount += getAmount(currentTier.flatPrice.amount, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
50
+ }
51
+
52
+ return amount;
53
+ }
54
+
30
55
  export function calculateTierPrice(
31
56
  price: Price,
32
57
  currentTier: PriceTierFragment,
33
58
  selectedBillingPeriod: BillingPeriod,
34
59
  shouldShowMonthlyPriceAmount: boolean,
35
- perUnitQuantity?: number,
60
+ perUnitQuantity: number,
36
61
  ): number {
37
- const unitPrice =
38
- selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount
39
- ? currentTier.unitPrice.amount / 12
40
- : currentTier.unitPrice.amount;
41
62
  switch (price.tiersMode) {
42
63
  case TiersMode.Volume: {
43
- return unitPrice * (currentTier.upTo || 1);
44
- }
45
- case TiersMode.VolumePerUnit: {
46
- return unitPrice * (perUnitQuantity || 1);
64
+ return calculateTierPriceVolume(
65
+ currentTier,
66
+ perUnitQuantity,
67
+ selectedBillingPeriod,
68
+ shouldShowMonthlyPriceAmount,
69
+ );
47
70
  }
48
71
  default:
49
72
  return 0;
@@ -78,6 +101,10 @@ export function getSelectedTierQuantityBeFeature(
78
101
  return result;
79
102
  }
80
103
 
104
+ export function hasTierWithUnitPrice(tiers: PriceTierFragment[] | null | undefined) {
105
+ return tiers?.some(({ unitPrice, upTo }) => unitPrice && !isNil(upTo));
106
+ }
107
+
81
108
  export function getSelectedTier(
82
109
  plan: PaywallPlan,
83
110
  billingPeriod: BillingPeriod,
@@ -142,7 +169,7 @@ export function compareSelectedTierToCurrentTier(
142
169
  }
143
170
 
144
171
  const { featureId, unitQuantity } = currentTierPrice.feature!;
145
- const { tiersMode } = currentTierPrice;
172
+ const { tiers } = currentTierPrice;
146
173
 
147
174
  if (!unitQuantity) {
148
175
  return PriceTierComparison.Equal;
@@ -154,20 +181,13 @@ export function compareSelectedTierToCurrentTier(
154
181
  return PriceTierComparison.Equal;
155
182
  }
156
183
 
157
- if (tiersMode === TiersMode.Volume) {
158
- if (selectedTier.upTo && selectedTier.upTo < unitQuantity) {
159
- return PriceTierComparison.Lower;
160
- }
184
+ const effectiveQuantity = hasTierWithUnitPrice(tiers) ? selectedQuantity : selectedTier.upTo;
161
185
 
162
- if (selectedTier.upTo && selectedTier.upTo > unitQuantity) {
163
- return PriceTierComparison.Higher;
164
- }
165
- } else if (tiersMode === TiersMode.VolumePerUnit) {
166
- if (selectedQuantity && selectedQuantity < unitQuantity) {
186
+ if (!isNil(effectiveQuantity)) {
187
+ if (effectiveQuantity < unitQuantity) {
167
188
  return PriceTierComparison.Lower;
168
189
  }
169
-
170
- if (selectedQuantity && selectedQuantity > unitQuantity) {
190
+ if (effectiveQuantity > unitQuantity) {
171
191
  return PriceTierComparison.Higher;
172
192
  }
173
193
  }
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';
@@ -116,8 +116,8 @@ function tieredPricing(): Price[] {
116
116
  tiersMode: TiersMode.Volume,
117
117
  tiers: TIERS.map((tier, index) => ({
118
118
  upTo: tier,
119
- unitPrice: {
120
- amount: TIERS_PRICE_MONTHLY[index] / tier,
119
+ flatPrice: {
120
+ amount: TIERS_PRICE_MONTHLY[index],
121
121
  currency: Currency.Usd,
122
122
  },
123
123
  })),
@@ -131,8 +131,8 @@ function tieredPricing(): Price[] {
131
131
  tiersMode: TiersMode.Volume,
132
132
  tiers: TIERS.map((tier, index) => ({
133
133
  upTo: tier,
134
- unitPrice: {
135
- amount: TIERS_PRICE_YEARLY[index] / tier,
134
+ flatPrice: {
135
+ amount: TIERS_PRICE_YEARLY[index],
136
136
  currency: Currency.Usd,
137
137
  },
138
138
  })),