@stigg/react-sdk 4.4.0-beta.1 → 4.4.0-beta.10

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 (91) hide show
  1. package/dist/components/checkout/Checkout.d.ts +1 -1
  2. package/dist/components/checkout/CheckoutContainer.d.ts +7 -2
  3. package/dist/components/checkout/CheckoutProvider.d.ts +3 -1
  4. package/dist/components/checkout/components/Button.d.ts +0 -1
  5. package/dist/components/checkout/components/ChangePlanButton.d.ts +8 -0
  6. package/dist/components/checkout/components/DowngradeToFreeContainer.d.ts +32 -0
  7. package/dist/components/checkout/hooks/useCheckoutModel.d.ts +2 -0
  8. package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +8 -2
  9. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +10 -1
  10. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +3 -0
  11. package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +2 -1
  12. package/dist/components/checkout/index.d.ts +2 -0
  13. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +3 -2
  14. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +3 -2
  15. package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -1
  16. package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -1
  17. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +4 -0
  18. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +4 -3
  19. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +1 -0
  20. package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +6 -1
  21. package/dist/components/checkout/summary/CheckoutSuccess.d.ts +4 -1
  22. package/dist/components/checkout/summary/CheckoutSummary.d.ts +3 -1
  23. package/dist/components/checkout/summary/components/CheckoutCaptions.d.ts +2 -1
  24. package/dist/components/checkout/summary/components/LineItems.d.ts +2 -2
  25. package/dist/components/checkout/textOverrides.d.ts +7 -3
  26. package/dist/components/checkout/theme.d.ts +0 -1
  27. package/dist/components/checkout/types.d.ts +7 -0
  28. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.style.d.ts +1 -1
  29. package/dist/components/paywall/paywallTextOverrides.d.ts +4 -0
  30. package/dist/components/utils/getPaidPriceText.d.ts +3 -1
  31. package/dist/react-sdk.cjs.development.js +1147 -524
  32. package/dist/react-sdk.cjs.development.js.map +1 -1
  33. package/dist/react-sdk.cjs.production.min.js +1 -1
  34. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  35. package/dist/react-sdk.esm.js +1181 -532
  36. package/dist/react-sdk.esm.js.map +1 -1
  37. package/dist/theme/getResolvedTheme.d.ts +1 -0
  38. package/dist/theme/types.d.ts +1 -0
  39. package/package.json +2 -2
  40. package/src/assets/payment-method.svg +3 -10
  41. package/src/components/checkout/Checkout.tsx +2 -1
  42. package/src/components/checkout/CheckoutContainer.style.ts +1 -0
  43. package/src/components/checkout/CheckoutContainer.tsx +59 -28
  44. package/src/components/checkout/CheckoutProvider.tsx +18 -18
  45. package/src/components/checkout/components/Button.tsx +19 -35
  46. package/src/components/checkout/components/ChangePlanButton.tsx +32 -0
  47. package/src/components/checkout/components/DowngradeToFreeContainer.tsx +118 -0
  48. package/src/components/checkout/components/Skeletons.style.ts +4 -1
  49. package/src/components/checkout/hooks/useCheckoutModel.ts +12 -2
  50. package/src/components/checkout/hooks/usePaymentStepModel.ts +22 -3
  51. package/src/components/checkout/hooks/usePlanStepModel.ts +25 -10
  52. package/src/components/checkout/hooks/usePreviewSubscription.ts +112 -40
  53. package/src/components/checkout/hooks/useProgressBarModel.ts +18 -0
  54. package/src/components/checkout/hooks/useSubscriptionModel.ts +8 -2
  55. package/src/components/checkout/hooks/useSubscriptionState.ts +2 -1
  56. package/src/components/checkout/index.ts +2 -0
  57. package/src/components/checkout/planHeader/PlanHeader.style.tsx +1 -1
  58. package/src/components/checkout/planHeader/PlanHeader.tsx +7 -15
  59. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +6 -3
  60. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +13 -9
  61. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +6 -7
  62. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +58 -11
  63. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +1 -0
  64. package/src/components/checkout/steps/payment/PaymentMethods.tsx +13 -6
  65. package/src/components/checkout/steps/payment/PaymentStep.tsx +3 -1
  66. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +35 -4
  67. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +4 -3
  68. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +61 -48
  69. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +27 -6
  70. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +26 -5
  71. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +62 -12
  72. package/src/components/checkout/summary/CheckoutSuccess.tsx +52 -6
  73. package/src/components/checkout/summary/CheckoutSummary.tsx +48 -33
  74. package/src/components/checkout/summary/components/CheckoutCaptions.tsx +30 -29
  75. package/src/components/checkout/summary/components/LineItems.tsx +8 -16
  76. package/src/components/checkout/textOverrides.ts +15 -12
  77. package/src/components/checkout/theme.ts +0 -4
  78. package/src/components/checkout/types.ts +9 -0
  79. package/src/components/common/Icon.tsx +4 -6
  80. package/src/components/common/mapExternalTheme.ts +1 -2
  81. package/src/components/paywall/PlanPrice.tsx +10 -2
  82. package/src/components/paywall/paywallTextOverrides.ts +3 -0
  83. package/src/components/utils/getPaidPriceText.ts +8 -2
  84. package/src/components/utils/getPlanPrice.ts +1 -1
  85. package/src/stories/Checkout.stories.tsx +6 -5
  86. package/src/theme/Theme.tsx +10 -1
  87. package/src/theme/getResolvedTheme.ts +1 -0
  88. package/src/theme/types.ts +1 -0
  89. package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +0 -2
  90. package/src/assets/nyancat.svg +0 -634
  91. package/src/components/checkout/steps/surprise/SurpriseStep.tsx +0 -27
