@stigg/react-sdk 5.28.3 → 5.29.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/checkout/CheckoutProvider.d.ts +1 -0
- package/dist/components/checkout/hooks/useLoadCheckout.d.ts +1 -0
- package/dist/components/checkout/summary/CheckoutSummary.d.ts +2 -1
- package/dist/components/checkout/summary/CheckoutSummarySkeleton.d.ts +3 -1
- package/dist/components/paywall/Paywall.d.ts +3 -2
- package/dist/components/paywall/PaywallContainer.d.ts +3 -2
- package/dist/components/paywall/PlanOffering.d.ts +3 -2
- package/dist/components/paywall/PlanOfferingButton.d.ts +3 -2
- package/dist/components/paywall/hooks/useLoadPaywallData.d.ts +3 -2
- package/dist/components/paywall/types.d.ts +8 -0
- package/dist/components/paywall/utils/mapPaywallData.d.ts +3 -2
- package/dist/components/utils/priceTierUtils.d.ts +14 -3
- package/dist/react-sdk.cjs.development.js +130 -49
- 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 +130 -49
- package/dist/react-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/checkout/CheckoutContainer.tsx +3 -2
- package/src/components/checkout/CheckoutProvider.tsx +8 -1
- package/src/components/checkout/hooks/useLoadCheckout.ts +1 -0
- package/src/components/checkout/summary/CheckoutSummary.tsx +3 -2
- package/src/components/checkout/summary/CheckoutSummarySkeleton.tsx +2 -2
- package/src/components/paywall/Paywall.tsx +11 -2
- package/src/components/paywall/PaywallContainer.tsx +11 -1
- package/src/components/paywall/PlanOffering.tsx +11 -2
- package/src/components/paywall/PlanOfferingButton.tsx +9 -2
- package/src/components/paywall/hooks/useLoadPaywallData.ts +4 -2
- package/src/components/paywall/types.ts +12 -0
- package/src/components/paywall/utils/mapPaywallData.ts +13 -3
- package/src/components/utils/priceTierUtils.ts +54 -13
package/package.json
CHANGED
|
@@ -83,7 +83,7 @@ export function CheckoutContainer({
|
|
|
83
83
|
onMockCheckoutPreview,
|
|
84
84
|
}: CheckoutContainerProps) {
|
|
85
85
|
const { stripePromise, setupIntentClientSecret } = useStripeIntegration();
|
|
86
|
-
const [{ stiggTheme, widgetState, theme }] = useCheckoutContext();
|
|
86
|
+
const [{ stiggTheme, widgetState, theme, isWidgetWatermarkEnabled }] = useCheckoutContext();
|
|
87
87
|
const { currentStep } = useProgressBarModel();
|
|
88
88
|
|
|
89
89
|
const { isLoadingCheckoutData } = widgetState;
|
|
@@ -151,7 +151,7 @@ export function CheckoutContainer({
|
|
|
151
151
|
<CheckoutContent>
|
|
152
152
|
<CheckoutPanel>{isLoadingCheckoutData ? <ContentLoadingSkeleton /> : checkoutContent}</CheckoutPanel>
|
|
153
153
|
{isLoadingCheckoutData ? (
|
|
154
|
-
<CheckoutSummarySkeleton />
|
|
154
|
+
<CheckoutSummarySkeleton isWidgetWatermarkEnabled={isWidgetWatermarkEnabled} />
|
|
155
155
|
) : (
|
|
156
156
|
<CheckoutSummary
|
|
157
157
|
disablePromotionCode={disablePromotionCode}
|
|
@@ -160,6 +160,7 @@ export function CheckoutContainer({
|
|
|
160
160
|
onCheckoutCompleted={onCheckoutCompleted}
|
|
161
161
|
isFreeDowngrade={isFreeDowngrade}
|
|
162
162
|
onMockCheckoutPreview={onMockCheckoutPreview}
|
|
163
|
+
isWidgetWatermarkEnabled={isWidgetWatermarkEnabled}
|
|
163
164
|
/>
|
|
164
165
|
)}
|
|
165
166
|
</CheckoutContent>
|
|
@@ -35,6 +35,7 @@ export interface CheckoutContextState {
|
|
|
35
35
|
addonsStep: AddonsStepState;
|
|
36
36
|
paymentStep: PaymentStepState;
|
|
37
37
|
widgetState: WidgetState;
|
|
38
|
+
isWidgetWatermarkEnabled: boolean;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export const CheckoutContext = React.createContext<
|
|
@@ -101,7 +102,12 @@ export function CheckoutProvider({
|
|
|
101
102
|
}: {
|
|
102
103
|
children: React.ReactNode;
|
|
103
104
|
} & CheckoutProviderProps) {
|
|
104
|
-
const { checkout, isLoading } = useLoadCheckout({
|
|
105
|
+
const { checkout, isLoading, isWidgetWatermarkEnabled } = useLoadCheckout({
|
|
106
|
+
resourceId,
|
|
107
|
+
planId,
|
|
108
|
+
billingCountryCode,
|
|
109
|
+
onMockCheckoutState,
|
|
110
|
+
});
|
|
105
111
|
const configuration: CustomizedTheme = checkout?.configuration
|
|
106
112
|
? mapCheckoutConfiguration(checkout.configuration)
|
|
107
113
|
: { typography: mapTypography(defaultCheckoutTypography) };
|
|
@@ -147,6 +153,7 @@ export function CheckoutProvider({
|
|
|
147
153
|
paymentStep,
|
|
148
154
|
resourceId: checkout?.resource?.id,
|
|
149
155
|
widgetState: { readOnly: false, isValid: true, isLoadingCheckoutData: isLoading },
|
|
156
|
+
isWidgetWatermarkEnabled,
|
|
150
157
|
};
|
|
151
158
|
|
|
152
159
|
return initialState;
|
|
@@ -110,7 +110,8 @@ export const CheckoutSummary = ({
|
|
|
110
110
|
disableSuccessAnimation,
|
|
111
111
|
isFreeDowngrade,
|
|
112
112
|
onMockCheckoutPreview,
|
|
113
|
-
|
|
113
|
+
isWidgetWatermarkEnabled,
|
|
114
|
+
}: CheckoutContainerProps & { isFreeDowngrade: boolean; isWidgetWatermarkEnabled: boolean }) => {
|
|
114
115
|
const [isCheckoutCompletedSuccessfully, setIsCheckoutCompletedSuccessfully] = useState(false);
|
|
115
116
|
const { setErrorMessage } = usePaymentStepModel();
|
|
116
117
|
const progressBar = useProgressBarModel();
|
|
@@ -415,7 +416,7 @@ export const CheckoutSummary = ({
|
|
|
415
416
|
</SummaryCard>
|
|
416
417
|
<PoweredByStigg
|
|
417
418
|
source="checkout"
|
|
418
|
-
showWatermark
|
|
419
|
+
showWatermark={isWidgetWatermarkEnabled}
|
|
419
420
|
style={{ marginTop: 8, display: 'flex', justifyContent: 'center' }}
|
|
420
421
|
/>
|
|
421
422
|
{!disableSuccessAnimation && isCheckoutCompletedSuccessfully && (
|
|
@@ -3,7 +3,7 @@ import { PoweredByStigg } from '../../common/PoweredByStigg';
|
|
|
3
3
|
import { SummaryCard, SummaryContainer } from './CheckoutSummary';
|
|
4
4
|
import { FlexedSkeleton, Skeleton, SkeletonsContainer } from '../components/Skeletons.style';
|
|
5
5
|
|
|
6
|
-
export const CheckoutSummarySkeleton = () => {
|
|
6
|
+
export const CheckoutSummarySkeleton = ({ isWidgetWatermarkEnabled }: { isWidgetWatermarkEnabled: boolean }) => {
|
|
7
7
|
return (
|
|
8
8
|
<SummaryContainer>
|
|
9
9
|
<SummaryCard>
|
|
@@ -31,7 +31,7 @@ export const CheckoutSummarySkeleton = () => {
|
|
|
31
31
|
</SummaryCard>
|
|
32
32
|
<PoweredByStigg
|
|
33
33
|
source="checkout"
|
|
34
|
-
showWatermark
|
|
34
|
+
showWatermark={isWidgetWatermarkEnabled}
|
|
35
35
|
style={{ marginTop: 8, display: 'flex', justifyContent: 'center' }}
|
|
36
36
|
/>
|
|
37
37
|
</SummaryContainer>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
PaywallPlan,
|
|
11
11
|
SubscribeIntentionType,
|
|
12
12
|
SelectDefaultTierIndexFn,
|
|
13
|
+
CurrentSubscriptionOverride,
|
|
13
14
|
} from './types';
|
|
14
15
|
import { PaywallLocalization } from './paywallTextOverrides';
|
|
15
16
|
import { PoweredByStigg } from '../common/PoweredByStigg';
|
|
@@ -49,6 +50,7 @@ type PaywallProps = {
|
|
|
49
50
|
plans: PaywallPlan[];
|
|
50
51
|
customer: Customer | null;
|
|
51
52
|
currentSubscription: Subscription | null;
|
|
53
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
52
54
|
selectedBillingPeriod: BillingPeriod;
|
|
53
55
|
highlightedPlanId?: string;
|
|
54
56
|
onBillingPeriodChanged: (billingPeriod: BillingPeriod) => void;
|
|
@@ -75,6 +77,7 @@ export const Paywall = ({
|
|
|
75
77
|
locale,
|
|
76
78
|
shouldHidePlan,
|
|
77
79
|
selectDefaultTierIndex,
|
|
80
|
+
currentSubscriptionOverride,
|
|
78
81
|
}: PaywallProps) => {
|
|
79
82
|
const { stigg } = useStiggContext();
|
|
80
83
|
const discountRate = calculatePaywallDiscountRate(plans);
|
|
@@ -123,11 +126,16 @@ export const Paywall = ({
|
|
|
123
126
|
return (
|
|
124
127
|
!isCustomerInCustomPlan &&
|
|
125
128
|
plansToShow.some((plan) => {
|
|
126
|
-
const tiers = getTiersPerUnitQuantities(
|
|
129
|
+
const tiers = getTiersPerUnitQuantities({
|
|
130
|
+
plan,
|
|
131
|
+
billingPeriod: selectedBillingPeriod,
|
|
132
|
+
currentSubscription,
|
|
133
|
+
currentSubscriptionOverride,
|
|
134
|
+
});
|
|
127
135
|
return Object.values(tiers).length > 0;
|
|
128
136
|
})
|
|
129
137
|
);
|
|
130
|
-
}, [selectedBillingPeriod, currentSubscription, isCustomerInCustomPlan, plansToShow]);
|
|
138
|
+
}, [selectedBillingPeriod, currentSubscription, currentSubscriptionOverride, isCustomerInCustomPlan, plansToShow]);
|
|
131
139
|
|
|
132
140
|
const withTrialLeftRow = plansToShow.some((plan) => {
|
|
133
141
|
return plan.isCurrentCustomerPlan && plan.trialDaysLeft;
|
|
@@ -156,6 +164,7 @@ export const Paywall = ({
|
|
|
156
164
|
plan={plan}
|
|
157
165
|
withStartingAtRow={withStartingAtRow}
|
|
158
166
|
currentSubscription={currentSubscription}
|
|
167
|
+
currentSubscriptionOverride={currentSubscriptionOverride}
|
|
159
168
|
billingPeriod={selectedBillingPeriod}
|
|
160
169
|
isHighlighted={plan.id === highlightedPlanId}
|
|
161
170
|
isCustomerOnTrial={isCustomerOnTrial}
|
|
@@ -2,7 +2,12 @@ import React from 'react';
|
|
|
2
2
|
import { BillingPeriod } from '@stigg/js-client-sdk';
|
|
3
3
|
import { Paywall } from './Paywall';
|
|
4
4
|
import { useLoadPaywallData } from './hooks/useLoadPaywallData';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ShouldHidePlanFn,
|
|
7
|
+
OnPlanSelectedCallbackFn,
|
|
8
|
+
SelectDefaultTierIndexFn,
|
|
9
|
+
CurrentSubscriptionOverrideFn,
|
|
10
|
+
} from './types';
|
|
6
11
|
import { getResolvedPaywallLocalize, PaywallLocalization } from './paywallTextOverrides';
|
|
7
12
|
import { DeepPartial } from '../../types';
|
|
8
13
|
import { PaywallLoader } from './PaywallLoader';
|
|
@@ -25,6 +30,7 @@ export type PaywallContainerProps = {
|
|
|
25
30
|
billingCountryCode?: string;
|
|
26
31
|
shouldHidePlan?: ShouldHidePlanFn;
|
|
27
32
|
selectDefaultTierIndex?: SelectDefaultTierIndexFn;
|
|
33
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverrideFn;
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
export const PaywallContainer = ({
|
|
@@ -39,6 +45,7 @@ export const PaywallContainer = ({
|
|
|
39
45
|
billingCountryCode,
|
|
40
46
|
shouldHidePlan,
|
|
41
47
|
selectDefaultTierIndex,
|
|
48
|
+
currentSubscriptionOverride: currentSubscriptionOverrideFn,
|
|
42
49
|
}: PaywallContainerProps) => {
|
|
43
50
|
const hasCustomerPortalContext = useCheckContextExists(CustomerPortalContext);
|
|
44
51
|
let isCustomerPortalLoading = false;
|
|
@@ -52,6 +59,7 @@ export const PaywallContainer = ({
|
|
|
52
59
|
plans,
|
|
53
60
|
customer,
|
|
54
61
|
currentSubscription,
|
|
62
|
+
currentSubscriptionOverride,
|
|
55
63
|
isCustomerOnTrial,
|
|
56
64
|
isLoading,
|
|
57
65
|
selectedBillingPeriod,
|
|
@@ -65,6 +73,7 @@ export const PaywallContainer = ({
|
|
|
65
73
|
showOnlyEligiblePlans,
|
|
66
74
|
billingCountryCode,
|
|
67
75
|
preferredBillingPeriod,
|
|
76
|
+
currentSubscriptionOverrideFn,
|
|
68
77
|
});
|
|
69
78
|
const paywallLocale = getResolvedPaywallLocalize(textOverrides);
|
|
70
79
|
const handlePeriodChange = (billingPeriod: BillingPeriod) => {
|
|
@@ -82,6 +91,7 @@ export const PaywallContainer = ({
|
|
|
82
91
|
plans={plans}
|
|
83
92
|
customer={customer}
|
|
84
93
|
currentSubscription={currentSubscription}
|
|
94
|
+
currentSubscriptionOverride={currentSubscriptionOverride}
|
|
85
95
|
selectedBillingPeriod={selectedBillingPeriod}
|
|
86
96
|
onBillingPeriodChanged={handlePeriodChange}
|
|
87
97
|
availableBillingPeriods={availableBillingPeriods}
|
|
@@ -5,7 +5,7 @@ import classNames from 'classnames';
|
|
|
5
5
|
import Grid from '@mui/material/Grid';
|
|
6
6
|
import { PlanEntitlements } from './PlanEntitlements';
|
|
7
7
|
import { PlanOfferingButton } from './PlanOfferingButton';
|
|
8
|
-
import { PaywallPlan, SelectDefaultTierIndexFn, SubscribeIntentionType } from './types';
|
|
8
|
+
import { CurrentSubscriptionOverride, PaywallPlan, SelectDefaultTierIndexFn, SubscribeIntentionType } from './types';
|
|
9
9
|
import { PaywallLocalization } from './paywallTextOverrides';
|
|
10
10
|
import { flexLayoutMapper } from '../../theme/getResolvedTheme';
|
|
11
11
|
import { Typography } from '../common/Typography';
|
|
@@ -75,6 +75,7 @@ type PlanOfferingProps = {
|
|
|
75
75
|
plan: PaywallPlan;
|
|
76
76
|
billingPeriod: BillingPeriod;
|
|
77
77
|
currentSubscription: Subscription | null;
|
|
78
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
78
79
|
isHighlighted: boolean;
|
|
79
80
|
shouldShowDescriptionSection: boolean;
|
|
80
81
|
hasAnnuallyPrice: boolean;
|
|
@@ -128,6 +129,7 @@ export function PlanOffering({
|
|
|
128
129
|
billingPeriod,
|
|
129
130
|
isHighlighted,
|
|
130
131
|
currentSubscription,
|
|
132
|
+
currentSubscriptionOverride,
|
|
131
133
|
shouldShowDescriptionSection,
|
|
132
134
|
hasMonthlyPrice,
|
|
133
135
|
hasAnnuallyPrice,
|
|
@@ -161,7 +163,13 @@ export function PlanOffering({
|
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
const [perUnitQuantityByFeature, setPerUnitQuantityByFeature] = useState<Record<string, number>>(
|
|
164
|
-
getTiersPerUnitQuantities(
|
|
166
|
+
getTiersPerUnitQuantities({
|
|
167
|
+
plan,
|
|
168
|
+
billingPeriod,
|
|
169
|
+
currentSubscription,
|
|
170
|
+
currentSubscriptionOverride,
|
|
171
|
+
selectDefaultTierIndex,
|
|
172
|
+
}),
|
|
165
173
|
);
|
|
166
174
|
|
|
167
175
|
const onPlanButtonClick = (intentionType: SubscribeIntentionType) => {
|
|
@@ -214,6 +222,7 @@ export function PlanOffering({
|
|
|
214
222
|
customer={customer}
|
|
215
223
|
plan={plan}
|
|
216
224
|
currentSubscription={currentSubscription}
|
|
225
|
+
currentSubscriptionOverride={currentSubscriptionOverride}
|
|
217
226
|
billingPeriod={billingPeriod}
|
|
218
227
|
isCustomerOnTrial={isCustomerOnTrial}
|
|
219
228
|
onPlanSelected={onPlanButtonClick}
|
|
@@ -4,7 +4,7 @@ import { isFunction } from 'lodash';
|
|
|
4
4
|
import ClipLoader from 'react-spinners/ClipLoader';
|
|
5
5
|
import styled from '@emotion/styled/macro';
|
|
6
6
|
import { css, useTheme } from '@emotion/react';
|
|
7
|
-
import { PaywallPlan, SubscribeIntentionType } from './types';
|
|
7
|
+
import { CurrentSubscriptionOverride, PaywallPlan, SubscribeIntentionType } from './types';
|
|
8
8
|
import { PaywallLocalization } from './paywallTextOverrides';
|
|
9
9
|
import { flexLayoutMapper } from '../../theme/getResolvedTheme';
|
|
10
10
|
import { Typography } from '../common/Typography';
|
|
@@ -77,6 +77,7 @@ type PlanOfferingButtonProps = {
|
|
|
77
77
|
customer: Customer | null;
|
|
78
78
|
plan: PaywallPlan;
|
|
79
79
|
currentSubscription: Subscription | null;
|
|
80
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
80
81
|
billingPeriod: BillingPeriod;
|
|
81
82
|
isCustomerOnTrial: boolean;
|
|
82
83
|
paywallLocale: PaywallLocalization;
|
|
@@ -95,6 +96,7 @@ export function PlanOfferingButton({
|
|
|
95
96
|
paywallLocale,
|
|
96
97
|
withTrialLeftRow,
|
|
97
98
|
currentSubscription,
|
|
99
|
+
currentSubscriptionOverride,
|
|
98
100
|
perUnitQuantityByFeature,
|
|
99
101
|
}: PlanOfferingButtonProps) {
|
|
100
102
|
const theme = useTheme();
|
|
@@ -142,7 +144,12 @@ export function PlanOfferingButton({
|
|
|
142
144
|
isSameBillingPeriod ||
|
|
143
145
|
(plan.pricingType && [PricingType.Free, PricingType.Custom].includes(plan.pricingType))
|
|
144
146
|
) {
|
|
145
|
-
const planComparison = compareSelectedTierToCurrentTier(
|
|
147
|
+
const planComparison = compareSelectedTierToCurrentTier({
|
|
148
|
+
perUnitQuantityByFeature,
|
|
149
|
+
plan,
|
|
150
|
+
currentSubscription,
|
|
151
|
+
currentSubscriptionOverride,
|
|
152
|
+
});
|
|
146
153
|
switch (planComparison) {
|
|
147
154
|
case PriceTierComparison.Lower:
|
|
148
155
|
buttonProps.intentionType = SubscribeIntentionType.CHANGE_UNIT_QUANTITY;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BillingPeriod, Paywall } from '@stigg/js-client-sdk';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import logger from '../../../services/logger';
|
|
4
|
-
import { PaywallData } from '../types';
|
|
4
|
+
import { CurrentSubscriptionOverrideFn, PaywallData } from '../types';
|
|
5
5
|
import { computeBillingPeriods } from '../utils/computeDefaultBillingPeriod';
|
|
6
6
|
import { mapPaywallData } from '../utils/mapPaywallData';
|
|
7
7
|
import { useStiggContext } from '../../../hooks/useStiggContext';
|
|
@@ -12,6 +12,7 @@ type UseLoadPaywallDataProps = {
|
|
|
12
12
|
showOnlyEligiblePlans?: boolean;
|
|
13
13
|
billingCountryCode?: string;
|
|
14
14
|
preferredBillingPeriod?: BillingPeriod;
|
|
15
|
+
currentSubscriptionOverrideFn?: CurrentSubscriptionOverrideFn;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export function useLoadPaywallData({
|
|
@@ -20,6 +21,7 @@ export function useLoadPaywallData({
|
|
|
20
21
|
showOnlyEligiblePlans,
|
|
21
22
|
billingCountryCode,
|
|
22
23
|
preferredBillingPeriod,
|
|
24
|
+
currentSubscriptionOverrideFn,
|
|
23
25
|
}: UseLoadPaywallDataProps): PaywallData {
|
|
24
26
|
const { stigg, locale } = useStiggContext();
|
|
25
27
|
const [selectedBillingPeriod, setSelectedBillingPeriod] = useState(BillingPeriod.Annually);
|
|
@@ -57,7 +59,7 @@ export function useLoadPaywallData({
|
|
|
57
59
|
void loadPaywall();
|
|
58
60
|
}, [stigg, productId, stigg.isCustomerLoaded, billingCountryCode, resourceId, preferredBillingPeriod]);
|
|
59
61
|
|
|
60
|
-
const paywallData = mapPaywallData(paywall, showOnlyEligiblePlans);
|
|
62
|
+
const paywallData = mapPaywallData(paywall, showOnlyEligiblePlans, currentSubscriptionOverrideFn);
|
|
61
63
|
|
|
62
64
|
return {
|
|
63
65
|
customer: paywall?.customer || null,
|
|
@@ -14,6 +14,7 @@ export type PaywallData = {
|
|
|
14
14
|
plans: PaywallPlan[] | null;
|
|
15
15
|
customer: Customer | null;
|
|
16
16
|
currentSubscription: Subscription | null;
|
|
17
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
17
18
|
isCustomerOnTrial: boolean;
|
|
18
19
|
isLoading: boolean;
|
|
19
20
|
selectedBillingPeriod: BillingPeriod;
|
|
@@ -23,6 +24,11 @@ export type PaywallData = {
|
|
|
23
24
|
configuration?: CustomizedTheme;
|
|
24
25
|
};
|
|
25
26
|
|
|
27
|
+
export type CurrentSubscriptionOverride = {
|
|
28
|
+
planId: string;
|
|
29
|
+
billableFeatures: BillableFeature[];
|
|
30
|
+
};
|
|
31
|
+
|
|
26
32
|
export enum SubscribeIntentionType {
|
|
27
33
|
START_TRIAL = 'START_TRIAL',
|
|
28
34
|
UPGRADE_TRIAL_TO_PAID = 'UPGRADE_TRIAL_TO_PAID',
|
|
@@ -64,4 +70,10 @@ export type OnPlanSelectedCallbackFn = ({
|
|
|
64
70
|
|
|
65
71
|
export type ShouldHidePlanFn = ({ plan }: { plan: PaywallPlan }) => boolean | Promise<boolean>;
|
|
66
72
|
|
|
73
|
+
export type CurrentSubscriptionOverrideFn = ({
|
|
74
|
+
currentSubscription,
|
|
75
|
+
}: {
|
|
76
|
+
currentSubscription: Subscription | null;
|
|
77
|
+
}) => CurrentSubscriptionOverride | null | undefined;
|
|
78
|
+
|
|
67
79
|
export type SelectDefaultTierIndexFn = ({ plan }: { plan: PaywallPlan }) => number;
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@stigg/js-client-sdk';
|
|
9
9
|
import isNil from 'lodash/isNil';
|
|
10
10
|
import sortBy from 'lodash/sortBy';
|
|
11
|
-
import { PaywallPlan } from '../types';
|
|
11
|
+
import { CurrentSubscriptionOverride, CurrentSubscriptionOverrideFn, PaywallPlan } from '../types';
|
|
12
12
|
import { calculateTrialDaysLeft } from './calculateTrialDaysLeft';
|
|
13
13
|
import { BillingPeriodChangeVariables, DeepPartial, DowngradeChangeVariables } from '../../../types';
|
|
14
14
|
import { StiggTheme } from '../../../theme/types';
|
|
@@ -39,16 +39,23 @@ function getCustomerSubscriptionDetails(activeSubscriptions?: Subscription[] | n
|
|
|
39
39
|
type PaywallData = {
|
|
40
40
|
currentPlan?: Plan;
|
|
41
41
|
currentSubscription: Subscription | null;
|
|
42
|
+
currentSubscriptionOverride: CurrentSubscriptionOverride | null | undefined;
|
|
42
43
|
isCustomerOnTrial: boolean;
|
|
43
44
|
plans: PaywallPlan[];
|
|
44
45
|
paywallConfiguration?: DeepPartial<StiggTheme>;
|
|
45
46
|
};
|
|
46
47
|
|
|
47
|
-
export function mapPaywallData(
|
|
48
|
+
export function mapPaywallData(
|
|
49
|
+
paywall: Paywall | null,
|
|
50
|
+
showOnlyEligiblePlans?: boolean,
|
|
51
|
+
currentSubscriptionOverrideFn?: CurrentSubscriptionOverrideFn,
|
|
52
|
+
): PaywallData {
|
|
48
53
|
const { plans, currency, configuration, customer, activeSubscriptions, paywallCalculatedPricePoints } = paywall || {};
|
|
49
54
|
const { currentSubscription, currentPlan, isCustomerOnTrial, trialDaysLeft } =
|
|
50
55
|
getCustomerSubscriptionDetails(activeSubscriptions);
|
|
51
56
|
|
|
57
|
+
const currentSubscriptionOverride = currentSubscriptionOverrideFn?.({ currentSubscription });
|
|
58
|
+
|
|
52
59
|
const scheduledUpdates = currentSubscription?.scheduledUpdates || [];
|
|
53
60
|
const currentCustomerPlanBillingPeriod = currentSubscription?.price?.billingPeriod;
|
|
54
61
|
const downgradeSchedule = scheduledUpdates.find(
|
|
@@ -62,7 +69,9 @@ export function mapPaywallData(paywall: Paywall | null, showOnlyEligiblePlans?:
|
|
|
62
69
|
const eligibleForProductTrial = customer?.eligibleForTrial?.find(
|
|
63
70
|
(productTrial) => productTrial.productId === plan.product.id,
|
|
64
71
|
);
|
|
65
|
-
const isCurrentCustomerPlan =
|
|
72
|
+
const isCurrentCustomerPlan = currentSubscriptionOverride?.planId
|
|
73
|
+
? currentSubscriptionOverride?.planId === plan.id
|
|
74
|
+
: plan.id === currentPlan?.id;
|
|
66
75
|
|
|
67
76
|
const isNextPlan = (currentBillingPeriod: BillingPeriod) => {
|
|
68
77
|
const downgradeVariables = downgradeSchedule?.scheduleVariables as DowngradeChangeVariables;
|
|
@@ -109,6 +118,7 @@ export function mapPaywallData(paywall: Paywall | null, showOnlyEligiblePlans?:
|
|
|
109
118
|
return {
|
|
110
119
|
currentPlan,
|
|
111
120
|
currentSubscription,
|
|
121
|
+
currentSubscriptionOverride,
|
|
112
122
|
isCustomerOnTrial,
|
|
113
123
|
plans: paywallPlans,
|
|
114
124
|
paywallConfiguration,
|
|
@@ -2,7 +2,7 @@ import { BillingModel, TiersMode, BillingPeriod, Price, PriceTierFragment, Subsc
|
|
|
2
2
|
import isNil from 'lodash/isNil';
|
|
3
3
|
import { sum } from 'lodash';
|
|
4
4
|
import { PaywallPlan } from '../paywall';
|
|
5
|
-
import { SelectDefaultTierIndexFn } from '../paywall/types';
|
|
5
|
+
import { CurrentSubscriptionOverride, SelectDefaultTierIndexFn } from '../paywall/types';
|
|
6
6
|
|
|
7
7
|
export function getPriceFeatureUnit(price: Price) {
|
|
8
8
|
if (!price.feature) {
|
|
@@ -131,12 +131,19 @@ export function isQuantityInFirstTier(tiers: PriceTierFragment[] | null | undefi
|
|
|
131
131
|
return tiers?.[0].upTo && quantity <= tiers[0].upTo;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export function getTiersPerUnitQuantities(
|
|
135
|
-
plan
|
|
136
|
-
billingPeriod
|
|
137
|
-
currentSubscription
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
export function getTiersPerUnitQuantities({
|
|
135
|
+
plan,
|
|
136
|
+
billingPeriod,
|
|
137
|
+
currentSubscription,
|
|
138
|
+
currentSubscriptionOverride,
|
|
139
|
+
selectDefaultTierIndex,
|
|
140
|
+
}: {
|
|
141
|
+
plan: PaywallPlan;
|
|
142
|
+
billingPeriod: BillingPeriod;
|
|
143
|
+
currentSubscription: Subscription | null;
|
|
144
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
145
|
+
selectDefaultTierIndex?: SelectDefaultTierIndexFn;
|
|
146
|
+
}): Record<string, number> {
|
|
140
147
|
const planTierPrices = plan.pricePoints.filter(
|
|
141
148
|
(price) => price.billingPeriod === billingPeriod && price.isTieredPrice,
|
|
142
149
|
);
|
|
@@ -161,6 +168,15 @@ export function getTiersPerUnitQuantities(
|
|
|
161
168
|
}
|
|
162
169
|
}
|
|
163
170
|
|
|
171
|
+
if (currentSubscriptionOverride?.planId === plan.id) {
|
|
172
|
+
const billableFeature = currentSubscriptionOverride.billableFeatures.find(
|
|
173
|
+
(billableFeature) => billableFeature.featureId === featureId,
|
|
174
|
+
);
|
|
175
|
+
if (billableFeature) {
|
|
176
|
+
quantity = billableFeature.quantity;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
164
180
|
const result: Record<string, number> = {};
|
|
165
181
|
result[featureId] = quantity;
|
|
166
182
|
|
|
@@ -176,22 +192,47 @@ export enum PriceTierComparison {
|
|
|
176
192
|
Higher = 1,
|
|
177
193
|
}
|
|
178
194
|
|
|
179
|
-
export function compareSelectedTierToCurrentTier(
|
|
180
|
-
perUnitQuantityByFeature
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
export function compareSelectedTierToCurrentTier({
|
|
196
|
+
perUnitQuantityByFeature,
|
|
197
|
+
plan,
|
|
198
|
+
currentSubscription,
|
|
199
|
+
currentSubscriptionOverride,
|
|
200
|
+
}: {
|
|
201
|
+
perUnitQuantityByFeature: Record<string, number>;
|
|
202
|
+
plan: PaywallPlan;
|
|
203
|
+
currentSubscription: Subscription | null;
|
|
204
|
+
currentSubscriptionOverride?: CurrentSubscriptionOverride | null;
|
|
205
|
+
}): PriceTierComparison {
|
|
183
206
|
if (!currentSubscription) {
|
|
184
207
|
return PriceTierComparison.Equal;
|
|
185
208
|
}
|
|
186
209
|
|
|
187
|
-
|
|
210
|
+
let currentTierPrice = currentSubscription.prices.find(
|
|
188
211
|
(price) => price.pricingModel === BillingModel.PerUnit && price.tiersMode,
|
|
189
212
|
);
|
|
213
|
+
|
|
214
|
+
const isCurrentPlanOverride = plan.id === currentSubscriptionOverride?.planId;
|
|
215
|
+
if (isCurrentPlanOverride) {
|
|
216
|
+
currentTierPrice =
|
|
217
|
+
plan.pricePoints.find((price) => price.pricingModel === BillingModel.PerUnit && price.tiersMode) ??
|
|
218
|
+
currentTierPrice;
|
|
219
|
+
}
|
|
220
|
+
|
|
190
221
|
if (!currentTierPrice) {
|
|
191
222
|
return PriceTierComparison.Equal;
|
|
192
223
|
}
|
|
193
224
|
|
|
194
|
-
const { featureId, unitQuantity
|
|
225
|
+
const { featureId, unitQuantity } = currentTierPrice.feature!;
|
|
226
|
+
let oldQuantity = unitQuantity;
|
|
227
|
+
|
|
228
|
+
if (isCurrentPlanOverride) {
|
|
229
|
+
const billableFeature = currentSubscriptionOverride?.billableFeatures?.find(
|
|
230
|
+
(billableFeature) => billableFeature.featureId === featureId,
|
|
231
|
+
);
|
|
232
|
+
if (billableFeature) {
|
|
233
|
+
oldQuantity = billableFeature.quantity;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
195
236
|
|
|
196
237
|
if (isNil(oldQuantity)) {
|
|
197
238
|
return PriceTierComparison.Equal;
|