@stigg/react-sdk 4.1.1 → 4.2.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/paywall/PlanOffering.d.ts +6 -4
- package/dist/components/paywall/PlanOfferingButton.d.ts +5 -2
- package/dist/components/paywall/PlanPrice.d.ts +18 -0
- package/dist/components/paywall/TiersLayout.d.ts +10 -0
- package/dist/components/paywall/paywallTextOverrides.d.ts +12 -1
- package/dist/components/paywall/planPriceTier.d.ts +10 -0
- package/dist/components/paywall/types.d.ts +3 -2
- package/dist/components/utils/getPaidPriceText.d.ts +3 -2
- package/dist/components/utils/getPlanPrice.d.ts +4 -2
- package/dist/react-sdk.cjs.development.js +590 -288
- 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 +607 -301
- package/dist/react-sdk.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/paywall/Paywall.tsx +17 -3
- package/src/components/paywall/PlanOffering.tsx +38 -105
- package/src/components/paywall/PlanOfferingButton.tsx +35 -11
- package/src/components/paywall/PlanPrice.tsx +152 -0
- package/src/components/paywall/TiersLayout.tsx +74 -0
- package/src/components/paywall/paywallTextOverrides.ts +9 -1
- package/src/components/paywall/planPriceTier.ts +105 -0
- package/src/components/paywall/types.ts +3 -0
- package/src/components/utils/getPaidPriceText.ts +42 -18
- package/src/components/utils/getPlanPrice.ts +10 -2
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { PaywallPlan } from './types';
|
|
2
|
+
|
|
3
|
+
import { BillingModel, TiersMode, BillingPeriod, Price, PriceTierFragment, Subscription } from '@stigg/js-client-sdk';
|
|
4
|
+
|
|
5
|
+
export function calculateTierPrice(
|
|
6
|
+
price: Price,
|
|
7
|
+
currentTier: PriceTierFragment,
|
|
8
|
+
selectedBillingPeriod: BillingPeriod,
|
|
9
|
+
shouldShowMonthlyPriceAmount: boolean,
|
|
10
|
+
): number {
|
|
11
|
+
switch (price.tiersMode) {
|
|
12
|
+
case TiersMode.Volume:
|
|
13
|
+
const unitPrice =
|
|
14
|
+
selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount
|
|
15
|
+
? currentTier.unitPrice.amount / 12
|
|
16
|
+
: currentTier.unitPrice.amount;
|
|
17
|
+
|
|
18
|
+
return unitPrice * currentTier.upTo;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getSelectedTier(
|
|
25
|
+
plan: PaywallPlan,
|
|
26
|
+
billingPeriod: BillingPeriod,
|
|
27
|
+
currentSubscription: Subscription | null,
|
|
28
|
+
selectedTierByFeature: Record<string, PriceTierFragment>,
|
|
29
|
+
): Record<string, PriceTierFragment> {
|
|
30
|
+
const planTierPrices = plan.pricePoints.filter(price => price.billingPeriod === billingPeriod && price.isTieredPrice);
|
|
31
|
+
|
|
32
|
+
if (planTierPrices.length == 1) {
|
|
33
|
+
const [price] = planTierPrices;
|
|
34
|
+
const featureId = price.feature!.featureId;
|
|
35
|
+
|
|
36
|
+
let currentTier = price.tiers![0];
|
|
37
|
+
|
|
38
|
+
if (selectedTierByFeature[featureId]) {
|
|
39
|
+
currentTier = price.tiers?.find(tier => tier.upTo === selectedTierByFeature[featureId].upTo) || currentTier;
|
|
40
|
+
} else if (currentSubscription) {
|
|
41
|
+
const tieredPrice = currentSubscription.prices.find(
|
|
42
|
+
subscriptionPrice =>
|
|
43
|
+
subscriptionPrice.pricingModel == BillingModel.PerUnit &&
|
|
44
|
+
subscriptionPrice.billingPeriod == billingPeriod &&
|
|
45
|
+
subscriptionPrice.tiersMode &&
|
|
46
|
+
subscriptionPrice.feature?.featureId === featureId,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (tieredPrice) {
|
|
50
|
+
const customerTier = tieredPrice.tiers!.find(tier => tier.upTo === tieredPrice.feature!.unitQuantity);
|
|
51
|
+
currentTier = customerTier || tieredPrice.tiers![0];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result: Record<string, PriceTierFragment> = {};
|
|
56
|
+
result[featureId] = currentTier;
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export enum PriceTierComparison {
|
|
65
|
+
Lower = -1,
|
|
66
|
+
Equal = 0,
|
|
67
|
+
Higher = 1,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function compareSelectedTierToCurrentTier(
|
|
71
|
+
selectedTierByFeature: Record<string, PriceTierFragment>,
|
|
72
|
+
currentSubscription: Subscription | null,
|
|
73
|
+
): PriceTierComparison {
|
|
74
|
+
if (!currentSubscription || !selectedTierByFeature) {
|
|
75
|
+
return PriceTierComparison.Equal;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const currentTierPrice = currentSubscription.prices.find(
|
|
79
|
+
price => price.pricingModel == BillingModel.PerUnit && price.tiersMode,
|
|
80
|
+
);
|
|
81
|
+
if (!currentTierPrice) {
|
|
82
|
+
return PriceTierComparison.Equal;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const { featureId, unitQuantity } = currentTierPrice.feature!;
|
|
86
|
+
|
|
87
|
+
if (!unitQuantity) {
|
|
88
|
+
return PriceTierComparison.Equal;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const selectedTier = selectedTierByFeature[featureId];
|
|
92
|
+
if (!selectedTier) {
|
|
93
|
+
return PriceTierComparison.Equal;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (selectedTier.upTo < unitQuantity!) {
|
|
97
|
+
return PriceTierComparison.Lower;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (selectedTier.upTo > unitQuantity!) {
|
|
101
|
+
return PriceTierComparison.Higher;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return PriceTierComparison.Equal;
|
|
105
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CustomerPortalSubscriptionScheduledUpdateDataFragment,
|
|
7
7
|
PaywallCurrency,
|
|
8
8
|
PaywallCalculatedPricePoint,
|
|
9
|
+
BillableFeature,
|
|
9
10
|
} from '@stigg/js-client-sdk';
|
|
10
11
|
import { CustomizedTheme } from '../../theme/Theme';
|
|
11
12
|
|
|
@@ -50,10 +51,12 @@ export type OnPlanSelectedCallbackFn = ({
|
|
|
50
51
|
subscription,
|
|
51
52
|
intentionType,
|
|
52
53
|
selectedBillingPeriod,
|
|
54
|
+
billableFeatures,
|
|
53
55
|
}: {
|
|
54
56
|
plan: Plan;
|
|
55
57
|
customer: Customer | null;
|
|
56
58
|
subscription: Subscription | null;
|
|
57
59
|
intentionType: SubscribeIntentionType;
|
|
58
60
|
selectedBillingPeriod: BillingPeriod;
|
|
61
|
+
billableFeatures?: BillableFeature[];
|
|
59
62
|
}) => void | Promise<void>;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BillingModel,
|
|
3
|
+
BillingPeriod,
|
|
4
|
+
PaywallCalculatedPricePoint,
|
|
5
|
+
Price,
|
|
6
|
+
PriceTierFragment,
|
|
7
|
+
} from '@stigg/js-client-sdk';
|
|
2
8
|
import { currencyPriceFormatter } from './currencyUtils';
|
|
3
9
|
import { PlanPriceText } from './getPlanPrice';
|
|
10
|
+
import { calculateTierPrice } from '../paywall/planPriceTier';
|
|
4
11
|
|
|
5
12
|
type GetPaidPriceTextParams = {
|
|
6
13
|
planPrices: Price[];
|
|
@@ -8,6 +15,7 @@ type GetPaidPriceTextParams = {
|
|
|
8
15
|
selectedBillingPeriod: BillingPeriod;
|
|
9
16
|
locale: string;
|
|
10
17
|
shouldShowMonthlyPriceAmount: boolean;
|
|
18
|
+
selectedTierByFeature: Record<string, PriceTierFragment>;
|
|
11
19
|
};
|
|
12
20
|
|
|
13
21
|
export function getPaidPriceText({
|
|
@@ -16,32 +24,48 @@ export function getPaidPriceText({
|
|
|
16
24
|
selectedBillingPeriod,
|
|
17
25
|
locale,
|
|
18
26
|
shouldShowMonthlyPriceAmount,
|
|
27
|
+
selectedTierByFeature,
|
|
19
28
|
}: GetPaidPriceTextParams): PlanPriceText {
|
|
20
29
|
const { amount, currency } = paywallCalculatedPrice || planPrices[0];
|
|
30
|
+
const priceAmount = amount || 0;
|
|
31
|
+
|
|
21
32
|
const isSinglePrice = planPrices.length === 1;
|
|
22
|
-
|
|
23
|
-
selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount ?
|
|
24
|
-
|
|
33
|
+
let priceNumber =
|
|
34
|
+
selectedBillingPeriod === BillingPeriod.Annually && shouldShowMonthlyPriceAmount ? priceAmount / 12 : priceAmount;
|
|
35
|
+
|
|
36
|
+
let tiers;
|
|
37
|
+
let tierUnits;
|
|
38
|
+
let unit = shouldShowMonthlyPriceAmount ? '/ month' : '/ year';
|
|
39
|
+
|
|
40
|
+
for (const price of planPrices) {
|
|
41
|
+
if (price.isTieredPrice) {
|
|
42
|
+
let currentTier = price.tiers![0];
|
|
43
|
+
if (selectedTierByFeature[price.feature!.featureId]) {
|
|
44
|
+
currentTier = selectedTierByFeature[price.feature!.featureId] || currentTier;
|
|
45
|
+
|
|
46
|
+
tiers = price.tiers;
|
|
47
|
+
tierUnits = price.feature!.unitsPlural || '';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
priceNumber += calculateTierPrice(price, currentTier, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
25
53
|
|
|
26
54
|
if (isSinglePrice) {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
unit: shouldShowMonthlyPriceAmount ? `per ${featureUnit} / month` : `per ${featureUnit} / year`,
|
|
33
|
-
};
|
|
55
|
+
const price = planPrices[0];
|
|
56
|
+
const featureUnit = price.feature?.units || '';
|
|
57
|
+
|
|
58
|
+
if (price.pricingModel === BillingModel.PerUnit && !price.isTieredPrice) {
|
|
59
|
+
unit = shouldShowMonthlyPriceAmount ? `per ${featureUnit} / month` : `per ${featureUnit} / year`;
|
|
34
60
|
} else if (price.pricingModel === BillingModel.UsageBased) {
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
price: priceString,
|
|
38
|
-
unit: `per ${featureUnit}`,
|
|
39
|
-
};
|
|
61
|
+
unit = `per ${featureUnit}`;
|
|
40
62
|
}
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
return {
|
|
44
|
-
price:
|
|
45
|
-
unit:
|
|
66
|
+
price: currencyPriceFormatter({ amount: priceNumber, currency: currency, locale }),
|
|
67
|
+
unit: unit,
|
|
68
|
+
tiers: tiers,
|
|
69
|
+
tierUnits: tierUnits,
|
|
46
70
|
};
|
|
47
71
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BillingPeriod, PricingType } from '@stigg/js-client-sdk';
|
|
1
|
+
import { BillingPeriod, PriceTierFragment, PricingType } from '@stigg/js-client-sdk';
|
|
2
2
|
import { PaywallPlan } from '../paywall';
|
|
3
3
|
import { PaywallLocalization } from '../paywall';
|
|
4
4
|
import { getPaidPriceText } from './getPaidPriceText';
|
|
@@ -6,6 +6,8 @@ import { getPaidPriceText } from './getPaidPriceText';
|
|
|
6
6
|
export type PlanPriceText = {
|
|
7
7
|
price: string;
|
|
8
8
|
unit?: string;
|
|
9
|
+
tiers?: PriceTierFragment[] | null | undefined;
|
|
10
|
+
tierUnits?: string;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export function getPlanPrice(
|
|
@@ -14,6 +16,7 @@ export function getPlanPrice(
|
|
|
14
16
|
paywallLocale: PaywallLocalization,
|
|
15
17
|
locale: string,
|
|
16
18
|
shouldShowMonthlyPriceAmount: boolean,
|
|
19
|
+
selectedTierByFeature?: Record<string, PriceTierFragment>,
|
|
17
20
|
): PlanPriceText {
|
|
18
21
|
switch (plan.pricingType) {
|
|
19
22
|
case PricingType.Free:
|
|
@@ -38,7 +41,12 @@ export function getPlanPrice(
|
|
|
38
41
|
};
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
const paidParams = {
|
|
44
|
+
const paidParams = {
|
|
45
|
+
planPrices,
|
|
46
|
+
paywallCalculatedPrice,
|
|
47
|
+
selectedBillingPeriod: billingPeriod,
|
|
48
|
+
selectedTierByFeature: selectedTierByFeature || {},
|
|
49
|
+
};
|
|
42
50
|
|
|
43
51
|
return paywallLocale.price.paid
|
|
44
52
|
? paywallLocale.price.paid({ ...paidParams, plan })
|