@stigg/react-sdk 5.22.1 → 5.23.1

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 (33) hide show
  1. package/dist/components/checkout/Checkout.d.ts +1 -1
  2. package/dist/components/checkout/CheckoutProvider.d.ts +3 -1
  3. package/dist/components/checkout/configurations/steps.d.ts +1 -0
  4. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +13 -3
  5. package/dist/components/checkout/progressBar/CheckoutProgressBar.d.ts +1 -1
  6. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +2 -3
  7. package/dist/components/checkout/steps/payment/PaymentMethods.style.d.ts +2 -0
  8. package/dist/components/utils/formatNumber.d.ts +1 -0
  9. package/dist/components/utils/planPrices.d.ts +4 -0
  10. package/dist/react-sdk.cjs.development.js +130 -62
  11. package/dist/react-sdk.cjs.development.js.map +1 -1
  12. package/dist/react-sdk.cjs.production.min.js +1 -1
  13. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  14. package/dist/react-sdk.esm.js +130 -62
  15. package/dist/react-sdk.esm.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/components/checkout/Checkout.tsx +3 -1
  18. package/src/components/checkout/CheckoutProvider.tsx +18 -2
  19. package/src/components/checkout/configurations/steps.ts +1 -0
  20. package/src/components/checkout/hooks/usePlanStepModel.ts +6 -9
  21. package/src/components/checkout/hooks/useProgressBarModel.ts +64 -5
  22. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +5 -1
  23. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +8 -1
  24. package/src/components/checkout/steps/payment/PaymentMethods.tsx +11 -12
  25. package/src/components/checkout/steps/payment/PaymentStep.tsx +1 -0
  26. package/src/components/checkout/summary/CheckoutSummary.tsx +27 -20
  27. package/src/components/checkout/summary/components/LineItems.tsx +1 -1
  28. package/src/components/common/VolumeBulkSelect.tsx +2 -1
  29. package/src/components/paywall/EntitlementRow.tsx +2 -7
  30. package/src/components/utils/formatNumber.ts +5 -0
  31. package/src/components/utils/planPrices.ts +10 -0
  32. package/src/stories/Checkout.stories.tsx +17 -2
  33. package/src/stories/mocks/checkout/mockCheckoutState.ts +1 -0
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.22.1",
2
+ "version": "5.23.1",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -15,6 +15,7 @@ export const Checkout = ({
15
15
  billableFeatures,
16
16
  billingInformation,
17
17
  onMockCheckoutState,
18
+ skipCheckoutSteps,
18
19
  ...containerProps
19
20
  }: CheckoutProps) => {
20
21
  return (
@@ -27,7 +28,8 @@ export const Checkout = ({
27
28
  billingCountryCode={billingCountryCode}
28
29
  billableFeatures={billableFeatures}
29
30
  billingInformation={billingInformation}
30
- onMockCheckoutState={onMockCheckoutState}>
31
+ onMockCheckoutState={onMockCheckoutState}
32
+ skipCheckoutSteps={skipCheckoutSteps}>
31
33
  <CheckoutContainer {...containerProps} />
32
34
  </CheckoutProvider>
33
35
  );
@@ -21,6 +21,7 @@ import { CheckoutTheme, getResolvedCheckoutTheme } from './configurations/theme'
21
21
  import { StiggTheme } from '../../theme/types';
22
22
  import { BillingInformation, MockCheckoutStateCallback } from './types';
23
23
  import { defaultCheckoutTypography } from './configurations/typography';
24
+ import { CheckoutSteps } from './configurations/steps';
24
25
 
25
26
  export interface CheckoutContextState {
26
27
  checkout?: GetCheckoutStateResults | null;
@@ -82,6 +83,7 @@ export type CheckoutProviderProps = {
82
83
  billableFeatures?: BillableFeature[];
83
84
  billingInformation?: BillingInformation;
84
85
  onMockCheckoutState?: MockCheckoutStateCallback;
86
+ skipCheckoutSteps?: CheckoutSteps[];
85
87
  };
86
88
 
87
89
  export function CheckoutProvider({
@@ -95,6 +97,7 @@ export function CheckoutProvider({
95
97
  billingCountryCode,
96
98
  billingInformation,
97
99
  onMockCheckoutState,
100
+ skipCheckoutSteps,
98
101
  }: {
99
102
  children: React.ReactNode;
100
103
  } & CheckoutProviderProps) {
@@ -124,7 +127,13 @@ export function CheckoutProvider({
124
127
  taxPercentage: billingInformation?.taxDetails?.taxPercentage,
125
128
  });
126
129
  const progressBar = getProgressBarInitialState({
127
- availableAddons: isLoading ? undefined : addonsStep.availableAddons,
130
+ isLoading,
131
+ skipCheckoutSteps: skipCheckoutSteps ?? [],
132
+ plan: checkout?.plan,
133
+ availableAddons: addonsStep.availableAddons,
134
+ availableCharges: planStep.billableFeatures,
135
+ preferredBillingPeriod,
136
+ preconfiguredBillableFeatures: billableFeatures ?? [],
128
137
  });
129
138
 
130
139
  const initialState: CheckoutContextState = {
@@ -142,7 +151,14 @@ export function CheckoutProvider({
142
151
 
143
152
  return initialState;
144
153
  // eslint-disable-next-line react-hooks/exhaustive-deps
145
- }, [preferredBillingPeriod, billingCountryCode, checkout, isLoading, billingInformation?.taxDetails?.taxPercentage]);
154
+ }, [
155
+ preferredBillingPeriod,
156
+ billingCountryCode,
157
+ checkout,
158
+ isLoading,
159
+ skipCheckoutSteps,
160
+ billingInformation?.taxDetails?.taxPercentage,
161
+ ]);
146
162
 
147
163
  return (
148
164
  <SdkThemeProvider key={checkout?.plan.id} componentTheme={configuration}>
@@ -0,0 +1 @@
1
+ export type CheckoutSteps = 'PLAN' | 'ADDONS';
@@ -5,6 +5,7 @@ import { BillableFeature, BillingModel, Plan, Price, Subscription } from '@stigg
5
5
  import { useCheckoutContext } from '../CheckoutProvider';
6
6
  import { getTierByQuantity, hasTierWithUnitPrice } from '../../utils/priceTierUtils';
7
7
  import { getValidPriceQuantity } from '../../utils/priceUtils';
8
+ import { hasAnnualPrices, hasMonthlyPrices } from '../../utils/planPrices';
8
9
 
9
10
  export type PlanStepState = {
10
11
  billingPeriod: BillingPeriod;
@@ -95,11 +96,11 @@ function resolveBillingPeriod({
95
96
  activeSubscription?: Subscription | null;
96
97
  preferredBillingPeriod?: BillingPeriod;
97
98
  }) {
98
- const hasMonthlyPrices = plan?.pricePoints.some((pricePoint) => pricePoint.billingPeriod === BillingPeriod.Monthly);
99
- const hasAnnualPrices = plan?.pricePoints.some((pricePoint) => pricePoint.billingPeriod === BillingPeriod.Annually);
99
+ const hasMonthlyPlan = hasMonthlyPrices(plan);
100
+ const hasAnnualPlan = hasAnnualPrices(plan);
100
101
 
101
102
  if (preferredBillingPeriod) {
102
- const billingPeriod = getBillingPeriod(preferredBillingPeriod, hasMonthlyPrices, hasAnnualPrices);
103
+ const billingPeriod = getBillingPeriod(preferredBillingPeriod, hasMonthlyPlan, hasAnnualPlan);
103
104
  if (billingPeriod) {
104
105
  return billingPeriod;
105
106
  }
@@ -111,17 +112,13 @@ function resolveBillingPeriod({
111
112
  }
112
113
 
113
114
  if (activeSubscription?.prices && activeSubscription?.prices.length > 0) {
114
- const billingPeriod = getBillingPeriod(
115
- activeSubscription?.prices[0].billingPeriod,
116
- hasMonthlyPrices,
117
- hasAnnualPrices,
118
- );
115
+ const billingPeriod = getBillingPeriod(activeSubscription?.prices[0].billingPeriod, hasMonthlyPlan, hasAnnualPlan);
119
116
  if (billingPeriod) {
120
117
  return billingPeriod;
121
118
  }
122
119
  }
123
120
 
124
- return hasAnnualPrices ? BillingPeriod.Annually : BillingPeriod.Monthly;
121
+ return hasAnnualPlan ? BillingPeriod.Annually : BillingPeriod.Monthly;
125
122
  }
126
123
 
127
124
  export function getPlanStepInitialState({
@@ -1,5 +1,8 @@
1
- import { Addon } from '@stigg/js-client-sdk';
1
+ import { BillableFeatureInput } from '@stigg/api-client-js/src/generated/sdk';
2
+ import { Addon, BillableFeature, BillingPeriod, CheckoutStatePlan } from '@stigg/js-client-sdk';
2
3
  import { useCheckoutContext } from '../CheckoutProvider';
4
+ import { CheckoutSteps } from '../configurations/steps';
5
+ import { hasMultipleBillingPeriods } from '../../utils/planPrices';
3
6
 
4
7
  export enum CheckoutStepKey {
5
8
  PLAN = 'PLAN',
@@ -32,12 +35,68 @@ const INITIAL_STATE: ProgressBarState = {
32
35
  isDisabled: false,
33
36
  };
34
37
 
35
- export function getProgressBarInitialState({ availableAddons }: { availableAddons?: Addon[] }) {
36
- if (availableAddons?.length === 0) {
37
- return { ...INITIAL_STATE, steps: CHECKOUT_STEPS.filter((step) => step.key !== CheckoutStepKey.ADDONS) };
38
+ type GetProgressBarInitialStateProps = {
39
+ isLoading: boolean;
40
+ skipCheckoutSteps: CheckoutSteps[];
41
+ plan?: CheckoutStatePlan;
42
+ availableAddons?: Addon[];
43
+ availableCharges: BillableFeatureInput[];
44
+ preferredBillingPeriod?: BillingPeriod;
45
+ preconfiguredBillableFeatures: BillableFeature[];
46
+ };
47
+
48
+ const canSkipPlanStep = (
49
+ plan: CheckoutStatePlan,
50
+ availableCharges: BillableFeatureInput[],
51
+ preconfiguredBillableFeatures: BillableFeature[],
52
+ preferredBillingPeriod?: BillingPeriod,
53
+ ) => {
54
+ // if multiple billing periods are available, a preferred billing period must be selected
55
+ if (hasMultipleBillingPeriods(plan) && !preferredBillingPeriod) {
56
+ return false;
57
+ }
58
+
59
+ const availableChargesIds = availableCharges.map((charge) => charge.featureId);
60
+ const preconfiguredChargesIds = preconfiguredBillableFeatures.map((charge) => charge.featureId);
61
+
62
+ // if there are available charges, they must be preconfigured
63
+ if (
64
+ availableChargesIds.length !== preconfiguredChargesIds.length ||
65
+ !availableChargesIds.every((charge) => preconfiguredChargesIds.includes(charge))
66
+ ) {
67
+ return false;
68
+ }
69
+
70
+ return true;
71
+ };
72
+
73
+ export function getProgressBarInitialState({
74
+ isLoading,
75
+ skipCheckoutSteps,
76
+ plan,
77
+ availableAddons,
78
+ availableCharges,
79
+ preferredBillingPeriod,
80
+ preconfiguredBillableFeatures,
81
+ }: GetProgressBarInitialStateProps) {
82
+ if (isLoading || !plan) {
83
+ return INITIAL_STATE;
84
+ }
85
+
86
+ const stepsToFilter: CheckoutStepKey[] = [];
87
+
88
+ if (
89
+ skipCheckoutSteps.includes('PLAN') &&
90
+ canSkipPlanStep(plan, availableCharges, preconfiguredBillableFeatures, preferredBillingPeriod)
91
+ ) {
92
+ stepsToFilter.push(CheckoutStepKey.PLAN);
93
+ }
94
+
95
+ if (availableAddons?.length === 0 || skipCheckoutSteps.includes('ADDONS')) {
96
+ stepsToFilter.push(CheckoutStepKey.ADDONS);
38
97
  }
39
98
 
40
- return INITIAL_STATE;
99
+ return { ...INITIAL_STATE, steps: CHECKOUT_STEPS.filter((step) => !stepsToFilter.includes(step.key)) };
41
100
  }
42
101
 
43
102
  function useProgressBarState() {
@@ -15,8 +15,12 @@ export const CheckoutProgressBar = () => {
15
15
  const { activeStep, completedSteps, steps } = progressBarState || {};
16
16
  const progress = ((activeStep + 1) * 100) / steps.length;
17
17
 
18
+ if (progressBarState.steps.length === 1) {
19
+ return null;
20
+ }
21
+
18
22
  return (
19
- <Box sx={{ width: '100%', mb: 3 }}>
23
+ <Box className="stigg-checkout-progress-container" sx={{ width: '100%', mb: 3 }}>
20
24
  <StyledProgress variant="determinate" value={progress} $disabled={readOnly} />
21
25
  <Grid container display="flex">
22
26
  {steps.map(({ key, label }, index) => {
@@ -1,3 +1,4 @@
1
+ import { css } from '@emotion/react';
1
2
  import styled from '@emotion/styled';
2
3
  import Grid from '@mui/material/Grid';
3
4
 
@@ -11,9 +12,15 @@ export const PaymentMethodContainer = styled(Grid, { shouldForwardProp: (prop) =
11
12
  opacity: ${({ $disabled }) => ($disabled ? 0.6 : 1)};
12
13
  `;
13
14
 
14
- export const NewPaymentMethodContainer = styled(PaymentMethodContainer)`
15
+ export const NewPaymentMethodContainer = styled(PaymentMethodContainer)<{ $hideBorders?: boolean }>`
15
16
  flex-direction: column;
16
17
  align-items: unset;
18
+ ${({ $hideBorders }) =>
19
+ $hideBorders &&
20
+ css`
21
+ border: none;
22
+ padding: 0;
23
+ `}
17
24
  `;
18
25
 
19
26
  export const PaymentMethodLayoutContainer = styled(Grid)`
@@ -5,7 +5,6 @@ import Grid from '@mui/material/Grid';
5
5
  import Radio from '@mui/material/Radio';
6
6
  import { Customer } from '@stigg/js-client-sdk';
7
7
 
8
- import { Icon, Icons } from '../../../common/Icon';
9
8
  import { Typography } from '../../../common/Typography';
10
9
  import {
11
10
  NewPaymentMethodContainer,
@@ -19,7 +18,6 @@ import { CheckoutContainerProps } from '../../CheckoutContainer';
19
18
 
20
19
  export type PaymentMethodLayoutProps = {
21
20
  checked: boolean;
22
- icon: Icons;
23
21
  text: React.ReactNode;
24
22
  subtitle?: React.ReactNode;
25
23
  readOnly?: boolean;
@@ -31,13 +29,13 @@ export type PaymentMethodProps = Pick<Customer, 'paymentMethodDetails'> &
31
29
  export type NewPaymentMethodProps = Pick<PaymentMethodLayoutProps, 'checked' | 'readOnly'> & {
32
30
  onSelect: () => void;
33
31
  checkoutLocalization: CheckoutLocalization;
32
+ hasExistingPaymentMethod: boolean;
34
33
  } & Pick<CheckoutContainerProps, 'onBillingAddressChange' | 'collectPhoneNumber'>;
35
34
 
36
- function PaymentMethodLayout({ checked, icon, text, subtitle, readOnly }: PaymentMethodLayoutProps) {
35
+ function PaymentMethodLayout({ checked, text, subtitle, readOnly }: PaymentMethodLayoutProps) {
37
36
  return (
38
37
  <PaymentMethodLayoutContainer>
39
38
  <Radio checked={checked} disabled={readOnly} />
40
- <Icon icon={icon} style={{ display: 'flex' }} />
41
39
  <PaymentMethodTextContainer container>
42
40
  <Grid item>{text}</Grid>
43
41
  {subtitle && <Grid item>{subtitle}</Grid>}
@@ -57,7 +55,6 @@ export function ExistingPaymentMethod({ checked, paymentMethodDetails, readOnly,
57
55
  <PaymentMethodLayout
58
56
  checked={checked}
59
57
  readOnly={readOnly}
60
- icon="PaymentMethod"
61
58
  text={<Typography variant="h6">{`Card ending in ${last4Digits}`}</Typography>}
62
59
  subtitle={
63
60
  !!expirationMonth &&
@@ -73,6 +70,7 @@ export function ExistingPaymentMethod({ checked, paymentMethodDetails, readOnly,
73
70
  }
74
71
 
75
72
  export function NewPaymentMethod({
73
+ hasExistingPaymentMethod,
76
74
  checked,
77
75
  onSelect,
78
76
  readOnly,
@@ -81,13 +79,14 @@ export function NewPaymentMethod({
81
79
  collectPhoneNumber,
82
80
  }: NewPaymentMethodProps) {
83
81
  return (
84
- <NewPaymentMethodContainer item onClick={onSelect} $disabled={readOnly}>
85
- <PaymentMethodLayout
86
- checked={checked}
87
- readOnly={readOnly}
88
- icon="PaymentMethod"
89
- text={<Typography variant="h6">{checkoutLocalization.newPaymentMethodText}</Typography>}
90
- />
82
+ <NewPaymentMethodContainer item $hideBorders={!hasExistingPaymentMethod} onClick={onSelect} $disabled={readOnly}>
83
+ {hasExistingPaymentMethod && (
84
+ <PaymentMethodLayout
85
+ checked={checked}
86
+ readOnly={readOnly}
87
+ text={<Typography variant="h6">{checkoutLocalization.newPaymentMethodText}</Typography>}
88
+ />
89
+ )}
91
90
  <Collapse in={checked}>
92
91
  <StripePaymentForm onBillingAddressChange={onBillingAddressChange} collectPhoneNumber={collectPhoneNumber} />
93
92
  </Collapse>
@@ -44,6 +44,7 @@ export function PaymentStep({
44
44
  onSelect={() => handleOnSelect(false)}
45
45
  />
46
46
  <NewPaymentMethod
47
+ hasExistingPaymentMethod={!!customer?.paymentMethodDetails}
47
48
  readOnly={readOnly}
48
49
  checked={useNewPaymentMethod}
49
50
  checkoutLocalization={checkoutLocalization}
@@ -181,7 +181,12 @@ export const CheckoutSummary = ({
181
181
  <SummaryCard>
182
182
  <SummaryTitle variant="h3">{checkoutLocalization.summary.title}</SummaryTitle>
183
183
 
184
- <Grid display="flex" flexDirection="row" alignItems="center" marginY={2}>
184
+ <Grid
185
+ className="stigg-checkout-summary-plan-title-container"
186
+ display="flex"
187
+ flexDirection="row"
188
+ alignItems="center"
189
+ marginY={2}>
185
190
  <Typography variant="h6" color="primary" style={{ paddingRight: '8px' }}>
186
191
  {checkoutLocalization.summary.planName({ plan: plan! })}
187
192
  </Typography>
@@ -198,25 +203,27 @@ export const CheckoutSummary = ({
198
203
  )}
199
204
  {!baseCharge && isFreeDowngrade ? <FreeChargeLineItem label={baseChargeLabel} /> : null}
200
205
 
201
- {usageCharges.map((price) => {
202
- const priceBillableFeature = subscription.billableFeatures?.find(
203
- (billableFeature) => billableFeature.featureId === price.feature?.featureId,
204
- );
205
-
206
- return (
207
- <BilledPriceLineItem
208
- checkoutLocalization={checkoutLocalization}
209
- key={price.feature?.featureId}
210
- label={getFeatureDisplayNameText(
211
- price.feature?.displayName || '',
212
- price.feature?.units,
213
- price.feature?.unitsPlural,
214
- )}
215
- quantity={priceBillableFeature?.quantity || 1}
216
- price={price}
217
- />
218
- );
219
- })}
206
+ <Grid item className="stigg-checkout-summary-usage-charges-container">
207
+ {usageCharges.map((price) => {
208
+ const priceBillableFeature = subscription.billableFeatures?.find(
209
+ (billableFeature) => billableFeature.featureId === price.feature?.featureId,
210
+ );
211
+
212
+ return (
213
+ <BilledPriceLineItem
214
+ checkoutLocalization={checkoutLocalization}
215
+ key={price.feature?.featureId}
216
+ label={getFeatureDisplayNameText(
217
+ price.feature?.displayName || '',
218
+ price.feature?.units,
219
+ price.feature?.unitsPlural,
220
+ )}
221
+ quantity={priceBillableFeature?.quantity || 1}
222
+ price={price}
223
+ />
224
+ );
225
+ })}
226
+ </Grid>
220
227
 
221
228
  {!!subscription.addons?.length && (
222
229
  <>
@@ -98,7 +98,7 @@ export const BilledPriceLineItem = ({
98
98
  }
99
99
 
100
100
  return (
101
- <LineItemContainer>
101
+ <LineItemContainer className="stigg-checkout-summary-base-charges-container">
102
102
  <LineItemRow style={{ alignItems: 'flex-start' }}>
103
103
  <Grid item display="flex" gap={0.5} style={{ whiteSpace: 'nowrap' }}>
104
104
  {title}
@@ -7,6 +7,7 @@ import { map } from 'lodash';
7
7
  import React from 'react';
8
8
  import { Typography } from './Typography';
9
9
  import { TiersSelectContainerProps } from './TiersSelectContainer';
10
+ import { formatNumber } from '../utils/formatNumber';
10
11
 
11
12
  const TierSelect = styled(Select)`
12
13
  border-radius: 10px;
@@ -62,7 +63,7 @@ export function VolumeBulkSelect({
62
63
  {map(tiers, (tier: PriceTierFragment) => (
63
64
  <MenuItem className="stigg-price-tier-menu-item-text" key={tier.upTo} value={tier.upTo?.toString()}>
64
65
  <Typography variant="body1" color="primary" style={{ lineHeight: 'unset' }}>
65
- {tier.upTo} {tierUnits}
66
+ {formatNumber(tier.upTo)} {tierUnits}
66
67
  </Typography>
67
68
  </MenuItem>
68
69
  ))}
@@ -3,6 +3,7 @@ import styled from '@emotion/styled/macro';
3
3
  import { EntitlementResetPeriod } from '@stigg/js-client-sdk';
4
4
  import CheckUrl from '../../assets/check-stigg.svg';
5
5
  import { calculateUnitQuantityText } from './utils/calculateUnitQuantityText';
6
+ import { formatNumber } from '../utils/formatNumber';
6
7
  import { Typography } from '../common/Typography';
7
8
 
8
9
  const EntitlementName = styled(Typography)`
@@ -29,12 +30,6 @@ const EntitlementCheckIcon = styled(CheckUrl)`
29
30
  }
30
31
  `;
31
32
 
32
- function formatUsageNumber(usageLimit: number) {
33
- return usageLimit.toLocaleString('en-US', {
34
- maximumFractionDigits: 0,
35
- });
36
- }
37
-
38
33
  type EntitlementRowProps = {
39
34
  hasUnlimitedUsage?: boolean | null;
40
35
  isCustom?: boolean | null;
@@ -100,7 +95,7 @@ function getEntitlementDisplay({
100
95
 
101
96
  if (usageLimit) {
102
97
  const featureUnits = usageLimit === 1 ? feature?.units : feature?.unitsPlural;
103
- return `${formatUsageNumber(usageLimit)} ${featureUnits} ${resetPeriodSuffix}`;
98
+ return `${formatNumber(usageLimit)} ${featureUnits} ${resetPeriodSuffix}`;
104
99
  }
105
100
 
106
101
  if (unitBasedEntitlement) {
@@ -0,0 +1,5 @@
1
+ export function formatNumber(usageLimit: number | null | undefined) {
2
+ return usageLimit?.toLocaleString('en-US', {
3
+ maximumFractionDigits: 0,
4
+ });
5
+ }
@@ -0,0 +1,10 @@
1
+ import { Plan } from '@stigg/js-client-sdk';
2
+ import { BillingPeriod } from '@stigg/api-client-js/src/generated/sdk';
3
+
4
+ export const hasMonthlyPrices = (plan?: Plan) =>
5
+ !!plan?.pricePoints.some((pricePoint) => pricePoint.billingPeriod === BillingPeriod.Monthly);
6
+
7
+ export const hasAnnualPrices = (plan?: Plan) =>
8
+ !!plan?.pricePoints.some((pricePoint) => pricePoint.billingPeriod === BillingPeriod.Annually);
9
+
10
+ export const hasMultipleBillingPeriods = (plan?: Plan) => hasMonthlyPrices(plan) && hasAnnualPrices(plan);
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import styled from '@emotion/styled/macro';
3
+ import { BillingPeriod } from '@stigg/js-client-sdk';
3
4
  import { ComponentMeta, ComponentStory } from '@storybook/react';
4
5
  import { Checkout } from '../components/checkout';
5
6
  import { StiggProvider } from '../components/StiggProvider';
@@ -23,6 +24,16 @@ export default {
23
24
  </StiggProvider>
24
25
  ),
25
26
  ],
27
+ argTypes: {
28
+ billingPeriod: {
29
+ options: [BillingPeriod.Monthly, BillingPeriod.Annually, null],
30
+ control: { type: 'radio' },
31
+ },
32
+ skipSteps: {
33
+ options: ['PLAN', 'ADDONS'],
34
+ control: { type: 'check' },
35
+ },
36
+ },
26
37
  parameters: {
27
38
  controls: {
28
39
  exclude: [
@@ -32,6 +43,8 @@ export default {
32
43
  'onBillingAddressChange',
33
44
  'onMockCheckoutState',
34
45
  'onMockCheckoutPreview',
46
+ 'preferredBillingPeriod',
47
+ 'skipCheckoutSteps',
35
48
  ],
36
49
  },
37
50
  },
@@ -45,7 +58,7 @@ const Template: ComponentStory<any> = (args) => (
45
58
  <Wrapper>
46
59
  <Checkout
47
60
  planId={args.planId}
48
- preferredBillingPeriod={args.preferredBillingPeriod}
61
+ preferredBillingPeriod={args.billingPeriod}
49
62
  billingCountryCode={args.billingCountryCode}
50
63
  resourceId={args.resourceId}
51
64
  onCheckoutCompleted={(results) => {
@@ -62,10 +75,11 @@ const Template: ComponentStory<any> = (args) => (
62
75
  const { success, errorMessage, results } = await checkoutAction(checkoutParams);
63
76
  return { success, errorMessage, results };
64
77
  }}
65
- billableFeatures={[{ featureId: 'feature-seat', quantity: 30 }]}
78
+ billableFeatures={args.billableFeatures || []}
66
79
  onChangePlan={({ currentPlan }) => {
67
80
  console.log('plan changed clicked!', { currentPlan });
68
81
  }}
82
+ skipCheckoutSteps={args.skipSteps}
69
83
  onMockCheckoutState={
70
84
  args.useMockData
71
85
  ? (params) => {
@@ -74,6 +88,7 @@ const Template: ComponentStory<any> = (args) => (
74
88
  }
75
89
  : undefined
76
90
  }
91
+ disablePromotionCode={args.disablePromotionCode}
77
92
  onMockCheckoutPreview={
78
93
  args.useMockData
79
94
  ? (params) => {
@@ -184,6 +184,7 @@ function mockPlan(planRefId: string): CheckoutStatePlan {
184
184
  compatibleAddons: [additionalStorageAddons],
185
185
  entitlements: [],
186
186
  inheritedEntitlements: [],
187
+ compatiblePackageGroups: [],
187
188
  };
188
189
  }
189
190