@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.
Files changed (38) hide show
  1. package/dist/components/checkout/Checkout.d.ts +1 -1
  2. package/dist/components/checkout/CheckoutContainer.d.ts +4 -2
  3. package/dist/components/checkout/CheckoutProvider.d.ts +4 -2
  4. package/dist/components/checkout/components/DowngradeToFreeContainer.d.ts +3 -7
  5. package/dist/components/checkout/components/StyledArrow.d.ts +5 -0
  6. package/dist/components/checkout/hooks/useLoadCheckout.d.ts +3 -1
  7. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +8 -5
  8. package/dist/components/checkout/summary/CheckoutSummary.d.ts +1 -1
  9. package/dist/components/checkout/summary/components/LineItems.d.ts +6 -6
  10. package/dist/components/checkout/textOverrides.d.ts +24 -3
  11. package/dist/react-sdk.cjs.development.js +255 -195
  12. package/dist/react-sdk.cjs.development.js.map +1 -1
  13. package/dist/react-sdk.cjs.production.min.js +1 -1
  14. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  15. package/dist/react-sdk.esm.js +261 -211
  16. package/dist/react-sdk.esm.js.map +1 -1
  17. package/dist/stories/mocks/checkout/consts.d.ts +11 -0
  18. package/dist/stories/mocks/checkout/mockCheckoutPreview.d.ts +2 -0
  19. package/dist/stories/mocks/checkout/mockCheckoutState.d.ts +2 -0
  20. package/package.json +1 -1
  21. package/src/components/checkout/Checkout.tsx +3 -1
  22. package/src/components/checkout/CheckoutContainer.tsx +21 -2
  23. package/src/components/checkout/CheckoutProvider.tsx +6 -2
  24. package/src/components/checkout/components/DowngradeToFreeContainer.tsx +32 -35
  25. package/src/components/checkout/components/StyledArrow.tsx +9 -0
  26. package/src/components/checkout/hooks/useLoadCheckout.ts +10 -2
  27. package/src/components/checkout/hooks/usePreviewSubscription.ts +16 -6
  28. package/src/components/checkout/planHeader/PlanHeader.tsx +18 -25
  29. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +2 -1
  30. package/src/components/checkout/summary/CheckoutSummary.tsx +33 -21
  31. package/src/components/checkout/summary/components/LineItems.tsx +10 -17
  32. package/src/components/checkout/textOverrides.ts +21 -4
  33. package/src/stories/Checkout.stories.tsx +32 -6
  34. package/src/stories/mocks/checkout/consts.ts +15 -0
  35. package/src/stories/mocks/checkout/mockCheckoutPreview.ts +121 -0
  36. package/src/stories/mocks/checkout/mockCheckoutState.ts +206 -0
  37. package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +0 -25
  38. 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";
@@ -0,0 +1,2 @@
1
+ import { PreviewSubscription, SubscriptionPreview } from '../../../../../js-client-sdk';
2
+ export declare function mockPreviewSubscription(input: PreviewSubscription): SubscriptionPreview;
@@ -0,0 +1,2 @@
1
+ import { GetCheckoutState, GetCheckoutStateResults } from '../../../../../js-client-sdk';
2
+ export declare function mockCheckoutState(params: GetCheckoutState): GetCheckoutStateResults;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.4.0-beta.10",
2
+ "version": "4.4.0-beta.12",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -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 { ApplySubscription, BillingAddress, CheckoutStatePlan, PricingType } from '@stigg/js-client-sdk';
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
- clientSecret: setupIntentClientSecret,
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 '../planHeader/PlanHeader.style';
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
- totalPrice,
31
- billingPeriod,
29
+ priceText,
32
30
  }: {
31
+ headerText: string;
33
32
  planName: string;
34
- totalPrice?: {
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-free-downgrade-plan-box">
47
- <Typography className="stigg-checkout-downgrade-to-free-text-plan" color="secondary">
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
- <div>
51
- <Typography
52
- className="stigg-checkout-downgrade-to-free-text-price"
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.downgradeToFreeAlertText({ plan: activeSubscription.plan })}
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
- planName={activeSubscription.plan.displayName}
105
- totalPrice={activeSubscription.totalPrice?.total}
106
- billingPeriod={activeSubscription.prices[0].billingPeriod}
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 planName={freePlan.displayName} />
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
  );
