@stigg/react-sdk 4.4.0-beta.11 → 4.4.0-beta.12
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/Checkout.d.ts +1 -1
- package/dist/components/checkout/CheckoutContainer.d.ts +4 -2
- package/dist/components/checkout/CheckoutProvider.d.ts +4 -2
- package/dist/components/checkout/hooks/useLoadCheckout.d.ts +3 -1
- package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +8 -3
- package/dist/components/checkout/summary/CheckoutSummary.d.ts +1 -1
- package/dist/react-sdk.cjs.development.js +94 -46
- 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 +94 -46
- package/dist/react-sdk.esm.js.map +1 -1
- package/dist/stories/mocks/checkout/consts.d.ts +11 -0
- package/dist/stories/mocks/checkout/mockCheckoutPreview.d.ts +2 -0
- package/dist/stories/mocks/checkout/mockCheckoutState.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/checkout/Checkout.tsx +3 -1
- package/src/components/checkout/CheckoutContainer.tsx +21 -2
- package/src/components/checkout/CheckoutProvider.tsx +6 -2
- package/src/components/checkout/hooks/useLoadCheckout.ts +10 -2
- package/src/components/checkout/hooks/usePreviewSubscription.ts +15 -5
- package/src/components/checkout/summary/CheckoutSummary.tsx +2 -1
- package/src/stories/Checkout.stories.tsx +32 -6
- package/src/stories/mocks/checkout/consts.ts +15 -0
- package/src/stories/mocks/checkout/mockCheckoutPreview.ts +121 -0
- package/src/stories/mocks/checkout/mockCheckoutState.ts +206 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const BASE_FEE_MONTHLY = 200;
|
|
2
|
+
export declare const BASE_FEE_YEARLY = 175;
|
|
3
|
+
export declare const TIERS: number[];
|
|
4
|
+
export declare const TIERS_PRICE_MONTHLY: number[];
|
|
5
|
+
export declare const TIERS_PRICE_YEARLY: number[];
|
|
6
|
+
export declare const PER_UNIT_PRICE_MONTHLY = 12;
|
|
7
|
+
export declare const PER_UNIT_PRICE_YEARLY = 10;
|
|
8
|
+
export declare const ADDON_PRICE_MONTHLY = 50;
|
|
9
|
+
export declare const ADDON_PRICE_YEARLY = 35;
|
|
10
|
+
export declare const STRIPE_MOCK_ACCOUNT_ID = "acct_1NnHoQG6EyqgvTaj";
|
|
11
|
+
export declare const STRIPE_MOCK_ACCOUNT_PK = "pk_test_51NnHoQG6EyqgvTajznajopWC01AozNtq7zgySeQ1qx4PH9TAXvMj0TnbZvYT3yOt46jbQAcCDs1EU2QKcfG8eEoO00tlW0Jp3r";
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ export const Checkout = ({
|
|
|
13
13
|
billingCountryCode,
|
|
14
14
|
billableFeatures,
|
|
15
15
|
billingInformation,
|
|
16
|
+
onMockCheckoutState,
|
|
16
17
|
...containerProps
|
|
17
18
|
}: CheckoutProps) => {
|
|
18
19
|
return (
|
|
@@ -24,7 +25,8 @@ export const Checkout = ({
|
|
|
24
25
|
preferredBillingPeriod={preferredBillingPeriod}
|
|
25
26
|
billingCountryCode={billingCountryCode}
|
|
26
27
|
billableFeatures={billableFeatures}
|
|
27
|
-
billingInformation={billingInformation}
|
|
28
|
+
billingInformation={billingInformation}
|
|
29
|
+
onMockCheckoutState={onMockCheckoutState}>
|
|
28
30
|
<CheckoutContainer {...containerProps} />
|
|
29
31
|
</CheckoutProvider>
|
|
30
32
|
);
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Elements } from '@stripe/react-stripe-js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
PricingType,
|
|
5
|
+
BillingAddress,
|
|
6
|
+
ApplySubscription,
|
|
7
|
+
CheckoutStatePlan,
|
|
8
|
+
PreviewSubscription,
|
|
9
|
+
SubscriptionPreview,
|
|
10
|
+
} from '@stigg/js-client-sdk';
|
|
4
11
|
import { CheckoutContent, CheckoutLayout, CheckoutPanel } from './CheckoutContainer.style';
|
|
5
12
|
import { CheckoutProgressBar } from './progressBar/CheckoutProgressBar';
|
|
6
13
|
import { CheckoutSummary, CheckoutSummarySkeleton } from './summary';
|
|
@@ -19,6 +26,9 @@ type StepProps = {
|
|
|
19
26
|
content: React.ReactNode;
|
|
20
27
|
};
|
|
21
28
|
|
|
29
|
+
type StripeClientSecret = { clientSecret: string };
|
|
30
|
+
type StripeManualMode = { mode: 'setup' | 'payment' | 'subscription'; currency: string };
|
|
31
|
+
|
|
22
32
|
const getStepProps = (
|
|
23
33
|
currentStep: CheckoutStep,
|
|
24
34
|
{ onBillingAddressChange }: Pick<CheckoutContainerProps, 'onBillingAddressChange'>,
|
|
@@ -41,6 +51,8 @@ export type OnCheckoutParams = { checkoutParams: ApplySubscription; checkoutActi
|
|
|
41
51
|
|
|
42
52
|
export type OnCheckoutCompletedParams = { success: boolean; error?: string };
|
|
43
53
|
|
|
54
|
+
export type OnMockCheckoutPreviewCallback = (params: PreviewSubscription) => SubscriptionPreview;
|
|
55
|
+
|
|
44
56
|
export type CheckoutContainerProps = {
|
|
45
57
|
onCheckout?: (params: OnCheckoutParams) => Promise<CheckoutResult>;
|
|
46
58
|
onCheckoutCompleted: (params: OnCheckoutCompletedParams) => Promise<void>;
|
|
@@ -48,6 +60,7 @@ export type CheckoutContainerProps = {
|
|
|
48
60
|
onBillingAddressChange?: (params: { billingAddress: BillingAddress }) => Promise<void>;
|
|
49
61
|
disablePromotionCode?: boolean;
|
|
50
62
|
disableSuccessAnimation?: boolean;
|
|
63
|
+
onMockCheckoutPreview?: OnMockCheckoutPreviewCallback;
|
|
51
64
|
};
|
|
52
65
|
|
|
53
66
|
export function CheckoutContainer({
|
|
@@ -57,6 +70,7 @@ export function CheckoutContainer({
|
|
|
57
70
|
onBillingAddressChange,
|
|
58
71
|
disablePromotionCode,
|
|
59
72
|
disableSuccessAnimation,
|
|
73
|
+
onMockCheckoutPreview,
|
|
60
74
|
}: CheckoutContainerProps) {
|
|
61
75
|
const { stripePromise, setupIntentClientSecret } = useStripeIntegration();
|
|
62
76
|
const [{ stiggTheme, widgetState }] = useCheckoutContext();
|
|
@@ -93,11 +107,15 @@ export function CheckoutContainer({
|
|
|
93
107
|
</>
|
|
94
108
|
);
|
|
95
109
|
|
|
110
|
+
const stripeElementsMode: StripeClientSecret | StripeManualMode = setupIntentClientSecret
|
|
111
|
+
? { clientSecret: setupIntentClientSecret }
|
|
112
|
+
: { mode: 'setup', currency: 'usd' };
|
|
113
|
+
|
|
96
114
|
return (
|
|
97
115
|
<Elements
|
|
98
116
|
stripe={stripePromise}
|
|
99
117
|
options={{
|
|
100
|
-
|
|
118
|
+
...stripeElementsMode,
|
|
101
119
|
appearance: {
|
|
102
120
|
theme: 'stripe',
|
|
103
121
|
variables: {
|
|
@@ -121,6 +139,7 @@ export function CheckoutContainer({
|
|
|
121
139
|
onCheckout={onCheckout}
|
|
122
140
|
onCheckoutCompleted={onCheckoutCompleted}
|
|
123
141
|
isFreeDowngrade={isFreeDowngrade}
|
|
142
|
+
onMockCheckoutPreview={onMockCheckoutPreview}
|
|
124
143
|
/>
|
|
125
144
|
)}
|
|
126
145
|
</CheckoutContent>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
2
|
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { BillableFeature, BillingPeriod, GetCheckoutStateResults } from '@stigg/js-client-sdk';
|
|
3
|
+
import { BillableFeature, BillingPeriod, GetCheckoutState, GetCheckoutStateResults } from '@stigg/js-client-sdk';
|
|
4
4
|
import { CustomizedTheme, SdkThemeProvider, useStiggTheme } from '../../theme/Theme';
|
|
5
5
|
import { DeepPartial } from '../../types';
|
|
6
6
|
import { mapCheckoutConfiguration } from '../common/mapExternalTheme';
|
|
@@ -71,6 +71,8 @@ const CheckoutContextProvider: React.FC<{ children: React.ReactNode; initialStat
|
|
|
71
71
|
return <CheckoutContext.Provider value={[contextValue, setContextValue]}>{children}</CheckoutContext.Provider>;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
export type MockCheckoutStateCallback = (params: GetCheckoutState) => GetCheckoutStateResults;
|
|
75
|
+
|
|
74
76
|
export type CheckoutProviderProps = {
|
|
75
77
|
textOverrides?: DeepPartial<CheckoutLocalization>;
|
|
76
78
|
theme?: DeepPartial<CheckoutTheme>;
|
|
@@ -80,6 +82,7 @@ export type CheckoutProviderProps = {
|
|
|
80
82
|
billingCountryCode?: string;
|
|
81
83
|
billableFeatures?: BillableFeature[];
|
|
82
84
|
billingInformation?: BillingInformation;
|
|
85
|
+
onMockCheckoutState?: MockCheckoutStateCallback;
|
|
83
86
|
};
|
|
84
87
|
|
|
85
88
|
export function CheckoutProvider({
|
|
@@ -92,10 +95,11 @@ export function CheckoutProvider({
|
|
|
92
95
|
planId,
|
|
93
96
|
billingCountryCode,
|
|
94
97
|
billingInformation,
|
|
98
|
+
onMockCheckoutState,
|
|
95
99
|
}: {
|
|
96
100
|
children: React.ReactNode;
|
|
97
101
|
} & CheckoutProviderProps) {
|
|
98
|
-
const { checkout, isLoading } = useLoadCheckout({ resourceId, planId, billingCountryCode });
|
|
102
|
+
const { checkout, isLoading } = useLoadCheckout({ resourceId, planId, billingCountryCode, onMockCheckoutState });
|
|
99
103
|
const configuration: CustomizedTheme | undefined = checkout?.configuration
|
|
100
104
|
? mapCheckoutConfiguration(checkout.configuration)
|
|
101
105
|
: undefined;
|
|
@@ -2,14 +2,16 @@ import { GetCheckoutStateResults } from '@stigg/js-client-sdk';
|
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import logger from '../../../services/logger';
|
|
4
4
|
import { useStiggContext } from '../../StiggProvider';
|
|
5
|
+
import { MockCheckoutStateCallback } from '../CheckoutProvider';
|
|
5
6
|
|
|
6
7
|
type UseLoadCheckoutProps = {
|
|
7
8
|
planId: string;
|
|
8
9
|
resourceId?: string;
|
|
9
10
|
billingCountryCode?: string;
|
|
11
|
+
onMockCheckoutState?: MockCheckoutStateCallback;
|
|
10
12
|
};
|
|
11
13
|
|
|
12
|
-
export function useLoadCheckout({ planId, resourceId, billingCountryCode }: UseLoadCheckoutProps) {
|
|
14
|
+
export function useLoadCheckout({ planId, resourceId, billingCountryCode, onMockCheckoutState }: UseLoadCheckoutProps) {
|
|
13
15
|
const { stigg } = useStiggContext();
|
|
14
16
|
const [isLoading, setIsLoading] = useState(true);
|
|
15
17
|
const [checkout, setCheckout] = useState<GetCheckoutStateResults | null>();
|
|
@@ -26,11 +28,17 @@ export function useLoadCheckout({ planId, resourceId, billingCountryCode }: UseL
|
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
30
|
|
|
31
|
+
if (onMockCheckoutState) {
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
setCheckout(onMockCheckoutState({ planId, resourceId, billingCountryCode }));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
if (stigg.isCustomerLoaded) {
|
|
30
38
|
setIsLoading(true);
|
|
31
39
|
void loadCheckout();
|
|
32
40
|
}
|
|
33
|
-
}, [stigg, stigg.isCustomerLoaded, resourceId, planId, billingCountryCode]);
|
|
41
|
+
}, [stigg, stigg.isCustomerLoaded, resourceId, planId, billingCountryCode, onMockCheckoutState]);
|
|
34
42
|
|
|
35
43
|
return {
|
|
36
44
|
checkout,
|
|
@@ -5,6 +5,7 @@ import { useStiggContext } from '../../StiggProvider';
|
|
|
5
5
|
import { useCheckoutContext } from '../CheckoutProvider';
|
|
6
6
|
import { useCheckoutModel } from './useCheckoutModel';
|
|
7
7
|
import { SubscriptionState, useSubscriptionModel } from './useSubscriptionModel';
|
|
8
|
+
import { OnMockCheckoutPreviewCallback } from '../CheckoutContainer';
|
|
8
9
|
|
|
9
10
|
function mapBillingInformation({
|
|
10
11
|
billingAddress,
|
|
@@ -25,12 +26,17 @@ function mapBillingInformation({
|
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
type UsePreviewSubscriptionProps = {
|
|
30
|
+
onMockCheckoutPreview?: OnMockCheckoutPreviewCallback;
|
|
31
|
+
};
|
|
32
|
+
|
|
28
33
|
export type PreviewSubscriptionProps = {
|
|
29
34
|
customerId?: string;
|
|
30
35
|
planId?: string;
|
|
31
36
|
resourceId?: string;
|
|
32
37
|
stigg: StiggClient;
|
|
33
|
-
} & SubscriptionState
|
|
38
|
+
} & SubscriptionState &
|
|
39
|
+
UsePreviewSubscriptionProps;
|
|
34
40
|
|
|
35
41
|
const previewSubscription = async ({
|
|
36
42
|
stigg,
|
|
@@ -44,6 +50,7 @@ const previewSubscription = async ({
|
|
|
44
50
|
billingPeriod,
|
|
45
51
|
billingAddress,
|
|
46
52
|
taxPercentage,
|
|
53
|
+
onMockCheckoutPreview,
|
|
47
54
|
}: PreviewSubscriptionProps) => {
|
|
48
55
|
const estimateAddons = addons.map(({ addon, quantity }) => ({ addonId: addon.id, quantity }));
|
|
49
56
|
let subscriptionPreview: SubscriptionPreview | null = null;
|
|
@@ -63,7 +70,9 @@ const previewSubscription = async ({
|
|
|
63
70
|
...mapBillingInformation({ billingAddress, taxPercentage }),
|
|
64
71
|
};
|
|
65
72
|
|
|
66
|
-
subscriptionPreview =
|
|
73
|
+
subscriptionPreview = onMockCheckoutPreview
|
|
74
|
+
? onMockCheckoutPreview(previewSubscriptionProps)
|
|
75
|
+
: await stigg.previewSubscription(previewSubscriptionProps);
|
|
67
76
|
}
|
|
68
77
|
} catch (error) {
|
|
69
78
|
const [, errorMsg] = (error as any)?.message?.split('Error:') || [];
|
|
@@ -74,7 +83,7 @@ const previewSubscription = async ({
|
|
|
74
83
|
return { subscriptionPreview, errorMessage };
|
|
75
84
|
};
|
|
76
85
|
|
|
77
|
-
export const usePreviewSubscriptionAction = () => {
|
|
86
|
+
export const usePreviewSubscriptionAction = ({ onMockCheckoutPreview }: UsePreviewSubscriptionProps = {}) => {
|
|
78
87
|
const { stigg } = useStiggContext();
|
|
79
88
|
const subscription = useSubscriptionModel();
|
|
80
89
|
const [{ resourceId }] = useCheckoutContext();
|
|
@@ -99,6 +108,7 @@ export const usePreviewSubscriptionAction = () => {
|
|
|
99
108
|
billingAddress: subscription.billingAddress,
|
|
100
109
|
taxPercentage: subscription.taxPercentage,
|
|
101
110
|
promotionCode: promotionCode ?? subscription.promotionCode,
|
|
111
|
+
onMockCheckoutPreview,
|
|
102
112
|
});
|
|
103
113
|
},
|
|
104
114
|
[
|
|
@@ -122,11 +132,11 @@ export const usePreviewSubscriptionAction = () => {
|
|
|
122
132
|
|
|
123
133
|
const SUBSCRIPTION_PREVIEW_DEBOUNCE_TIME = 500;
|
|
124
134
|
|
|
125
|
-
export const usePreviewSubscription = () => {
|
|
135
|
+
export const usePreviewSubscription = ({ onMockCheckoutPreview }: UsePreviewSubscriptionProps = {}) => {
|
|
126
136
|
const [subscriptionPreview, setSubscriptionPreview] = useState<SubscriptionPreview | null>(null);
|
|
127
137
|
const [isFetchingSubscriptionPreview, setIsFetchingSubscriptionPreview] = useState(false);
|
|
128
138
|
|
|
129
|
-
const { previewSubscriptionAction } = usePreviewSubscriptionAction();
|
|
139
|
+
const { previewSubscriptionAction } = usePreviewSubscriptionAction({ onMockCheckoutPreview });
|
|
130
140
|
|
|
131
141
|
useEffect(() => {
|
|
132
142
|
const estimateSubscription = async () => {
|
|
@@ -91,6 +91,7 @@ export const CheckoutSummary = ({
|
|
|
91
91
|
disablePromotionCode,
|
|
92
92
|
disableSuccessAnimation,
|
|
93
93
|
isFreeDowngrade,
|
|
94
|
+
onMockCheckoutPreview,
|
|
94
95
|
}: CheckoutContainerProps & { isFreeDowngrade: boolean }) => {
|
|
95
96
|
const [isCheckoutCompletedSuccessfully, setIsCheckoutCompletedSuccessfully] = useState(false);
|
|
96
97
|
const { setErrorMessage } = usePaymentStepModel();
|
|
@@ -105,7 +106,7 @@ export const CheckoutSummary = ({
|
|
|
105
106
|
const [baseCharge] = baseCharges || [];
|
|
106
107
|
const isLastStep = isFreeDowngrade || (progressBar.isCheckoutComplete && progressBar.isLastStep);
|
|
107
108
|
|
|
108
|
-
const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription();
|
|
109
|
+
const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription({ onMockCheckoutPreview });
|
|
109
110
|
|
|
110
111
|
const { handleSubmit, isLoading } = useSubmit({
|
|
111
112
|
disableSuccessAnimation,
|
|
@@ -4,6 +4,8 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
|
4
4
|
import { Checkout } from '../components/checkout';
|
|
5
5
|
import { StiggProvider } from '../components/StiggProvider';
|
|
6
6
|
import { defaultArgsWithCustomer } from './baseArgs';
|
|
7
|
+
import { mockCheckoutState } from './mocks/checkout/mockCheckoutState';
|
|
8
|
+
import { mockPreviewSubscription } from './mocks/checkout/mockCheckoutPreview';
|
|
7
9
|
|
|
8
10
|
export default {
|
|
9
11
|
title: 'Stigg React SDK/Checkout',
|
|
@@ -21,6 +23,18 @@ export default {
|
|
|
21
23
|
</StiggProvider>
|
|
22
24
|
),
|
|
23
25
|
],
|
|
26
|
+
parameters: {
|
|
27
|
+
controls: {
|
|
28
|
+
exclude: [
|
|
29
|
+
'onCheckout',
|
|
30
|
+
'onCheckoutCompleted',
|
|
31
|
+
'onChangePlan',
|
|
32
|
+
'onBillingAddressChange',
|
|
33
|
+
'onMockCheckoutState',
|
|
34
|
+
'onMockCheckoutPreview',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
24
38
|
} as ComponentMeta<typeof Checkout>;
|
|
25
39
|
|
|
26
40
|
const Wrapper = styled.div`
|
|
@@ -43,11 +57,26 @@ const Template: ComponentStory<any> = (args) => (
|
|
|
43
57
|
const { success, errorMessage } = await checkoutAction();
|
|
44
58
|
return { success, errorMessage };
|
|
45
59
|
}}
|
|
60
|
+
billableFeatures={[{ featureId: 'feature-seat', quantity: 30 }]}
|
|
46
61
|
onChangePlan={({ currentPlan }) => {
|
|
47
62
|
console.log('plan changed clicked!', { currentPlan });
|
|
48
63
|
}}
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
onMockCheckoutState={
|
|
65
|
+
args.useMockData
|
|
66
|
+
? (params) => {
|
|
67
|
+
console.log('mocking checkout state', params);
|
|
68
|
+
return mockCheckoutState(params);
|
|
69
|
+
}
|
|
70
|
+
: undefined
|
|
71
|
+
}
|
|
72
|
+
onMockCheckoutPreview={
|
|
73
|
+
args.useMockData
|
|
74
|
+
? (params) => {
|
|
75
|
+
console.log('mocking checkout preview');
|
|
76
|
+
return mockPreviewSubscription(params);
|
|
77
|
+
}
|
|
78
|
+
: undefined
|
|
79
|
+
}
|
|
51
80
|
/>
|
|
52
81
|
</Wrapper>
|
|
53
82
|
);
|
|
@@ -56,8 +85,5 @@ export const DefaultCheckout = Template.bind({});
|
|
|
56
85
|
DefaultCheckout.args = {
|
|
57
86
|
...defaultArgsWithCustomer,
|
|
58
87
|
planId: 'plan-revvenu-essentials',
|
|
59
|
-
|
|
60
|
-
// apiKey: 'client-72b058a6-0f22-4c86-adce-bf266d12e12e:9f356ceb-c94c-42a4-9572-10b12824da81',
|
|
61
|
-
baseUri: 'https://api-staging.stigg.io',
|
|
62
|
-
apiKey: 'client-79584f52-7ef9-4c58-b9ac-5080acf492e4:71f2274c-100a-4fa4-8a43-48fa3b16c627',
|
|
88
|
+
useMockData: false,
|
|
63
89
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const BASE_FEE_MONTHLY = 200;
|
|
2
|
+
export const BASE_FEE_YEARLY = 175;
|
|
3
|
+
export const TIERS = [1000, 10000, 50000];
|
|
4
|
+
export const TIERS_PRICE_MONTHLY = [10, 90, 480];
|
|
5
|
+
export const TIERS_PRICE_YEARLY = [8, 75, 350];
|
|
6
|
+
|
|
7
|
+
export const PER_UNIT_PRICE_MONTHLY = 12;
|
|
8
|
+
export const PER_UNIT_PRICE_YEARLY = 10;
|
|
9
|
+
|
|
10
|
+
export const ADDON_PRICE_MONTHLY = 50;
|
|
11
|
+
export const ADDON_PRICE_YEARLY = 35;
|
|
12
|
+
|
|
13
|
+
export const STRIPE_MOCK_ACCOUNT_ID = 'acct_1NnHoQG6EyqgvTaj';
|
|
14
|
+
export const STRIPE_MOCK_ACCOUNT_PK =
|
|
15
|
+
'pk_test_51NnHoQG6EyqgvTajznajopWC01AozNtq7zgySeQ1qx4PH9TAXvMj0TnbZvYT3yOt46jbQAcCDs1EU2QKcfG8eEoO00tlW0Jp3r';
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
import {
|
|
3
|
+
BillingPeriod,
|
|
4
|
+
BillingModel,
|
|
5
|
+
Currency,
|
|
6
|
+
BillableFeature,
|
|
7
|
+
DateRange,
|
|
8
|
+
Money,
|
|
9
|
+
Plan,
|
|
10
|
+
PreviewSubscription,
|
|
11
|
+
SubscriptionEstimationAddon,
|
|
12
|
+
SubscriptionPreview,
|
|
13
|
+
} from '../../../../../js-client-sdk';
|
|
14
|
+
import { mockCheckoutState } from './mockCheckoutState';
|
|
15
|
+
|
|
16
|
+
const mockBillingPeriod = (period?: BillingPeriod): DateRange => {
|
|
17
|
+
return {
|
|
18
|
+
start: moment().toDate(),
|
|
19
|
+
end: moment()
|
|
20
|
+
.add(1, period === BillingPeriod.Monthly ? 'month' : 'year')
|
|
21
|
+
.toDate(),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defaultPreviewSubscription = (): SubscriptionPreview => {
|
|
26
|
+
const defaultCost: Money = {
|
|
27
|
+
amount: 0,
|
|
28
|
+
currency: Currency.Usd,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
subTotal: defaultCost,
|
|
33
|
+
total: defaultCost,
|
|
34
|
+
totalExcludingTax: defaultCost,
|
|
35
|
+
billingPeriodRange: mockBillingPeriod(),
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const flatFeeCost = (plan: Plan, billingPeriod: BillingPeriod | undefined) => {
|
|
40
|
+
const filteredPrice = plan.pricePoints?.find(
|
|
41
|
+
(price) => price.billingPeriod === billingPeriod && price.pricingModel === BillingModel.FlatFee,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return filteredPrice?.amount || 0;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const addonCost = (plan: Plan, billingPeriod: BillingPeriod, addonId: string, quantity: number) => {
|
|
48
|
+
const addon = plan.compatibleAddons?.find((addon) => addon.id === addonId);
|
|
49
|
+
|
|
50
|
+
const price = addon?.pricePoints.find((price) => price.billingPeriod === billingPeriod);
|
|
51
|
+
|
|
52
|
+
return (price?.amount || 0) * quantity;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const billableFeatureCost = (plan: Plan, billingPeriod: BillingPeriod, featureId: string, quantity: number) => {
|
|
56
|
+
const price = plan.pricePoints.find(
|
|
57
|
+
(price) => price.feature?.featureId === featureId && price.billingPeriod === billingPeriod,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (!price) return 0;
|
|
61
|
+
|
|
62
|
+
const { tiers } = price;
|
|
63
|
+
|
|
64
|
+
if (tiers) {
|
|
65
|
+
const quantityTier = tiers.find((tier) => tier.upTo >= quantity);
|
|
66
|
+
const priceTier = quantityTier || tiers[tiers.length - 1];
|
|
67
|
+
return quantity * priceTier.unitPrice.amount;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (price?.amount || 0) * quantity;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const mockTotalPrice = (
|
|
74
|
+
plan: Plan,
|
|
75
|
+
billingPeriod: BillingPeriod,
|
|
76
|
+
addons: SubscriptionEstimationAddon[],
|
|
77
|
+
features: BillableFeature[],
|
|
78
|
+
) => {
|
|
79
|
+
const currency = plan.pricePoints?.[0].currency || Currency.Usd;
|
|
80
|
+
|
|
81
|
+
const totalFlatFeeCost = flatFeeCost(plan, billingPeriod);
|
|
82
|
+
const totalFeaturesCost = features.reduce(
|
|
83
|
+
(total, feature) => total + billableFeatureCost(plan, billingPeriod, feature.featureId, feature.quantity || 0),
|
|
84
|
+
0,
|
|
85
|
+
);
|
|
86
|
+
const totalAddonsCost = addons.reduce(
|
|
87
|
+
(total, addon) => total + addonCost(plan, billingPeriod, addon.addonId, addon.quantity || 0),
|
|
88
|
+
0,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const cost: Money = {
|
|
92
|
+
amount: totalFlatFeeCost + totalFeaturesCost + totalAddonsCost,
|
|
93
|
+
currency: currency || Currency.Usd,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
subTotal: cost,
|
|
98
|
+
total: cost,
|
|
99
|
+
totalExcludingTax: cost,
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export function mockPreviewSubscription(input: PreviewSubscription): SubscriptionPreview {
|
|
104
|
+
const { planId, billingPeriod = BillingPeriod.Monthly, billableFeatures: features = [], addons = [] } = input;
|
|
105
|
+
const data = mockCheckoutState({ planId });
|
|
106
|
+
|
|
107
|
+
if (!data || !data.plan) {
|
|
108
|
+
return defaultPreviewSubscription();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const total = mockTotalPrice(data.plan, billingPeriod, addons, features);
|
|
112
|
+
|
|
113
|
+
if (!total) {
|
|
114
|
+
return defaultPreviewSubscription();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
...total,
|
|
119
|
+
billingPeriodRange: mockBillingPeriod(billingPeriod),
|
|
120
|
+
};
|
|
121
|
+
}
|