@stigg/react-sdk 5.2.1 → 5.3.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.
- package/dist/components/common/TiersSelectContainer.d.ts +2 -4
- package/dist/components/common/VolumeBulkSelect.d.ts +1 -1
- package/dist/components/common/VolumePerUnitInput.d.ts +1 -1
- package/dist/components/paywall/PlanOfferingButton.d.ts +2 -3
- package/dist/components/paywall/PlanPrice.d.ts +2 -4
- package/dist/components/utils/getPaidPriceText.d.ts +2 -3
- package/dist/components/utils/getPlanPrice.d.ts +1 -1
- package/dist/components/utils/priceTierUtils.d.ts +4 -5
- package/dist/react-sdk.cjs.development.js +82 -176
- package/dist/react-sdk.cjs.development.js.map +1 -1
- package/dist/react-sdk.cjs.production.min.js +1 -1
- package/dist/react-sdk.cjs.production.min.js.map +1 -1
- package/dist/react-sdk.esm.js +83 -177
- package/dist/react-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/checkout/hooks/usePlanStepModel.ts +1 -1
- package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +4 -11
- package/src/components/checkout/summary/components/LineItems.tsx +1 -1
- package/src/components/common/TiersSelectContainer.tsx +5 -16
- package/src/components/common/VolumeBulkSelect.tsx +7 -4
- package/src/components/common/VolumePerUnitInput.tsx +3 -5
- package/src/components/paywall/Paywall.tsx +2 -2
- package/src/components/paywall/PlanOffering.tsx +6 -27
- package/src/components/paywall/PlanOfferingButton.tsx +2 -8
- package/src/components/paywall/PlanPrice.tsx +4 -23
- package/src/components/utils/getPaidPriceText.ts +6 -24
- package/src/components/utils/getPlanPrice.ts +0 -2
- package/src/components/utils/priceTierUtils.ts +25 -69
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
|
|
|
3
3
|
import styled from '@emotion/styled';
|
|
4
4
|
import Box from '@mui/material/Box';
|
|
5
5
|
import { BillableFeatureInput } from '@stigg/api-client-js/src/generated/sdk';
|
|
6
|
-
import { BillingModel, BillingPeriod, Plan, Price
|
|
6
|
+
import { BillingModel, BillingPeriod, Plan, Price } from '@stigg/js-client-sdk';
|
|
7
7
|
|
|
8
8
|
import { Typography } from '../../../common/Typography';
|
|
9
9
|
import { useChargesSort } from '../../../hooks/useChargeSort';
|
|
@@ -12,7 +12,6 @@ import { currencyPriceFormatter } from '../../../utils/currencyUtils';
|
|
|
12
12
|
import { InputField } from '../../components';
|
|
13
13
|
import { useCheckoutModel, usePlanStepModel, useProgressBarModel } from '../../hooks';
|
|
14
14
|
import { TiersSelectContainer } from '../../../common/TiersSelectContainer';
|
|
15
|
-
import { getTierByQuantity } from '../../../utils/priceTierUtils';
|
|
16
15
|
import { getValidPriceQuantity } from '../../../utils/priceUtils';
|
|
17
16
|
import { getFeatureDisplayNameText } from '../../../utils/getFeatureName';
|
|
18
17
|
|
|
@@ -104,20 +103,14 @@ export function PlanCharge({
|
|
|
104
103
|
chargeRow += ' / unit';
|
|
105
104
|
}
|
|
106
105
|
} else if (charge.isTieredPrice && charge.tiersMode && featureId) {
|
|
107
|
-
const
|
|
106
|
+
const quantity = billableFeature?.quantity || 1;
|
|
108
107
|
chargeRow = (
|
|
109
108
|
<TiersSelectContainer
|
|
110
109
|
componentId={`${featureId}-tiers`}
|
|
111
110
|
tiers={charge.tiers}
|
|
112
|
-
selectedTier={tier}
|
|
113
|
-
handleTierChange={(tier: PriceTierFragment) => {
|
|
114
|
-
if (tier.upTo) {
|
|
115
|
-
setBillableFeature(featureId, tier.upTo);
|
|
116
|
-
}
|
|
117
|
-
}}
|
|
118
111
|
tiersMode={charge.tiersMode}
|
|
119
|
-
|
|
120
|
-
|
|
112
|
+
value={quantity}
|
|
113
|
+
handleChange={(quantity: number) => {
|
|
121
114
|
setBillableFeature(featureId, quantity);
|
|
122
115
|
}}
|
|
123
116
|
width={120}
|
|
@@ -75,7 +75,7 @@ export const BilledPriceLineItem = ({
|
|
|
75
75
|
let amount;
|
|
76
76
|
if (price.isTieredPrice) {
|
|
77
77
|
const tier = getTierByQuantity(price.tiers!, quantity);
|
|
78
|
-
amount = calculateTierPriceVolume(tier
|
|
78
|
+
amount = calculateTierPriceVolume(tier, quantity);
|
|
79
79
|
} else {
|
|
80
80
|
amount = price.amount!;
|
|
81
81
|
}
|
|
@@ -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 {
|
|
4
|
+
import { hasTierWithUnitPrice } from '../utils/priceTierUtils';
|
|
5
5
|
import { Typography } from './Typography';
|
|
6
6
|
import { VolumePerUnitInput } from './VolumePerUnitInput';
|
|
7
7
|
import { VolumeBulkSelect } from './VolumeBulkSelect';
|
|
@@ -10,11 +10,9 @@ export type TiersSelectContainerProps = {
|
|
|
10
10
|
componentId: string;
|
|
11
11
|
tiers?: PriceTierFragment[] | null;
|
|
12
12
|
tierUnits?: string;
|
|
13
|
-
selectedTier?: PriceTierFragment;
|
|
14
|
-
handleTierChange: (tier: PriceTierFragment) => void;
|
|
15
13
|
tiersMode?: TiersMode | null;
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
handleChange: (quantity: number) => void;
|
|
15
|
+
value: number;
|
|
18
16
|
width?: number;
|
|
19
17
|
};
|
|
20
18
|
|
|
@@ -23,20 +21,11 @@ const TiersSelectLayout = styled(Typography)`
|
|
|
23
21
|
`;
|
|
24
22
|
|
|
25
23
|
export function TiersSelectContainer(props: TiersSelectContainerProps) {
|
|
26
|
-
const { tiers
|
|
27
|
-
const handleChange = (quantity: number) => {
|
|
28
|
-
if (!tiers) return;
|
|
29
|
-
|
|
30
|
-
handleTierChange(getTierByQuantity(tiers, quantity)!);
|
|
31
|
-
};
|
|
24
|
+
const { tiers } = props;
|
|
32
25
|
|
|
33
26
|
return (
|
|
34
27
|
<TiersSelectLayout as="div" className="stigg-price-tier-select">
|
|
35
|
-
{hasTierWithUnitPrice(tiers) ?
|
|
36
|
-
<VolumePerUnitInput handleChange={handleChange} {...props} />
|
|
37
|
-
) : (
|
|
38
|
-
<VolumeBulkSelect handleChange={handleChange} {...props} />
|
|
39
|
-
)}
|
|
28
|
+
{hasTierWithUnitPrice(tiers) ? <VolumePerUnitInput {...props} /> : <VolumeBulkSelect {...props} />}
|
|
40
29
|
</TiersSelectLayout>
|
|
41
30
|
);
|
|
42
31
|
}
|
|
@@ -29,12 +29,12 @@ const TierInput = styled(OutlinedInput)`
|
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
31
|
export function VolumeBulkSelect({
|
|
32
|
-
|
|
32
|
+
value,
|
|
33
33
|
componentId,
|
|
34
34
|
tierUnits,
|
|
35
35
|
tiers,
|
|
36
36
|
handleChange,
|
|
37
|
-
}: Pick<TiersSelectContainerProps, '
|
|
37
|
+
}: Pick<TiersSelectContainerProps, 'value' | 'componentId' | 'tiers' | 'tierUnits'> & {
|
|
38
38
|
handleChange: (quantity: number) => void;
|
|
39
39
|
}) {
|
|
40
40
|
if (!tiers) {
|
|
@@ -43,10 +43,13 @@ export function VolumeBulkSelect({
|
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
45
|
<TierSelect
|
|
46
|
-
value={
|
|
46
|
+
value={value.toString()}
|
|
47
47
|
fullWidth
|
|
48
48
|
onChange={(event) => {
|
|
49
|
-
|
|
49
|
+
const quantity = event?.target?.value ? Number(event?.target?.value) : null;
|
|
50
|
+
if (quantity) {
|
|
51
|
+
handleChange(quantity);
|
|
52
|
+
}
|
|
50
53
|
}}
|
|
51
54
|
id={componentId}
|
|
52
55
|
input={<TierInput />}
|
|
@@ -7,10 +7,9 @@ import { TiersSelectContainerProps } from './TiersSelectContainer';
|
|
|
7
7
|
export function VolumePerUnitInput({
|
|
8
8
|
width,
|
|
9
9
|
tierUnits,
|
|
10
|
-
|
|
11
|
-
handlePerUnitQuantityChange,
|
|
10
|
+
value,
|
|
12
11
|
handleChange,
|
|
13
|
-
}: Pick<TiersSelectContainerProps, 'width' | 'tierUnits' | '
|
|
12
|
+
}: Pick<TiersSelectContainerProps, 'width' | 'tierUnits' | 'value'> & {
|
|
14
13
|
handleChange: (quantity: number) => void;
|
|
15
14
|
}) {
|
|
16
15
|
return (
|
|
@@ -27,12 +26,11 @@ export function VolumePerUnitInput({
|
|
|
27
26
|
</InputAdornment>
|
|
28
27
|
),
|
|
29
28
|
}}
|
|
30
|
-
value={
|
|
29
|
+
value={value}
|
|
31
30
|
onChange={(event) => {
|
|
32
31
|
const quantity = event?.target?.value ? Number(event?.target?.value) : null;
|
|
33
32
|
if (quantity) {
|
|
34
33
|
handleChange(quantity);
|
|
35
|
-
handlePerUnitQuantityChange(quantity);
|
|
36
34
|
}
|
|
37
35
|
}}
|
|
38
36
|
/>
|
|
@@ -17,7 +17,7 @@ import { useStiggContext } from '../..';
|
|
|
17
17
|
import { hasPricePointsForPlans } from './utils/hasPricePoints';
|
|
18
18
|
import { getPlansToDisplay } from './utils/getPlansToDisplay';
|
|
19
19
|
import { getPlanPrice } from '../utils/getPlanPrice';
|
|
20
|
-
import {
|
|
20
|
+
import { getTiersPerUnitQuantities } from '../utils/priceTierUtils';
|
|
21
21
|
|
|
22
22
|
const PaywallPlansContainer = styled.div`
|
|
23
23
|
color: ${({ theme }) => theme.stigg.palette.text.primary};
|
|
@@ -123,7 +123,7 @@ export const Paywall = ({
|
|
|
123
123
|
return (
|
|
124
124
|
!isCustomerInCustomPlan &&
|
|
125
125
|
plansToShow.some((plan) => {
|
|
126
|
-
const tiers =
|
|
126
|
+
const tiers = getTiersPerUnitQuantities(plan, selectedBillingPeriod, currentSubscription);
|
|
127
127
|
return Object.values(tiers).length > 0;
|
|
128
128
|
})
|
|
129
129
|
);
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {
|
|
3
|
-
BillableFeature,
|
|
4
|
-
BillingPeriod,
|
|
5
|
-
Customer,
|
|
6
|
-
PriceTierFragment,
|
|
7
|
-
PricingType,
|
|
8
|
-
Subscription,
|
|
9
|
-
} from '@stigg/js-client-sdk';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { BillableFeature, BillingPeriod, Customer, PricingType, Subscription } from '@stigg/js-client-sdk';
|
|
10
3
|
import styled from '@emotion/styled/macro';
|
|
11
4
|
import classNames from 'classnames';
|
|
12
5
|
import Grid from '@mui/material/Grid';
|
|
@@ -18,7 +11,7 @@ import { flexLayoutMapper } from '../../theme/getResolvedTheme';
|
|
|
18
11
|
import { Typography } from '../common/Typography';
|
|
19
12
|
import MiniSchedule from '../../assets/mini-schedule.svg';
|
|
20
13
|
import { PlanPrice } from './PlanPrice';
|
|
21
|
-
import {
|
|
14
|
+
import { getTiersPerUnitQuantities } from '../utils/priceTierUtils';
|
|
22
15
|
|
|
23
16
|
const PlanOfferingButtonHeight = '66px';
|
|
24
17
|
|
|
@@ -167,28 +160,17 @@ export function PlanOffering({
|
|
|
167
160
|
);
|
|
168
161
|
}
|
|
169
162
|
|
|
170
|
-
const [perUnitQuantityByFeature, setPerUnitQuantityByFeature] = useState<Record<string, number>>(
|
|
171
|
-
|
|
172
|
-
getSelectedTier(plan, billingPeriod, currentSubscription, {}, selectDefaultTierIndex),
|
|
163
|
+
const [perUnitQuantityByFeature, setPerUnitQuantityByFeature] = useState<Record<string, number>>(
|
|
164
|
+
getTiersPerUnitQuantities(plan, billingPeriod, currentSubscription, selectDefaultTierIndex),
|
|
173
165
|
);
|
|
174
166
|
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
setSelectedTierByFeature(getSelectedTier(plan, billingPeriod, currentSubscription, selectedTierByFeature));
|
|
177
|
-
setPerUnitQuantityByFeature(getSelectedTierQuantityBeFeature(plan, billingPeriod, currentSubscription));
|
|
178
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
179
|
-
}, [billingPeriod, currentSubscription, plan]);
|
|
180
|
-
|
|
181
167
|
const onPlanButtonClick = (intentionType: SubscribeIntentionType) => {
|
|
182
|
-
const tierBillableFeatures: BillableFeature[] = Object.keys(selectedTierByFeature).map((featureId) => ({
|
|
183
|
-
featureId,
|
|
184
|
-
quantity: selectedTierByFeature[featureId].upTo || 0,
|
|
185
|
-
}));
|
|
186
168
|
const perUnitBillableFeatures: BillableFeature[] = Object.keys(perUnitQuantityByFeature).map((featureId) => ({
|
|
187
169
|
featureId,
|
|
188
170
|
quantity: perUnitQuantityByFeature[featureId],
|
|
189
171
|
}));
|
|
190
172
|
|
|
191
|
-
return onPlanSelected(intentionType,
|
|
173
|
+
return onPlanSelected(intentionType, perUnitBillableFeatures);
|
|
192
174
|
};
|
|
193
175
|
|
|
194
176
|
return (
|
|
@@ -216,8 +198,6 @@ export function PlanOffering({
|
|
|
216
198
|
withUnitPriceRow={withUnitPriceRow}
|
|
217
199
|
withStartingAtRow={withStartingAtRow}
|
|
218
200
|
withTiersRow={withTiersRow}
|
|
219
|
-
selectedTierByFeature={selectedTierByFeature}
|
|
220
|
-
setSelectedTierByFeature={setSelectedTierByFeature}
|
|
221
201
|
plan={plan}
|
|
222
202
|
billingPeriod={billingPeriod}
|
|
223
203
|
paywallLocale={paywallLocale}
|
|
@@ -239,7 +219,6 @@ export function PlanOffering({
|
|
|
239
219
|
onPlanSelected={onPlanButtonClick}
|
|
240
220
|
paywallLocale={paywallLocale}
|
|
241
221
|
withTrialLeftRow={withTrialLeftRow}
|
|
242
|
-
selectedTierByFeature={selectedTierByFeature}
|
|
243
222
|
perUnitQuantityByFeature={perUnitQuantityByFeature}
|
|
244
223
|
/>
|
|
245
224
|
) : (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { BillingPeriod, Customer,
|
|
2
|
+
import { BillingPeriod, Customer, PricingType, Subscription } from '@stigg/js-client-sdk';
|
|
3
3
|
import { isFunction } from 'lodash';
|
|
4
4
|
import ClipLoader from 'react-spinners/ClipLoader';
|
|
5
5
|
import styled from '@emotion/styled/macro';
|
|
@@ -82,7 +82,6 @@ type PlanOfferingButtonProps = {
|
|
|
82
82
|
paywallLocale: PaywallLocalization;
|
|
83
83
|
onPlanSelected: (intentionType: SubscribeIntentionType) => void | Promise<void>;
|
|
84
84
|
withTrialLeftRow: boolean;
|
|
85
|
-
selectedTierByFeature: Record<string, PriceTierFragment>;
|
|
86
85
|
perUnitQuantityByFeature: Record<string, number>;
|
|
87
86
|
};
|
|
88
87
|
|
|
@@ -96,7 +95,6 @@ export function PlanOfferingButton({
|
|
|
96
95
|
paywallLocale,
|
|
97
96
|
withTrialLeftRow,
|
|
98
97
|
currentSubscription,
|
|
99
|
-
selectedTierByFeature,
|
|
100
98
|
perUnitQuantityByFeature,
|
|
101
99
|
}: PlanOfferingButtonProps) {
|
|
102
100
|
const theme = useTheme();
|
|
@@ -144,11 +142,7 @@ export function PlanOfferingButton({
|
|
|
144
142
|
isSameBillingPeriod ||
|
|
145
143
|
(plan.pricingType && [PricingType.Free, PricingType.Custom].includes(plan.pricingType))
|
|
146
144
|
) {
|
|
147
|
-
const planComparison = compareSelectedTierToCurrentTier(
|
|
148
|
-
selectedTierByFeature,
|
|
149
|
-
perUnitQuantityByFeature,
|
|
150
|
-
currentSubscription,
|
|
151
|
-
);
|
|
145
|
+
const planComparison = compareSelectedTierToCurrentTier(perUnitQuantityByFeature, currentSubscription);
|
|
152
146
|
switch (planComparison) {
|
|
153
147
|
case PriceTierComparison.Lower:
|
|
154
148
|
buttonProps.intentionType = SubscribeIntentionType.CHANGE_UNIT_QUANTITY;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from '@emotion/styled/macro';
|
|
3
|
-
import { BillingPeriod
|
|
3
|
+
import { BillingPeriod } from '@stigg/js-client-sdk';
|
|
4
4
|
import { PaywallPlan } from './types';
|
|
5
5
|
import { PaywallLocalization } from './paywallTextOverrides';
|
|
6
6
|
import { getPlanPrice } from '../utils/getPlanPrice';
|
|
@@ -57,8 +57,6 @@ export const PlanPrice = ({
|
|
|
57
57
|
withUnitPriceRow,
|
|
58
58
|
withStartingAtRow,
|
|
59
59
|
withTiersRow,
|
|
60
|
-
selectedTierByFeature,
|
|
61
|
-
setSelectedTierByFeature,
|
|
62
60
|
plan,
|
|
63
61
|
billingPeriod,
|
|
64
62
|
paywallLocale,
|
|
@@ -72,8 +70,6 @@ export const PlanPrice = ({
|
|
|
72
70
|
withUnitPriceRow: boolean;
|
|
73
71
|
withStartingAtRow: boolean;
|
|
74
72
|
withTiersRow: boolean;
|
|
75
|
-
selectedTierByFeature: Record<string, PriceTierFragment>;
|
|
76
|
-
setSelectedTierByFeature: React.Dispatch<React.SetStateAction<Record<string, PriceTierFragment>>>;
|
|
77
73
|
perUnitQuantityByFeature: Record<string, number>;
|
|
78
74
|
setPerUnitQuantityByFeature: React.Dispatch<React.SetStateAction<Record<string, number>>>;
|
|
79
75
|
plan: PaywallPlan;
|
|
@@ -89,7 +85,6 @@ export const PlanPrice = ({
|
|
|
89
85
|
paywallLocale,
|
|
90
86
|
locale,
|
|
91
87
|
hasMonthlyPrice,
|
|
92
|
-
selectedTierByFeature,
|
|
93
88
|
perUnitQuantityByFeature,
|
|
94
89
|
);
|
|
95
90
|
|
|
@@ -98,19 +93,7 @@ export const PlanPrice = ({
|
|
|
98
93
|
return planPrice.billingPeriod === billingPeriod && planPrice.isTieredPrice;
|
|
99
94
|
});
|
|
100
95
|
const featureId = tieredPrice ? tieredPrice.feature!.featureId : undefined;
|
|
101
|
-
const
|
|
102
|
-
const perUnitQuantity = featureId ? perUnitQuantityByFeature[featureId] : undefined;
|
|
103
|
-
|
|
104
|
-
const handleTierChange = (tier: PriceTierFragment) => {
|
|
105
|
-
if (!featureId) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
setSelectedTierByFeature((prevState) => ({
|
|
110
|
-
...prevState,
|
|
111
|
-
[featureId]: tier,
|
|
112
|
-
}));
|
|
113
|
-
};
|
|
96
|
+
const perUnitQuantity = perUnitQuantityByFeature[featureId || ''] ?? 1;
|
|
114
97
|
|
|
115
98
|
const handlePerUnitQuantityChange = (quantity: number) => {
|
|
116
99
|
if (!featureId) {
|
|
@@ -161,11 +144,9 @@ export const PlanPrice = ({
|
|
|
161
144
|
componentId={`${plan.id}_${featureId}_tier`}
|
|
162
145
|
tiers={tiers}
|
|
163
146
|
tierUnits={tierUnits}
|
|
164
|
-
selectedTier={selectedTier}
|
|
165
|
-
handleTierChange={handleTierChange}
|
|
166
147
|
tiersMode={tieredPrice?.tiersMode}
|
|
167
|
-
|
|
168
|
-
|
|
148
|
+
handleChange={handlePerUnitQuantityChange}
|
|
149
|
+
value={perUnitQuantity}
|
|
169
150
|
/>
|
|
170
151
|
) : null}
|
|
171
152
|
</>
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BillingModel,
|
|
3
|
-
BillingPeriod,
|
|
4
|
-
PaywallCalculatedPricePoint,
|
|
5
|
-
Price,
|
|
6
|
-
PriceTierFragment,
|
|
7
|
-
} from '@stigg/js-client-sdk';
|
|
1
|
+
import { BillingModel, BillingPeriod, PaywallCalculatedPricePoint, Price } from '@stigg/js-client-sdk';
|
|
8
2
|
import { currencyPriceFormatter } from './currencyUtils';
|
|
9
3
|
import { PlanPriceText } from './getPlanPrice';
|
|
10
4
|
import { calculateTierPrice, getPriceFeatureUnit } from './priceTierUtils';
|
|
@@ -16,7 +10,6 @@ type GetPaidPriceTextParams = {
|
|
|
16
10
|
selectedBillingPeriod: BillingPeriod;
|
|
17
11
|
locale: string;
|
|
18
12
|
shouldShowMonthlyPriceAmount: boolean;
|
|
19
|
-
selectedTierByFeature: Record<string, PriceTierFragment>;
|
|
20
13
|
paywallLocale: PaywallLocalization;
|
|
21
14
|
perUnitQuantityByFeature?: Record<string, number>;
|
|
22
15
|
};
|
|
@@ -27,7 +20,6 @@ export function getPaidPriceText({
|
|
|
27
20
|
selectedBillingPeriod,
|
|
28
21
|
locale,
|
|
29
22
|
shouldShowMonthlyPriceAmount,
|
|
30
|
-
selectedTierByFeature,
|
|
31
23
|
paywallLocale,
|
|
32
24
|
perUnitQuantityByFeature,
|
|
33
25
|
}: GetPaidPriceTextParams): PlanPriceText {
|
|
@@ -46,22 +38,12 @@ export function getPaidPriceText({
|
|
|
46
38
|
let unit = pricePeriod;
|
|
47
39
|
|
|
48
40
|
for (const price of planPrices) {
|
|
49
|
-
if (price.isTieredPrice) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
if (price.isTieredPrice && price.tiers) {
|
|
42
|
+
const quantity = perUnitQuantityByFeature?.[price.feature!.featureId] || 1;
|
|
43
|
+
tiers = price.tiers;
|
|
44
|
+
tierUnits = getPriceFeatureUnit(price);
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
tierUnits = getPriceFeatureUnit(price);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
priceNumber += calculateTierPrice(
|
|
59
|
-
price,
|
|
60
|
-
currentTier,
|
|
61
|
-
selectedBillingPeriod,
|
|
62
|
-
shouldShowMonthlyPriceAmount,
|
|
63
|
-
perUnitQuantityByFeature?.[price.feature!.featureId] || 1,
|
|
64
|
-
);
|
|
46
|
+
priceNumber += calculateTierPrice(price, selectedBillingPeriod, shouldShowMonthlyPriceAmount, quantity);
|
|
65
47
|
}
|
|
66
48
|
}
|
|
67
49
|
|
|
@@ -15,7 +15,6 @@ export function getPlanPrice(
|
|
|
15
15
|
paywallLocale: PaywallLocalization,
|
|
16
16
|
locale: string,
|
|
17
17
|
shouldShowMonthlyPriceAmount: boolean,
|
|
18
|
-
selectedTierByFeature?: Record<string, PriceTierFragment>,
|
|
19
18
|
perUnitQuantityByFeature?: Record<string, number>,
|
|
20
19
|
): PlanPriceText {
|
|
21
20
|
switch (plan.pricingType) {
|
|
@@ -48,7 +47,6 @@ export function getPlanPrice(
|
|
|
48
47
|
planPrices,
|
|
49
48
|
paywallCalculatedPrice,
|
|
50
49
|
selectedBillingPeriod: billingPeriod,
|
|
51
|
-
selectedTierByFeature: selectedTierByFeature || {},
|
|
52
50
|
perUnitQuantityByFeature: perUnitQuantityByFeature || {},
|
|
53
51
|
};
|
|
54
52
|
|
|
@@ -11,9 +11,7 @@ export function getPriceFeatureUnit(price: Price) {
|
|
|
11
11
|
return (price.feature.unitQuantity !== 1 ? price.feature.unitsPlural : price.feature.units) || '';
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function getTierByQuantity(tiers: PriceTierFragment[], quantity: number) {
|
|
15
|
-
if (!tiers) return undefined;
|
|
16
|
-
|
|
14
|
+
export function getTierByQuantity(tiers: PriceTierFragment[], quantity: number): PriceTierFragment {
|
|
17
15
|
const ascendingTiers = [...tiers];
|
|
18
16
|
// Sort tiers by upTo value, ascending, if upTo is not set,
|
|
19
17
|
// put it at the end as it represent the last infinity tier
|
|
@@ -54,64 +52,34 @@ export function calculateTierPriceVolume(
|
|
|
54
52
|
|
|
55
53
|
export function calculateTierPrice(
|
|
56
54
|
price: Price,
|
|
57
|
-
currentTier: PriceTierFragment,
|
|
58
55
|
selectedBillingPeriod: BillingPeriod,
|
|
59
56
|
shouldShowMonthlyPriceAmount: boolean,
|
|
60
|
-
|
|
57
|
+
unitQuantity: number,
|
|
61
58
|
): number {
|
|
59
|
+
if (!price.tiers) {
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
62
63
|
switch (price.tiersMode) {
|
|
63
64
|
case TiersMode.Volume: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
perUnitQuantity,
|
|
67
|
-
selectedBillingPeriod,
|
|
68
|
-
shouldShowMonthlyPriceAmount,
|
|
69
|
-
);
|
|
65
|
+
const currentTier = getTierByQuantity(price.tiers, unitQuantity);
|
|
66
|
+
return calculateTierPriceVolume(currentTier, unitQuantity, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
|
|
70
67
|
}
|
|
71
68
|
default:
|
|
72
69
|
return 0;
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
72
|
|
|
76
|
-
export function getSelectedTierQuantityBeFeature(
|
|
77
|
-
plan: PaywallPlan,
|
|
78
|
-
billingPeriod: BillingPeriod,
|
|
79
|
-
currentSubscription: Subscription | null,
|
|
80
|
-
) {
|
|
81
|
-
const result: Record<string, number> = {};
|
|
82
|
-
const planTierPrices = plan.pricePoints.filter(
|
|
83
|
-
(price) => price.billingPeriod === billingPeriod && price.isTieredPrice,
|
|
84
|
-
);
|
|
85
|
-
if (planTierPrices.length === 1) {
|
|
86
|
-
const [price] = planTierPrices;
|
|
87
|
-
const featureId = price?.feature!.featureId;
|
|
88
|
-
if (currentSubscription && currentSubscription.plan.id === plan.id) {
|
|
89
|
-
const tieredPrice = currentSubscription?.prices.find(
|
|
90
|
-
(subscriptionPrice) =>
|
|
91
|
-
subscriptionPrice.pricingModel === BillingModel.PerUnit &&
|
|
92
|
-
subscriptionPrice.tiersMode &&
|
|
93
|
-
subscriptionPrice.feature?.featureId === featureId,
|
|
94
|
-
);
|
|
95
|
-
if (tieredPrice) {
|
|
96
|
-
result[featureId] = tieredPrice.feature?.unitQuantity || 1;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return result;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
73
|
export function hasTierWithUnitPrice(tiers: PriceTierFragment[] | null | undefined) {
|
|
105
74
|
return tiers?.some(({ unitPrice, upTo }) => unitPrice && !isNil(upTo));
|
|
106
75
|
}
|
|
107
76
|
|
|
108
|
-
export function
|
|
77
|
+
export function getTiersPerUnitQuantities(
|
|
109
78
|
plan: PaywallPlan,
|
|
110
79
|
billingPeriod: BillingPeriod,
|
|
111
80
|
currentSubscription: Subscription | null,
|
|
112
|
-
selectedTierByFeature: Record<string, PriceTierFragment>,
|
|
113
81
|
selectDefaultTierIndex?: SelectDefaultTierIndexFn,
|
|
114
|
-
): Record<string,
|
|
82
|
+
): Record<string, number> {
|
|
115
83
|
const planTierPrices = plan.pricePoints.filter(
|
|
116
84
|
(price) => price.billingPeriod === billingPeriod && price.isTieredPrice,
|
|
117
85
|
);
|
|
@@ -120,11 +88,10 @@ export function getSelectedTier(
|
|
|
120
88
|
const [price] = planTierPrices;
|
|
121
89
|
const { featureId } = price.feature!;
|
|
122
90
|
const selectedDefaultTierIndex = selectDefaultTierIndex ? selectDefaultTierIndex({ plan }) : 0;
|
|
123
|
-
|
|
91
|
+
const currentTier = price.tiers![selectedDefaultTierIndex];
|
|
92
|
+
let quantity = hasTierWithUnitPrice(price.tiers) ? 1 : currentTier.upTo || 1;
|
|
124
93
|
|
|
125
|
-
if (
|
|
126
|
-
currentTier = price.tiers?.find((tier) => tier.upTo === selectedTierByFeature[featureId].upTo) || currentTier;
|
|
127
|
-
} else if (currentSubscription && currentSubscription.plan.id === plan.id) {
|
|
94
|
+
if (currentSubscription && currentSubscription.plan.id === plan.id) {
|
|
128
95
|
const tieredPrice = currentSubscription.prices.find(
|
|
129
96
|
(subscriptionPrice) =>
|
|
130
97
|
subscriptionPrice.pricingModel === BillingModel.PerUnit &&
|
|
@@ -133,12 +100,12 @@ export function getSelectedTier(
|
|
|
133
100
|
);
|
|
134
101
|
|
|
135
102
|
if (tieredPrice) {
|
|
136
|
-
|
|
103
|
+
quantity = tieredPrice.feature!.unitQuantity || 1;
|
|
137
104
|
}
|
|
138
105
|
}
|
|
139
106
|
|
|
140
|
-
const result: Record<string,
|
|
141
|
-
result[featureId] =
|
|
107
|
+
const result: Record<string, number> = {};
|
|
108
|
+
result[featureId] = quantity;
|
|
142
109
|
|
|
143
110
|
return result;
|
|
144
111
|
}
|
|
@@ -153,11 +120,10 @@ export enum PriceTierComparison {
|
|
|
153
120
|
}
|
|
154
121
|
|
|
155
122
|
export function compareSelectedTierToCurrentTier(
|
|
156
|
-
selectedTierByFeature: Record<string, PriceTierFragment>,
|
|
157
123
|
perUnitQuantityByFeature: Record<string, number>,
|
|
158
124
|
currentSubscription: Subscription | null,
|
|
159
125
|
): PriceTierComparison {
|
|
160
|
-
if (!currentSubscription
|
|
126
|
+
if (!currentSubscription) {
|
|
161
127
|
return PriceTierComparison.Equal;
|
|
162
128
|
}
|
|
163
129
|
|
|
@@ -168,29 +134,19 @@ export function compareSelectedTierToCurrentTier(
|
|
|
168
134
|
return PriceTierComparison.Equal;
|
|
169
135
|
}
|
|
170
136
|
|
|
171
|
-
const { featureId, unitQuantity } = currentTierPrice.feature!;
|
|
172
|
-
const { tiers } = currentTierPrice;
|
|
173
|
-
|
|
174
|
-
if (!unitQuantity) {
|
|
175
|
-
return PriceTierComparison.Equal;
|
|
176
|
-
}
|
|
137
|
+
const { featureId, unitQuantity: oldQuantity } = currentTierPrice.feature!;
|
|
177
138
|
|
|
178
|
-
|
|
179
|
-
const selectedQuantity = perUnitQuantityByFeature[featureId];
|
|
180
|
-
if (!selectedTier) {
|
|
139
|
+
if (isNil(oldQuantity)) {
|
|
181
140
|
return PriceTierComparison.Equal;
|
|
182
141
|
}
|
|
183
142
|
|
|
184
|
-
const
|
|
143
|
+
const newQuantity = perUnitQuantityByFeature[featureId];
|
|
185
144
|
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return PriceTierComparison.Higher;
|
|
192
|
-
}
|
|
145
|
+
if (newQuantity < oldQuantity) {
|
|
146
|
+
return PriceTierComparison.Lower;
|
|
147
|
+
}
|
|
148
|
+
if (newQuantity > oldQuantity) {
|
|
149
|
+
return PriceTierComparison.Higher;
|
|
193
150
|
}
|
|
194
|
-
|
|
195
151
|
return PriceTierComparison.Equal;
|
|
196
152
|
}
|