@@ -0,0 +1,9 @@
1
+ import styled from '@emotion/styled/macro';
2
+
3
+ import ArrowRightIcon from '../../../assets/arrow-right.svg';
4
+
5
+ export const StyledArrowRightIcon = styled(ArrowRightIcon)`
6
+ path {
7
+ stroke: ${({ theme }) => theme.stigg.palette.text.secondary};
8
+ }
9
+ `;
@@ -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 = await stigg.previewSubscription(previewSubscriptionProps);
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, activeSubscription } = checkoutState || {};
18
- const isPlanChanged = plan?.id !== activeSubscription?.plan.id;
16
+ const { plan } = checkoutState || {};
19
17
 
20
18
  return (
21
19
  <>
22
- <PlanHeaderContainer>
23
- <PlanPathContainer>
24
- {activeSubscription && isPlanChanged && (
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
- {allowChangePlan && onChangePlan && (
39
- <ChangePlanButton
40
- onClick={() => {
41
- onChangePlan({ currentPlan: plan });
42
- }}
43
- checkoutLocalization={checkoutLocalization}
44
- size="medium"
45
- />
46
- )}
47
- </PlanHeaderContainer>
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 (!!errorMessage) {
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="h6" color="primary">
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
- {!disablePromotionCode && !isFreeDowngrade && (
221
- <>
222
- <PromotionCodeSection checkoutLocalization={checkoutLocalization} />
230
+ {showPromotionCodeLine && <PromotionCodeSection checkoutLocalization={checkoutLocalization} />}
223
231
 
224
- <StyledDivider className="stigg-checkout-summary-divider" />
225
- </>
232
+ {showDiscountLine && (
233
+ <DiscountLineItem
234
+ subscriptionPreview={subscriptionPreview!}
235
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
236
+ />
226
237
  )}
227
238
 
228
- <DiscountLineItem
229
- subscriptionPreview={subscriptionPreview}
230
- isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
231
- />
239
+ {showTaxLine && (
240
+ <TaxLineItem
241
+ subscriptionPreview={subscriptionPreview!}
242
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
243
+ checkoutLocalization={checkoutLocalization}
244
+ />
245
+ )}
232
246
 
233
- <TaxLineItem
234
- subscriptionPreview={subscriptionPreview}
235
- isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
236
- checkoutLocalization={checkoutLocalization}
237
- />
247
+ {showAppliedCreditsLine && (
248
+ <AppliedCreditsLineItem
249
+ subscriptionPreview={subscriptionPreview!}
250
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
251
+ checkoutLocalization={checkoutLocalization}
252
+ />
253
+ )}
238
254
 
239
- <AppliedCreditsLineItem
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="h6" color="primary">
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 | null;
78
+ subscriptionPreview: SubscriptionPreview;
79
79
  isFetchingSubscriptionPreview: boolean;
80
80
  }) => {
81
- const { subTotal, discount } = subscriptionPreview || {};
82
- if (!subTotal || !discount) {
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 | null;
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.used.amount, currency: credits.used.currency })}
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 | null;
141
+ subscriptionPreview: SubscriptionPreview;
147
142
  isFetchingSubscriptionPreview: boolean;
148
143
  checkoutLocalization: CheckoutLocalization;
149
144
  }) => {
150
- const { tax, taxDetails } = subscriptionPreview || {};
151
- if (!taxDetails || !tax) {
152
- return null;
153
- }
145
+ const tax = subscriptionPreview.tax!;
146
+ const taxDetails = subscriptionPreview.taxDetails!;
154
147
 
155
148
  return (
156
149
  <LineItemContainer>