@@ -4,6 +4,7 @@ export declare const getResolvedTheme: (customizedTheme?: {
4
4
  palette?: {
5
5
  primary?: string | undefined;
6
6
  primaryDark?: string | undefined;
7
+ primaryLight?: string | undefined;
7
8
  backgroundPaper?: string | undefined;
8
9
  backgroundHighlight?: string | undefined;
9
10
  backgroundSection?: string | undefined;
@@ -9,6 +9,7 @@ export declare type StiggTheme = {
9
9
  palette: {
10
10
  primary: string;
11
11
  primaryDark: string;
12
+ primaryLight: string;
12
13
  backgroundPaper: string;
13
14
  backgroundHighlight: string;
14
15
  backgroundSection: string;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.4.0-beta.1",
2
+ "version": "4.4.0-beta.10",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -101,7 +101,7 @@
101
101
  "@emotion/react": "^11.10.5",
102
102
  "@emotion/styled": "^11.10.5",
103
103
  "@mui/material": "^5.10.13",
104
- "@stigg/js-client-sdk": "2.21.0",
104
+ "@stigg/js-client-sdk": "2.23.0",
105
105
  "@stripe/react-stripe-js": "^2.1.1",
106
106
  "@stripe/stripe-js": "^1.54.1",
107
107
  "@types/styled-components": "^5.1.26",
@@ -1,11 +1,4 @@
1
- <svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <g clip-path="url(#clip0_239_13697)">
3
- <path d="M22 0H2C0.89543 0 0 0.89543 0 2V14C0 15.1046 0.89543 16 2 16H22C23.1046 16 24 15.1046 24 14V2C24 0.89543 23.1046 0 22 0Z" fill="#C6C6C7"/>
4
- </g>
5
- <path opacity="0.3" d="M18.75 12.4286H16.5C16.0125 12.4286 15.75 12.2 15.75 11.6667C15.75 11.1334 16.0125 10.9048 16.5 10.9048H18.75C19.2375 10.9048 19.5 11.1334 19.5 11.6667C19.5 12.2 19.2375 12.4286 18.75 12.4286ZM14.25 12.4286H12C11.5125 12.4286 11.25 12.2 11.25 11.6667C11.25 11.1334 11.5125 10.9048 12 10.9048H14.25C14.7375 10.9048 15 11.1334 15 11.6667C15 12.2 14.7375 12.4286 14.25 12.4286ZM9.75 12.4286H7.5C7.0125 12.4286 6.75 12.2 6.75 11.6667C6.75 11.1334 7.0125 10.9048 7.5 10.9048H9.75C10.2375 10.9048 10.5 11.1334 10.5 11.6667C10.5 12.2 10.2375 12.4286 9.75 12.4286ZM5.25 12.4286H3C2.5125 12.4286 2.25 12.2 2.25 11.6667C2.25 11.1334 2.5125 10.9048 3 10.9048H5.25C5.7375 10.9048 6 11.1334 6 11.6667C6 12.2 5.7375 12.4286 5.25 12.4286Z" fill="black"/>
6
- <defs>
7
- <clipPath id="clip0_239_13697">
8
- <rect width="24" height="16" fill="white"/>
9
- </clipPath>
10
- </defs>
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M21.1667 4H2.83333C1.82081 4 1 4.89543 1 6V18C1 19.1046 1.82081 20 2.83333 20H21.1667C22.1792 20 23 19.1046 23 18V6C23 4.89543 22.1792 4 21.1667 4Z" fill="#C6C6C7"/>
3
+ <path opacity="0.3" d="M19.75 16.4286H17.5C17.0125 16.4286 16.75 16.2 16.75 15.6667C16.75 15.1334 17.0125 14.9048 17.5 14.9048H19.75C20.2375 14.9048 20.5 15.1334 20.5 15.6667C20.5 16.2 20.2375 16.4286 19.75 16.4286ZM15.25 16.4286H13C12.5125 16.4286 12.25 16.2 12.25 15.6667C12.25 15.1334 12.5125 14.9048 13 14.9048H15.25C15.7375 14.9048 16 15.1334 16 15.6667C16 16.2 15.7375 16.4286 15.25 16.4286ZM10.75 16.4286H8.5C8.0125 16.4286 7.75 16.2 7.75 15.6667C7.75 15.1334 8.0125 14.9048 8.5 14.9048H10.75C11.2375 14.9048 11.5 15.1334 11.5 15.6667C11.5 16.2 11.2375 16.4286 10.75 16.4286ZM6.25 16.4286H4C3.5125 16.4286 3.25 16.2 3.25 15.6667C3.25 15.1334 3.5125 14.9048 4 14.9048H6.25C6.7375 14.9048 7 15.1334 7 15.6667C7 16.2 6.7375 16.4286 6.25 16.4286Z" fill="black"/>
11
4
  </svg>
@@ -12,6 +12,7 @@ export const Checkout = ({
12
12
  preferredBillingPeriod,
13
13
  billingCountryCode,
14
14
  billableFeatures,
15
+ billingInformation,
15
16
  ...containerProps
16
17
  }: CheckoutProps) => {
17
18
  return (
@@ -23,7 +24,7 @@ export const Checkout = ({
23
24
  preferredBillingPeriod={preferredBillingPeriod}
24
25
  billingCountryCode={billingCountryCode}
25
26
  billableFeatures={billableFeatures}
26
- >
27
+ billingInformation={billingInformation}>
27
28
  <CheckoutContainer {...containerProps} />
28
29
  </CheckoutProvider>
29
30
  );
@@ -4,6 +4,7 @@ import Box from '@mui/material/Box';
4
4
  export const CheckoutLayout = styled.div`
5
5
  margin: auto;
6
6
  width: 100%;
7
+ min-height: 760px;
7
8
  max-width: 920px;
8
9
  display: flex;
9
10
  position: relative;
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  import { Elements } from '@stripe/react-stripe-js';
3
- import { ApplySubscription, CheckoutStatePlan } from '@stigg/js-client-sdk';
3
+ import { ApplySubscription, BillingAddress, CheckoutStatePlan, PricingType } from '@stigg/js-client-sdk';
4
4
  import { CheckoutContent, CheckoutLayout, CheckoutPanel } from './CheckoutContainer.style';
5
5
  import { CheckoutProgressBar } from './progressBar/CheckoutProgressBar';
6
6
  import { CheckoutSummary, CheckoutSummarySkeleton } from './summary';
7
- import { useProgressBarModel } from './hooks';
7
+ import { CheckoutStep, CheckoutStepKey, useCheckoutModel, useProgressBarModel } from './hooks';
8
8
  import { PlanHeader } from './planHeader';
9
9
  import { CheckoutAddonsStep } from './steps/addons';
10
10
  import { PaymentStep } from './steps/payment';
@@ -12,22 +12,24 @@ import { useStripeIntegration } from './steps/payment/stripe';
12
12
  import { CheckoutPlanStep } from './steps/plan';
13
13
  import { useCheckoutContext } from './CheckoutProvider';
14
14
  import { ContentLoadingSkeleton } from './components';
15
-
16
- // import { SurpriseStep } from './steps/surprise/SurpriseStep';
15
+ import { DowngradeToFreePlan } from './components/DowngradeToFreeContainer';
17
16
 
18
17
  type StepProps = {
19
18
  allowChangePlan?: boolean;
20
19
  content: React.ReactNode;
21
20
  };
22
21
 
23
- const getStepProps = (step: number): StepProps => {
24
- switch (step) {
25
- case 0:
22
+ const getStepProps = (
23
+ currentStep: CheckoutStep,
24
+ { onBillingAddressChange }: Pick<CheckoutContainerProps, 'onBillingAddressChange'>,
25
+ ): StepProps => {
26
+ switch (currentStep.key) {
27
+ case CheckoutStepKey.PLAN:
26
28
  return { allowChangePlan: true, content: <CheckoutPlanStep /> };
27
- case 1:
29
+ case CheckoutStepKey.ADDONS:
28
30
  return { content: <CheckoutAddonsStep /> };
29
- case 2:
30
- return { content: <PaymentStep /> };
31
+ case CheckoutStepKey.PAYMENT:
32
+ return { content: <PaymentStep onBillingAddressChange={onBillingAddressChange} /> };
31
33
  default:
32
34
  return { content: null };
33
35
  }
@@ -43,26 +45,51 @@ export type CheckoutContainerProps = {
43
45
  onCheckout?: (params: OnCheckoutParams) => Promise<CheckoutResult>;
44
46
  onCheckoutCompleted: (params: OnCheckoutCompletedParams) => Promise<void>;
45
47
  onChangePlan?: (params: { currentPlan: CheckoutStatePlan | undefined }) => void;
48
+ onBillingAddressChange?: (params: { billingAddress: BillingAddress }) => Promise<void>;
49
+ disablePromotionCode?: boolean;
50
+ disableSuccessAnimation?: boolean;
46
51
  };
47
52
 
48
- export function CheckoutContainer({ onCheckout, onCheckoutCompleted, onChangePlan }: CheckoutContainerProps) {
53
+ export function CheckoutContainer({
54
+ onCheckout,
55
+ onCheckoutCompleted,
56
+ onChangePlan,
57
+ onBillingAddressChange,
58
+ disablePromotionCode,
59
+ disableSuccessAnimation,
60
+ }: CheckoutContainerProps) {
49
61
  const { stripePromise, setupIntentClientSecret } = useStripeIntegration();
50
62
  const [{ stiggTheme, widgetState }] = useCheckoutContext();
51
- const { progressBarState } = useProgressBarModel();
52
- const { activeStep } = progressBarState;
63
+ const { currentStep } = useProgressBarModel();
64
+
53
65
  const { isLoadingCheckoutData } = widgetState;
54
66
 
55
- // uncomment for fun!
56
- // if (activeStep > 2) {
57
- // return <SurpriseStep />;
58
- // }
67
+ const { checkoutState, checkoutLocalization } = useCheckoutModel();
68
+ const { plan, activeSubscription } = checkoutState || {};
69
+ const isFreeDowngrade =
70
+ !!plan &&
71
+ plan.pricingType === PricingType.Free &&
72
+ !!activeSubscription &&
73
+ activeSubscription.pricingType !== PricingType.Free;
59
74
 
60
- const { content, allowChangePlan } = getStepProps(activeStep);
75
+ const { content, allowChangePlan } = getStepProps(currentStep, { onBillingAddressChange });
61
76
 
62
77
  const checkoutContent = (
63
78
  <>
64
- <PlanHeader allowChangePlan={allowChangePlan} onChangePlan={onChangePlan} />
65
- {content}
79
+ {isFreeDowngrade ? (
80
+ <DowngradeToFreePlan
81
+ checkoutLocalization={checkoutLocalization}
82
+ freePlan={plan!}
83
+ activeSubscription={activeSubscription!}
84
+ allowChangePlan={allowChangePlan}
85
+ onChangePlan={onChangePlan}
86
+ />
87
+ ) : (
88
+ <>
89
+ <PlanHeader allowChangePlan={allowChangePlan} onChangePlan={onChangePlan} />
90
+ {content}
91
+ </>
92
+ )}
66
93
  </>
67
94
  );
68
95
 
@@ -82,15 +109,19 @@ export function CheckoutContainer({ onCheckout, onCheckoutCompleted, onChangePla
82
109
  },
83
110
  }}>
84
111
  <CheckoutLayout className="stigg-checkout-layout">
85
- <CheckoutProgressBar />
112
+ {!isFreeDowngrade && <CheckoutProgressBar />}
86
113
  <CheckoutContent>
87
- <CheckoutPanel>
88
- {isLoadingCheckoutData && <ContentLoadingSkeleton />}
89
- {!isLoadingCheckoutData && checkoutContent}
90
- </CheckoutPanel>
91
- {isLoadingCheckoutData && <CheckoutSummarySkeleton />}
92
- {!isLoadingCheckoutData && (
93
- <CheckoutSummary onCheckout={onCheckout} onCheckoutCompleted={onCheckoutCompleted} />
114
+ <CheckoutPanel>{isLoadingCheckoutData ? <ContentLoadingSkeleton /> : checkoutContent}</CheckoutPanel>
115
+ {isLoadingCheckoutData ? (
116
+ <CheckoutSummarySkeleton />
117
+ ) : (
118
+ <CheckoutSummary
119
+ disablePromotionCode={disablePromotionCode}
120
+ disableSuccessAnimation={disableSuccessAnimation}
121
+ onCheckout={onCheckout}
122
+ onCheckoutCompleted={onCheckoutCompleted}
123
+ isFreeDowngrade={isFreeDowngrade}
124
+ />
94
125
  )}
95
126
  </CheckoutContent>
96
127
  </CheckoutLayout>
@@ -1,8 +1,6 @@
1
1
  import { produce } from 'immer';
2
- import React, { useCallback, useContext, useMemo, useState } from 'react';
3
-
2
+ import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
4
3
  import { BillableFeature, BillingPeriod, GetCheckoutStateResults } from '@stigg/js-client-sdk';
5
-
6
4
  import { CustomizedTheme, SdkThemeProvider, useStiggTheme } from '../../theme/Theme';
7
5
  import { DeepPartial } from '../../types';
8
6
  import { mapCheckoutConfiguration } from '../common/mapExternalTheme';
@@ -21,6 +19,7 @@ import {
21
19
  import { CheckoutLocalization, getResolvedCheckoutLocalize } from './textOverrides';
22
20
  import { CheckoutTheme, getResolvedCheckoutTheme } from './theme';
23
21
  import { StiggTheme } from '../../theme/types';
22
+ import { BillingInformation } from './types';
24
23
 
25
24
  export interface CheckoutContextState {
26
25
  checkout?: GetCheckoutStateResults | null;
@@ -58,12 +57,16 @@ const CheckoutContextProvider: React.FC<{ children: React.ReactNode; initialStat
58
57
  }) => {
59
58
  const [state, innerSetState] = useState(initialState);
60
59
 
60
+ useEffect(() => {
61
+ innerSetState(initialState);
62
+ }, [initialState]);
63
+
61
64
  const setState = useCallback(
62
65
  (updater: (state: CheckoutContextState) => void) => innerSetState((old) => produce(old, (draft) => updater(draft))),
63
66
  [innerSetState],
64
67
  );
65
68
 
66
- const [contextValue, setContextValue] = useMemo(() => [state, setState], [state]);
69
+ const [contextValue, setContextValue] = useMemo(() => [state, setState], [setState, state]);
67
70
 
68
71
  return <CheckoutContext.Provider value={[contextValue, setContextValue]}>{children}</CheckoutContext.Provider>;
69
72
  };
@@ -76,17 +79,19 @@ export type CheckoutProviderProps = {
76
79
  preferredBillingPeriod?: BillingPeriod;
77
80
  billingCountryCode?: string;
78
81
  billableFeatures?: BillableFeature[];
82
+ billingInformation?: BillingInformation;
79
83
  };
80
84
 
81
85
  export function CheckoutProvider({
82
86
  children,
83
87
  textOverrides,
84
88
  theme,
89
+ preferredBillingPeriod,
90
+ billableFeatures,
85
91
  resourceId,
86
92
  planId,
87
- preferredBillingPeriod,
88
93
  billingCountryCode,
89
- billableFeatures,
94
+ billingInformation,
90
95
  }: {
91
96
  children: React.ReactNode;
92
97
  } & CheckoutProviderProps) {
@@ -111,7 +116,10 @@ export function CheckoutProvider({
111
116
  billingPeriod: planStep.billingPeriod,
112
117
  activeSubscription: checkout?.activeSubscription,
113
118
  });
114
- const paymentStep = getPaymentStepInitialState({ customer: checkout?.customer });
119
+ const paymentStep = getPaymentStepInitialState({
120
+ customer: checkout?.customer,
121
+ taxPercentage: billingInformation?.taxDetails?.taxPercentage,
122
+ });
115
123
  const progressBar = getProgressBarInitialState({
116
124
  availableAddons: isLoading ? undefined : addonsStep.availableAddons,
117
125
  });
@@ -126,20 +134,12 @@ export function CheckoutProvider({
126
134
  addonsStep,
127
135
  paymentStep,
128
136
  resourceId: checkout?.resource?.id,
129
- widgetState: { readOnly: false, isLoadingCheckoutData: isLoading },
137
+ widgetState: { readOnly: false, isValid: true, isLoadingCheckoutData: isLoading },
130
138
  };
131
139
 
132
140
  return initialState;
133
- }, [
134
- theme,
135
- textOverrides,
136
- preferredBillingPeriod,
137
- billingCountryCode,
138
- billableFeatures,
139
- globalTheme,
140
- checkout,
141
- isLoading,
142
- ]);
141
+ // eslint-disable-next-line react-hooks/exhaustive-deps
142
+ }, [preferredBillingPeriod, billingCountryCode, checkout, isLoading, billingInformation?.taxDetails?.taxPercentage]);
143
143
 
144
144
  return (
145
145
  <SdkThemeProvider key={checkout?.plan.id} componentTheme={configuration}>
@@ -1,49 +1,33 @@
1
1
  import React from 'react';
2
2
 
3
3
  import styled from '@emotion/styled/macro';
4
- import { Button as MuiButton, ButtonProps, css } from '@mui/material';
4
+ import { Button as MuiButton, ButtonProps } from '@mui/material';
5
5
 
6
- export type StyledButtonProps = { $isLoading?: boolean; $success?: boolean; $error?: boolean };
6
+ export type StyledButtonProps = { $success?: boolean; $error?: boolean };
7
7
 
8
- const StyledButton = styled(MuiButton)<StyledButtonProps>`
8
+ const StyledButton = styled(MuiButton, { shouldForwardProp: (prop) => !prop.startsWith('$') })<StyledButtonProps>`
9
9
  border-radius: 10px;
10
10
  text-transform: none;
11
11
 
12
- ${({ theme, $isLoading, $success, $error }) => {
13
- if ($isLoading) {
14
- return css`
15
- background-color: ${theme.stigg.palette.primaryDark};
16
- cursor: no-drop;
17
-
18
- &:hover {
19
- background-color: ${theme.stigg.palette.primaryDark};
20
- }
21
- `;
22
- }
23
-
12
+ background-color: ${({ theme, $success, $error }) => {
24
13
  if ($success) {
25
- return css`
26
- background-color: ${theme.stigg.palette.success};
27
- cursor: 'default';
28
-
29
- &:hover {
30
- background-color: ${theme.stigg.palette.successDark};
31
- }
32
- `;
14
+ return theme.stigg.palette.success;
15
+ } else if ($error) {
16
+ return theme.stigg.palette.error;
33
17
  }
34
-
35
- if ($error) {
36
- return css`
37
- background-color: ${theme.stigg.palette.error};
38
-
39
- &:hover {
40
- background-color: ${theme.stigg.palette.errorDark};
41
- }
42
- `;
43
- }
44
-
45
18
  return '';
46
- }}
19
+ }};
20
+
21
+ &:hover {
22
+ background-color: ${({ theme, $success, $error }) => {
23
+ if ($success) {
24
+ return theme.stigg.palette.successDark;
25
+ } else if ($error) {
26
+ return theme.stigg.palette.errorDark;
27
+ }
28
+ return '';
29
+ }};
30
+ }
47
31
  `;
48
32
 
49
33
  export const Button = ({ variant = 'outlined', ...props }: ButtonProps & StyledButtonProps) => {
@@ -0,0 +1,32 @@
1
+ import { Button } from '@mui/material';
2
+ import { Typography } from '../../common/Typography';
3
+ import React from 'react';
4
+ import { CheckoutLocalization } from '../textOverrides';
5
+ import { ButtonProps } from '@mui/material/Button';
6
+
7
+ export const ChangePlanButton = ({
8
+ onClick,
9
+ checkoutLocalization,
10
+ size,
11
+ }: {
12
+ onClick: () => void;
13
+ checkoutLocalization: CheckoutLocalization;
14
+ size: ButtonProps['size'];
15
+ }) => {
16
+ return (
17
+ <Button
18
+ className="stigg-checkout-change-plan-button"
19
+ sx={{ textTransform: 'none' }}
20
+ variant="text"
21
+ size={size}
22
+ onClick={onClick}>
23
+ <Typography
24
+ className="stigg-checkout-change-plan-button-text"
25
+ color="primary.main"
26
+ variant="body1"
27
+ style={{ lineHeight: '24px' }}>
28
+ {checkoutLocalization.changePlan}
29
+ </Typography>
30
+ </Button>
31
+ );
32
+ };
@@ -0,0 +1,118 @@
1
+ import React from 'react';
2
+ import { StyledArrowRightIcon } from '../planHeader/PlanHeader.style';
3
+ import styled from '@emotion/styled/macro';
4
+ import { Alert, Box } from '@mui/material';
5
+ import { Typography } from '../../common/Typography';
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
+ import { CheckoutLocalization } from '../textOverrides';
10
+ import { CheckoutContainerProps } from '../CheckoutContainer';
11
+ import { ChangePlanButton } from './ChangePlanButton';
12
+
13
+ const DowngradeToFreePlansContainer = styled(Box)`
14
+ display: flex;
15
+ `;
16
+
17
+ const DowngradeToFreeAlert = styled(Alert)`
18
+ margin-bottom: 16px;
19
+ `;
20
+
21
+ export const DowngradeToFreePlanBox = styled(Box)`
22
+ padding: 16px;
23
+ border-radius: 10px;
24
+ width: 100%;
25
+ border: ${({ theme }) => `1px solid ${theme.stigg.palette.outlinedBorder}`};
26
+ `;
27
+
28
+ export const DowngradeToFreeContent = ({
29
+ planName,
30
+ totalPrice,
31
+ billingPeriod,
32
+ }: {
33
+ planName: string;
34
+ totalPrice?: {
35
+ amount: number;
36
+ currency: Currency;
37
+ };
38
+ billingPeriod?: BillingPeriod;
39
+ }) => {
40
+ const priceText = totalPrice
41
+ ? currencyPriceFormatter({ amount: totalPrice.amount, currency: totalPrice.currency })
42
+ : 'Free';
43
+
44
+ const billingPeriodText = billingPeriod ? ` / Paid ${billingPeriod.toLowerCase()}` : '';
45
+ return (
46
+ <DowngradeToFreePlanBox className="stigg-checkout-free-downgrade-plan-box">
47
+ <Typography className="stigg-checkout-downgrade-to-free-text-plan" color="secondary">
48
+ {planName}
49
+ </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>
63
+ </DowngradeToFreePlanBox>
64
+ );
65
+ };
66
+
67
+ type DowngradeToFreePlanProps = {
68
+ checkoutLocalization: CheckoutLocalization;
69
+ activeSubscription: Subscription;
70
+ freePlan: CheckoutStatePlan;
71
+ allowChangePlan?: boolean;
72
+ } & Pick<CheckoutContainerProps, 'onChangePlan'>;
73
+
74
+ export const DowngradeToFreePlan = ({
75
+ checkoutLocalization,
76
+ activeSubscription,
77
+ freePlan,
78
+ allowChangePlan = false,
79
+ onChangePlan,
80
+ }: DowngradeToFreePlanProps) => {
81
+ let alertAction;
82
+ if (allowChangePlan && onChangePlan) {
83
+ alertAction = (
84
+ <ChangePlanButton
85
+ onClick={() => {
86
+ onChangePlan({ currentPlan: freePlan });
87
+ }}
88
+ checkoutLocalization={checkoutLocalization}
89
+ size="small"
90
+ />
91
+ );
92
+ }
93
+
94
+ return (
95
+ <>
96
+ <DowngradeToFreeAlert action={alertAction} className="stigg-checkout-downgrade-to-free-alert" severity="info">
97
+ <Typography span color="secondary">
98
+ {checkoutLocalization.downgradeToFreeAlertText({ plan: activeSubscription.plan })}
99
+ </Typography>
100
+ </DowngradeToFreeAlert>
101
+
102
+ <DowngradeToFreePlansContainer className="stigg-checkout-downgrade-to-free-plans-container">
103
+ <DowngradeToFreeContent
104
+ planName={activeSubscription.plan.displayName}
105
+ totalPrice={activeSubscription.totalPrice?.total}
106
+ billingPeriod={activeSubscription.prices[0].billingPeriod}
107
+ />
108
+
109
+ <StyledArrowRightIcon
110
+ className="stigg-checkout-downgrade-to-free-arrow"
111
+ style={{ margin: 'auto 16px', minWidth: '16px' }}
112
+ />
113
+
114
+ <DowngradeToFreeContent planName={freePlan.displayName} />
115
+ </DowngradeToFreePlansContainer>
116
+ </>
117
+ );
118
+ };
@@ -2,7 +2,10 @@ import styled from '@emotion/styled/macro';
2
2
  import { Grid } from '@mui/material';
3
3
  import ReactSkeleton from 'react-loading-skeleton';
4
4
 
5
- export const SkeletonsContainer = styled(Grid)<{ $gap: number; $flexDirection?: 'row' | 'column' }>`
5
+ export const SkeletonsContainer = styled(Grid, { shouldForwardProp: (prop) => !prop.startsWith('$') })<{
6
+ $gap: number;
7
+ $flexDirection?: 'row' | 'column';
8
+ }>`
6
9
  display: flex;
7
10
  flex-direction: ${({ $flexDirection }) => $flexDirection || 'row'};
8
11
  gap: ${({ $gap }) => $gap}px;
@@ -3,6 +3,7 @@ import { useCheckoutContext } from '../CheckoutProvider';
3
3
  export type WidgetState = {
4
4
  readOnly?: boolean;
5
5
  isLoadingCheckoutData?: boolean;
6
+ isValid?: boolean;
6
7
  };
7
8
 
8
9
  function useCheckoutState() {
@@ -19,14 +20,23 @@ function useSetWidgetReadonly() {
19
20
  });
20
21
  }
21
22
 
23
+ function useSetIsValid() {
24
+ const [, setState] = useCheckoutContext();
25
+
26
+ return (isValid: boolean) =>
27
+ setState((draft) => {
28
+ draft.widgetState.isValid = isValid;
29
+ });
30
+ }
31
+
22
32
  export function useCheckoutModel() {
23
33
  const { checkoutState, widgetState, checkoutLocalization } = useCheckoutState();
24
- const setWidgetReadOnly = useSetWidgetReadonly();
25
34
 
26
35
  return {
27
36
  checkoutState,
28
37
  widgetState,
29
38
  checkoutLocalization,
30
- setWidgetReadOnly,
39
+ setWidgetReadOnly: useSetWidgetReadonly(),
40
+ setIsValid: useSetIsValid(),
31
41
  };
32
42
  }
@@ -1,18 +1,27 @@
1
- import { Customer } from '@stigg/js-client-sdk';
1
+ import { BillingAddress, Customer } from '@stigg/js-client-sdk';
2
2
 
3
3
  import { useCheckoutContext } from '../CheckoutProvider';
4
4
 
5
5
  export type PaymentStepState = {
6
6
  useNewPaymentMethod: boolean;
7
7
  errorMessage?: string;
8
+ billingAddress?: BillingAddress;
9
+ taxPercentage?: number;
8
10
  };
9
11
 
10
12
  type GetPaymentStepInitialStateProps = {
11
13
  customer?: Customer;
14
+ taxPercentage?: number;
12
15
  };
13
16
 
14
- export function getPaymentStepInitialState({ customer }: GetPaymentStepInitialStateProps): PaymentStepState {
15
- return { useNewPaymentMethod: !customer?.paymentMethodDetails };
17
+ export function getPaymentStepInitialState({
18
+ customer,
19
+ taxPercentage,
20
+ }: GetPaymentStepInitialStateProps): PaymentStepState {
21
+ return {
22
+ useNewPaymentMethod: !customer?.paymentMethodDetails,
23
+ taxPercentage,
24
+ };
16
25
  }
17
26
 
18
27
  function useSetUseNewPaymentMethod() {
@@ -33,6 +42,15 @@ function useSetErrorMessage() {
33
42
  });
34
43
  }
35
44
 
45
+ function useSetBillingAddress() {
46
+ const [, setState] = useCheckoutContext();
47
+
48
+ return (billingAddress?: BillingAddress) =>
49
+ setState((draft) => {
50
+ draft.paymentStep.billingAddress = billingAddress;
51
+ });
52
+ }
53
+
36
54
  function usePaymentState() {
37
55
  const [{ paymentStep }] = useCheckoutContext();
38
56
  return paymentStep;
@@ -45,5 +63,6 @@ export function usePaymentStepModel() {
45
63
  ...state,
46
64
  setUseNewPaymentMethod: useSetUseNewPaymentMethod(),
47
65
  setErrorMessage: useSetErrorMessage(),
66
+ setBillingAddress: useSetBillingAddress(),
48
67
  };
49
68
  }