@stigg/react-sdk 4.4.0-beta.10 → 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/components/DowngradeToFreeContainer.d.ts +3 -7
- package/dist/components/checkout/components/StyledArrow.d.ts +5 -0
- package/dist/components/checkout/hooks/useLoadCheckout.d.ts +3 -1
- package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +8 -5
- package/dist/components/checkout/summary/CheckoutSummary.d.ts +1 -1
- package/dist/components/checkout/summary/components/LineItems.d.ts +6 -6
- package/dist/components/checkout/textOverrides.d.ts +24 -3
- package/dist/react-sdk.cjs.development.js +255 -195
- 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 +261 -211
- 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/components/DowngradeToFreeContainer.tsx +32 -35
- package/src/components/checkout/components/StyledArrow.tsx +9 -0
- package/src/components/checkout/hooks/useLoadCheckout.ts +10 -2
- package/src/components/checkout/hooks/usePreviewSubscription.ts +16 -6
- package/src/components/checkout/planHeader/PlanHeader.tsx +18 -25
- package/src/components/checkout/promotionCode/AddPromotionCode.tsx +2 -1
- package/src/components/checkout/summary/CheckoutSummary.tsx +33 -21
- package/src/components/checkout/summary/components/LineItems.tsx +10 -17
- package/src/components/checkout/textOverrides.ts +21 -4
- 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
- package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +0 -25
- package/src/components/checkout/planHeader/PlanHeader.style.tsx +0 -23
|
@@ -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;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { StyledArrowRightIcon } from '
|
|
2
|
+
import { StyledArrowRightIcon } from './StyledArrow';
|
|
3
3
|
import styled from '@emotion/styled/macro';
|
|
4
4
|
import { Alert, Box } from '@mui/material';
|
|
5
5
|
import { Typography } from '../../common/Typography';
|
|
6
6
|
import { CheckoutStatePlan, Subscription } from '@stigg/js-client-sdk';
|
|
7
|
-
import { Currency, BillingPeriod } from '@stigg/js-client-sdk';
|
|
8
|
-
import { currencyPriceFormatter } from '../../utils/currencyUtils';
|
|
9
7
|
import { CheckoutLocalization } from '../textOverrides';
|
|
10
8
|
import { CheckoutContainerProps } from '../CheckoutContainer';
|
|
11
9
|
import { ChangePlanButton } from './ChangePlanButton';
|
|
@@ -26,40 +24,29 @@ export const DowngradeToFreePlanBox = styled(Box)`
|
|
|
26
24
|
`;
|
|
27
25
|
|
|
28
26
|
export const DowngradeToFreeContent = ({
|
|
27
|
+
headerText,
|
|
29
28
|
planName,
|
|
30
|
-
|
|
31
|
-
billingPeriod,
|
|
29
|
+
priceText,
|
|
32
30
|
}: {
|
|
31
|
+
headerText: string;
|
|
33
32
|
planName: string;
|
|
34
|
-
|
|
35
|
-
amount: number;
|
|
36
|
-
currency: Currency;
|
|
37
|
-
};
|
|
38
|
-
billingPeriod?: BillingPeriod;
|
|
33
|
+
priceText: string;
|
|
39
34
|
}) => {
|
|
40
|
-
const priceText = totalPrice
|
|
41
|
-
? currencyPriceFormatter({ amount: totalPrice.amount, currency: totalPrice.currency })
|
|
42
|
-
: 'Free';
|
|
43
|
-
|
|
44
|
-
const billingPeriodText = billingPeriod ? ` / Paid ${billingPeriod.toLowerCase()}` : '';
|
|
45
35
|
return (
|
|
46
|
-
<DowngradeToFreePlanBox className="stigg-checkout-
|
|
47
|
-
<Typography
|
|
36
|
+
<DowngradeToFreePlanBox className="stigg-checkout-downgrade-to-free-container">
|
|
37
|
+
<Typography
|
|
38
|
+
className="stigg-checkout-downgrade-to-free-text-header"
|
|
39
|
+
style={{ opacity: 0.8 }}
|
|
40
|
+
variant="caption"
|
|
41
|
+
color="disabled">
|
|
42
|
+
{headerText}
|
|
43
|
+
</Typography>
|
|
44
|
+
<Typography className="stigg-checkout-downgrade-to-free-plan-name" bold variant="h3" color="primary">
|
|
48
45
|
{planName}
|
|
49
46
|
</Typography>
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
span
|
|
54
|
-
bold={true}
|
|
55
|
-
variant="h3"
|
|
56
|
-
color="primary">
|
|
57
|
-
{priceText}
|
|
58
|
-
</Typography>
|
|
59
|
-
<Typography className="stigg-checkout-downgrade-to-free-text-billing-period" span color="secondary">
|
|
60
|
-
{billingPeriodText}
|
|
61
|
-
</Typography>
|
|
62
|
-
</div>
|
|
47
|
+
<Typography className="stigg-checkout-downgrade-to-free-price-text" color="secondary">
|
|
48
|
+
{priceText}
|
|
49
|
+
</Typography>
|
|
63
50
|
</DowngradeToFreePlanBox>
|
|
64
51
|
);
|
|
65
52
|
};
|
|
@@ -91,19 +78,25 @@ export const DowngradeToFreePlan = ({
|
|
|
91
78
|
);
|
|
92
79
|
}
|
|
93
80
|
|
|
81
|
+
const paidBillingPeriod =
|
|
82
|
+
activeSubscription.prices.length > 0 ? activeSubscription.prices[0].billingPeriod : undefined;
|
|
83
|
+
|
|
94
84
|
return (
|
|
95
85
|
<>
|
|
96
86
|
<DowngradeToFreeAlert action={alertAction} className="stigg-checkout-downgrade-to-free-alert" severity="info">
|
|
97
87
|
<Typography span color="secondary">
|
|
98
|
-
{checkoutLocalization.
|
|
88
|
+
{checkoutLocalization.downgradeToFree.alertText({ plan: activeSubscription.plan })}
|
|
99
89
|
</Typography>
|
|
100
90
|
</DowngradeToFreeAlert>
|
|
101
91
|
|
|
102
92
|
<DowngradeToFreePlansContainer className="stigg-checkout-downgrade-to-free-plans-container">
|
|
103
93
|
<DowngradeToFreeContent
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
headerText={checkoutLocalization.downgradeToFree.paidPlanHeader({ plan: activeSubscription.plan })}
|
|
95
|
+
planName={checkoutLocalization.downgradeToFree.paidPlanName({ plan: activeSubscription.plan })}
|
|
96
|
+
priceText={checkoutLocalization.downgradeToFree.paidPlanPriceText({
|
|
97
|
+
plan: activeSubscription.plan,
|
|
98
|
+
billingPeriod: paidBillingPeriod,
|
|
99
|
+
})}
|
|
107
100
|
/>
|
|
108
101
|
|
|
109
102
|
<StyledArrowRightIcon
|
|
@@ -111,7 +104,11 @@ export const DowngradeToFreePlan = ({
|
|
|
111
104
|
style={{ margin: 'auto 16px', minWidth: '16px' }}
|
|
112
105
|
/>
|
|
113
106
|
|
|
114
|
-
<DowngradeToFreeContent
|
|
107
|
+
<DowngradeToFreeContent
|
|
108
|
+
headerText={checkoutLocalization.downgradeToFree.freePlanHeader({ plan: freePlan })}
|
|
109
|
+
planName={checkoutLocalization.downgradeToFree.freePlanName({ plan: freePlan })}
|
|
110
|
+
priceText={checkoutLocalization.downgradeToFree.freePlanPriceText({ plan: freePlan })}
|
|
111
|
+
/>
|
|
115
112
|
</DowngradeToFreePlansContainer>
|
|
116
113
|
</>
|
|
117
114
|
);
|
|
@@ -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();
|
|
@@ -84,7 +93,7 @@ export const usePreviewSubscriptionAction = () => {
|
|
|
84
93
|
const previewSubscriptionAction = useCallback(
|
|
85
94
|
async ({ promotionCode }: { promotionCode?: string | null } = {}) => {
|
|
86
95
|
if (!widgetState.isValid) {
|
|
87
|
-
return { subscriptionPreview: null };
|
|
96
|
+
return { subscriptionPreview: null, errorMessage: null };
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
return previewSubscription({
|
|
@@ -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 () => {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import { Divider } from '@mui/material';
|
|
3
|
+
import { Box, Divider } from '@mui/material';
|
|
4
4
|
|
|
5
5
|
import { Typography } from '../../common/Typography';
|
|
6
6
|
import { useCheckoutModel } from '../hooks/useCheckoutModel';
|
|
7
|
-
import { PlanHeaderContainer, PlanPathContainer, StyledArrowRightIcon } from './PlanHeader.style';
|
|
8
7
|
import { CheckoutContainerProps } from '../CheckoutContainer';
|
|
9
8
|
import { ChangePlanButton } from '../components/ChangePlanButton';
|
|
10
9
|
|
|
@@ -14,37 +13,31 @@ type PlanHeaderProps = {
|
|
|
14
13
|
|
|
15
14
|
export function PlanHeader({ allowChangePlan = false, onChangePlan }: PlanHeaderProps) {
|
|
16
15
|
const { checkoutState, checkoutLocalization } = useCheckoutModel();
|
|
17
|
-
const { plan
|
|
18
|
-
const isPlanChanged = plan?.id !== activeSubscription?.plan.id;
|
|
16
|
+
const { plan } = checkoutState || {};
|
|
19
17
|
|
|
20
18
|
return (
|
|
21
19
|
<>
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<Typography variant="h6" color="secondary">
|
|
27
|
-
{activeSubscription.plan.displayName}
|
|
28
|
-
</Typography>
|
|
29
|
-
<StyledArrowRightIcon />
|
|
30
|
-
</>
|
|
31
|
-
)}
|
|
20
|
+
<Box sx={{ marginBottom: '16px' }}>
|
|
21
|
+
<Typography variant="body1" color="disabled" style={{ opacity: 0.6, marginBottom: '8px' }}>
|
|
22
|
+
Selected plan
|
|
23
|
+
</Typography>
|
|
32
24
|
|
|
25
|
+
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
33
26
|
<Typography variant="h3" bold>
|
|
34
27
|
{plan?.displayName}
|
|
35
28
|
</Typography>
|
|
36
|
-
</PlanPathContainer>
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
30
|
+
{allowChangePlan && onChangePlan && (
|
|
31
|
+
<ChangePlanButton
|
|
32
|
+
onClick={() => {
|
|
33
|
+
onChangePlan({ currentPlan: plan });
|
|
34
|
+
}}
|
|
35
|
+
checkoutLocalization={checkoutLocalization}
|
|
36
|
+
size="medium"
|
|
37
|
+
/>
|
|
38
|
+
)}
|
|
39
|
+
</Box>
|
|
40
|
+
</Box>
|
|
48
41
|
<Divider className="stigg-checkout-plan-header-divider" />
|
|
49
42
|
</>
|
|
50
43
|
);
|
|
@@ -36,7 +36,7 @@ export const AddPromotionCode = ({ checkoutLocalization }: { checkoutLocalizatio
|
|
|
36
36
|
if (!errorMessage && subscriptionPreview?.discount) {
|
|
37
37
|
persistPromotionCode(promotionCode.toUpperCase());
|
|
38
38
|
setShowInput(false);
|
|
39
|
-
} else if (
|
|
39
|
+
} else if (errorMessage) {
|
|
40
40
|
setErrorMessage(errorMessage);
|
|
41
41
|
}
|
|
42
42
|
setIsLoading(false);
|
|
@@ -62,6 +62,7 @@ export const AddPromotionCode = ({ checkoutLocalization }: { checkoutLocalizatio
|
|
|
62
62
|
setPromotionCode(e.target.value);
|
|
63
63
|
}}
|
|
64
64
|
inputProps={{ maxLength: 20 }}
|
|
65
|
+
// eslint-disable-next-line react/jsx-no-duplicate-props
|
|
65
66
|
InputProps={{
|
|
66
67
|
endAdornment: (
|
|
67
68
|
<CouponCodeAddButton variant="contained" disabled={isLoading} onClick={handlePromotionCode}>
|
|
@@ -44,6 +44,7 @@ SummaryCard.defaultProps = {
|
|
|
44
44
|
|
|
45
45
|
const PlanName = styled(Typography)`
|
|
46
46
|
margin-bottom: 16px;
|
|
47
|
+
font-weight: 500;
|
|
47
48
|
`;
|
|
48
49
|
|
|
49
50
|
const StyledDivider = styled(Divider)`
|
|
@@ -90,6 +91,7 @@ export const CheckoutSummary = ({
|
|
|
90
91
|
disablePromotionCode,
|
|
91
92
|
disableSuccessAnimation,
|
|
92
93
|
isFreeDowngrade,
|
|
94
|
+
onMockCheckoutPreview,
|
|
93
95
|
}: CheckoutContainerProps & { isFreeDowngrade: boolean }) => {
|
|
94
96
|
const [isCheckoutCompletedSuccessfully, setIsCheckoutCompletedSuccessfully] = useState(false);
|
|
95
97
|
const { setErrorMessage } = usePaymentStepModel();
|
|
@@ -104,7 +106,7 @@ export const CheckoutSummary = ({
|
|
|
104
106
|
const [baseCharge] = baseCharges || [];
|
|
105
107
|
const isLastStep = isFreeDowngrade || (progressBar.isCheckoutComplete && progressBar.isLastStep);
|
|
106
108
|
|
|
107
|
-
const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription();
|
|
109
|
+
const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription({ onMockCheckoutPreview });
|
|
108
110
|
|
|
109
111
|
const { handleSubmit, isLoading } = useSubmit({
|
|
110
112
|
disableSuccessAnimation,
|
|
@@ -142,6 +144,14 @@ export const CheckoutSummary = ({
|
|
|
142
144
|
}
|
|
143
145
|
};
|
|
144
146
|
|
|
147
|
+
const showPromotionCodeLine = !disablePromotionCode && !isFreeDowngrade;
|
|
148
|
+
const showDiscountLine = !!subscriptionPreview?.subTotal && !!subscriptionPreview?.discount && !isFreeDowngrade;
|
|
149
|
+
const showTaxLine =
|
|
150
|
+
!!subscriptionPreview?.taxDetails && !!subscriptionPreview?.tax && subscriptionPreview?.tax.amount > 0;
|
|
151
|
+
const showAppliedCreditsLine = !!subscriptionPreview?.credits && subscriptionPreview?.credits.used.amount > 0;
|
|
152
|
+
|
|
153
|
+
const showAdditionalDivider = showPromotionCodeLine || showDiscountLine || showTaxLine || showAppliedCreditsLine;
|
|
154
|
+
|
|
145
155
|
return (
|
|
146
156
|
<Box flex={1}>
|
|
147
157
|
<SummaryCard>
|
|
@@ -150,7 +160,7 @@ export const CheckoutSummary = ({
|
|
|
150
160
|
{baseCharge && (
|
|
151
161
|
<LineItemContainer>
|
|
152
162
|
<LineItemRow>
|
|
153
|
-
<Typography variant="
|
|
163
|
+
<Typography variant="body1" color="secondary">
|
|
154
164
|
{typeof checkoutLocalization.baseChargeText === 'function'
|
|
155
165
|
? checkoutLocalization.baseChargeText({ billingPeriod: subscription.billingPeriod })
|
|
156
166
|
: checkoutLocalization.baseChargeText}
|
|
@@ -217,30 +227,32 @@ export const CheckoutSummary = ({
|
|
|
217
227
|
|
|
218
228
|
<StyledDivider className="stigg-checkout-summary-divider" />
|
|
219
229
|
|
|
220
|
-
{
|
|
221
|
-
<>
|
|
222
|
-
<PromotionCodeSection checkoutLocalization={checkoutLocalization} />
|
|
230
|
+
{showPromotionCodeLine && <PromotionCodeSection checkoutLocalization={checkoutLocalization} />}
|
|
223
231
|
|
|
224
|
-
|
|
225
|
-
|
|
232
|
+
{showDiscountLine && (
|
|
233
|
+
<DiscountLineItem
|
|
234
|
+
subscriptionPreview={subscriptionPreview!}
|
|
235
|
+
isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
|
|
236
|
+
/>
|
|
226
237
|
)}
|
|
227
238
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
{showTaxLine && (
|
|
240
|
+
<TaxLineItem
|
|
241
|
+
subscriptionPreview={subscriptionPreview!}
|
|
242
|
+
isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
|
|
243
|
+
checkoutLocalization={checkoutLocalization}
|
|
244
|
+
/>
|
|
245
|
+
)}
|
|
232
246
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
247
|
+
{showAppliedCreditsLine && (
|
|
248
|
+
<AppliedCreditsLineItem
|
|
249
|
+
subscriptionPreview={subscriptionPreview!}
|
|
250
|
+
isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
|
|
251
|
+
checkoutLocalization={checkoutLocalization}
|
|
252
|
+
/>
|
|
253
|
+
)}
|
|
238
254
|
|
|
239
|
-
<
|
|
240
|
-
subscriptionPreview={subscriptionPreview}
|
|
241
|
-
isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
|
|
242
|
-
checkoutLocalization={checkoutLocalization}
|
|
243
|
-
/>
|
|
255
|
+
{showAdditionalDivider && <StyledDivider className="stigg-checkout-summary-divider" />}
|
|
244
256
|
|
|
245
257
|
<LineItemContainer>
|
|
246
258
|
<LineItemRow>
|
|
@@ -52,7 +52,7 @@ export const BilledPriceLineItem = ({ label, quantity, price }: { label: string;
|
|
|
52
52
|
<LineItemContainer>
|
|
53
53
|
<LineItemRow style={{ alignItems: 'flex-end' }}>
|
|
54
54
|
<Grid item>
|
|
55
|
-
<Typography variant="
|
|
55
|
+
<Typography variant="body1" color="secondary">
|
|
56
56
|
{label}
|
|
57
57
|
</Typography>
|
|
58
58
|
{(quantity > 1 || billingPeriod === BillingPeriod.Annually) && (
|
|
@@ -75,13 +75,11 @@ export const DiscountLineItem = ({
|
|
|
75
75
|
subscriptionPreview,
|
|
76
76
|
isFetchingSubscriptionPreview,
|
|
77
77
|
}: {
|
|
78
|
-
subscriptionPreview: SubscriptionPreview
|
|
78
|
+
subscriptionPreview: SubscriptionPreview;
|
|
79
79
|
isFetchingSubscriptionPreview: boolean;
|
|
80
80
|
}) => {
|
|
81
|
-
const { subTotal
|
|
82
|
-
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
81
|
+
const { subTotal } = subscriptionPreview;
|
|
82
|
+
const discount = subscriptionPreview.discount!;
|
|
85
83
|
|
|
86
84
|
let discountAmount: number;
|
|
87
85
|
if (discount.type === DiscountType.Percentage) {
|
|
@@ -113,14 +111,11 @@ export const AppliedCreditsLineItem = ({
|
|
|
113
111
|
isFetchingSubscriptionPreview,
|
|
114
112
|
checkoutLocalization,
|
|
115
113
|
}: {
|
|
116
|
-
subscriptionPreview: SubscriptionPreview
|
|
114
|
+
subscriptionPreview: SubscriptionPreview;
|
|
117
115
|
isFetchingSubscriptionPreview: boolean;
|
|
118
116
|
checkoutLocalization: CheckoutLocalization;
|
|
119
117
|
}) => {
|
|
120
|
-
const { credits } = subscriptionPreview
|
|
121
|
-
if (!credits || credits.used.amount <= 0) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
118
|
+
const { credits } = subscriptionPreview;
|
|
124
119
|
|
|
125
120
|
return (
|
|
126
121
|
<LineItemContainer>
|
|
@@ -130,7 +125,7 @@ export const AppliedCreditsLineItem = ({
|
|
|
130
125
|
</Typography>
|
|
131
126
|
<Typography variant="body1" color="secondary">
|
|
132
127
|
<WithSkeleton isLoading={isFetchingSubscriptionPreview}>
|
|
133
|
-
{currencyPriceFormatter({ amount: -1 * credits
|
|
128
|
+
{currencyPriceFormatter({ amount: -1 * credits!.used.amount, currency: credits!.used.currency })}
|
|
134
129
|
</WithSkeleton>
|
|
135
130
|
</Typography>
|
|
136
131
|
</LineItemRow>
|
|
@@ -143,14 +138,12 @@ export const TaxLineItem = ({
|
|
|
143
138
|
isFetchingSubscriptionPreview,
|
|
144
139
|
checkoutLocalization,
|
|
145
140
|
}: {
|
|
146
|
-
subscriptionPreview: SubscriptionPreview
|
|
141
|
+
subscriptionPreview: SubscriptionPreview;
|
|
147
142
|
isFetchingSubscriptionPreview: boolean;
|
|
148
143
|
checkoutLocalization: CheckoutLocalization;
|
|
149
144
|
}) => {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
145
|
+
const tax = subscriptionPreview.tax!;
|
|
146
|
+
const taxDetails = subscriptionPreview.taxDetails!;
|
|
154
147
|
|
|
155
148
|
return (
|
|
156
149
|
<LineItemContainer>
|