@stigg/react-sdk 5.23.0 → 5.24.0

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/common/mediaQuery.d.ts +12 -0
  2. package/dist/components/hooks/useIsScreenWiderThan.d.ts +2 -0
  3. package/dist/components/utils/formatNumber.d.ts +1 -0
  4. package/dist/react-sdk.cjs.development.js +169 -116
  5. package/dist/react-sdk.cjs.development.js.map +1 -1
  6. package/dist/react-sdk.cjs.production.min.js +1 -1
  7. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  8. package/dist/react-sdk.esm.js +177 -136
  9. package/dist/react-sdk.esm.js.map +1 -1
  10. package/package.json +6 -4
  11. package/src/components/checkout/CheckoutContainer.style.ts +18 -3
  12. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +24 -5
  13. package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +11 -3
  14. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +4 -2
  15. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +13 -6
  16. package/src/components/checkout/summary/CheckoutSuccess.tsx +8 -2
  17. package/src/components/checkout/summary/CheckoutSummary.tsx +6 -1
  18. package/src/components/checkout/summary/components/LineItems.tsx +15 -4
  19. package/src/components/common/VolumeBulkSelect.tsx +2 -1
  20. package/src/components/common/mediaQuery.ts +19 -0
  21. package/src/components/customerPortal/billing/InformationGrid.tsx +1 -0
  22. package/src/components/customerPortal/billing/PaymentDetailsSection.tsx +15 -3
  23. package/src/components/customerPortal/common/SectionContainer.tsx +12 -1
  24. package/src/components/customerPortal/subscriptionOverview/SubscriptionOverviewLoader.tsx +4 -1
  25. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverview.tsx +3 -1
  26. package/src/components/customerPortal/usage/CustomerUsageData.style.tsx +4 -2
  27. package/src/components/customerPortal/usage/CustomerUsageData.tsx +6 -3
  28. package/src/components/hooks/useIsScreenWiderThan.ts +6 -0
  29. package/src/components/paywall/EntitlementRow.tsx +2 -7
  30. package/src/components/utils/formatNumber.ts +5 -0
  31. package/src/stories/Checkout.stories.tsx +2 -1
  32. package/src/stories/CustomerPortal.stories.tsx +2 -1
  33. package/src/stories/baseArgs.ts +4 -4
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.23.0",
2
+ "version": "5.24.0",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  "prepare": "husky install",
26
26
  "docs": "typedoc",
27
27
  "link-sdk": "yarn link && cd node_modules/react && yarn link && cd ../../node_modules/react-dom && yarn link && cd ../../",
28
- "publish-storybook": "export NODE_OPTIONS=--openssl-legacy-provider && yarn build-storybook && npx chromatic --project-token=cbd1660d8132"
28
+ "publish-storybook": "export NODE_OPTIONS=--openssl-legacy-provider && yarn build-storybook && npx chromatic --project-token=cbd1660d8132 --exit-once-uploaded"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": ">=16"
@@ -42,7 +42,9 @@
42
42
  ]
43
43
  },
44
44
  "name": "@stigg/react-sdk",
45
- "author": "Stigg",
45
+ "author": {
46
+ "name": "Stigg"
47
+ },
46
48
  "module": "dist/react-sdk.esm.js",
47
49
  "size-limit": [
48
50
  {
@@ -132,5 +134,5 @@
132
134
  "styled-typography": "^1.0.3"
133
135
  },
134
136
  "readme": "ERROR: No README data found!",
135
- "_id": "@stigg/react-sdk@0.18.0"
137
+ "_id": "@stigg/react-sdk@5.23.0"
136
138
  }
@@ -1,9 +1,9 @@
1
1
  import styled from '@emotion/styled/macro';
2
2
  import Box from '@mui/material/Box';
3
+ import { mq } from '../common/mediaQuery';
3
4
 
4
5
  export const CheckoutLayout = styled.div`
5
6
  margin: auto;
6
- width: 100%;
7
7
  min-height: 760px;
8
8
  max-width: 920px;
9
9
  display: flex;
@@ -11,14 +11,19 @@ export const CheckoutLayout = styled.div`
11
11
  flex-direction: column;
12
12
  align-items: center;
13
13
 
14
- padding: 16px 32px;
15
- border-radius: 10px;
16
14
  background-color: ${({ theme }) => theme.stigg.palette.backgroundPaper};
17
15
  border: ${({ theme }) => `1px solid ${theme.stigg.palette.outlinedBorder}`};
18
16
 
19
17
  & * {
20
18
  box-sizing: border-box;
21
19
  }
20
+
21
+ padding: 16px 16px;
22
+ ${mq.md} {
23
+ padding: 32px;
24
+ width: calc(100% - 64px);
25
+ border-radius: 10px;
26
+ }
22
27
  `;
23
28
  export const CheckoutContent = styled(Box)`
24
29
  display: flex;
@@ -26,6 +31,11 @@ export const CheckoutContent = styled(Box)`
26
31
  gap: 32px;
27
32
  flex-wrap: wrap;
28
33
  width: 100%;
34
+
35
+ flex-direction: column;
36
+ ${mq.md} {
37
+ flex-direction: row;
38
+ }
29
39
  `;
30
40
 
31
41
  export const CheckoutPanel = styled(Box)`
@@ -33,4 +43,9 @@ export const CheckoutPanel = styled(Box)`
33
43
  flex-direction: column;
34
44
  gap: 0;
35
45
  flex: 2;
46
+
47
+ width: 100%;
48
+ ${mq.md} {
49
+ width: auto;
50
+ }
36
51
  `;
@@ -1,26 +1,39 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import Grid from '@mui/material/Grid';
3
3
  import Box from '@mui/material/Box';
4
4
  import StepIcon from '@mui/material/StepIcon';
5
5
  import { useCheckoutModel, useProgressBarModel } from '../hooks';
6
6
  import { Typography } from '../../common/Typography';
7
- import { StyledProgress, StyledStepButton, StyledIcon } from './CheckoutProgressBar.style';
7
+ import { StyledIcon, StyledProgress, StyledStepButton } from './CheckoutProgressBar.style';
8
8
  import { Icons } from '../../common/Icon';
9
9
  import { Skeleton } from '../components/Skeletons.style';
10
+ import { useIsScreenWiderThan } from '../../hooks/useIsScreenWiderThan';
10
11
 
11
12
  export const CheckoutProgressBar = () => {
12
- const { progressBarState, setActiveStep } = useProgressBarModel();
13
+ const { progressBarState, setActiveStep, currentStep } = useProgressBarModel();
13
14
  const { widgetState } = useCheckoutModel();
15
+ const isScreenWiderThanMd = useIsScreenWiderThan('md');
16
+ const containerRef = useRef<HTMLElement>();
14
17
  const { readOnly, isLoadingCheckoutData } = widgetState;
15
18
  const { activeStep, completedSteps, steps } = progressBarState || {};
16
19
  const progress = ((activeStep + 1) * 100) / steps.length;
17
20
 
21
+ const [previousStep, setPreviousStep] = React.useState(currentStep);
22
+ useEffect(() => {
23
+ if (!isScreenWiderThanMd) {
24
+ if (containerRef.current && currentStep !== previousStep) {
25
+ containerRef.current.scrollIntoView({ behavior: 'smooth' });
26
+ }
27
+ }
28
+ setPreviousStep(currentStep);
29
+ }, [currentStep, isScreenWiderThanMd, previousStep, setPreviousStep]);
30
+
18
31
  if (progressBarState.steps.length === 1) {
19
32
  return null;
20
33
  }
21
34
 
22
35
  return (
23
- <Box className="stigg-checkout-progress-container" sx={{ width: '100%', mb: 3 }}>
36
+ <Box className="stigg-checkout-progress-container" sx={{ width: '100%', mb: 3 }} ref={containerRef}>
24
37
  <StyledProgress variant="determinate" value={progress} $disabled={readOnly} />
25
38
  <Grid container display="flex">
26
39
  {steps.map(({ key, label }, index) => {
@@ -32,7 +45,13 @@ export const CheckoutProgressBar = () => {
32
45
  const checkedIcon: Icons = isDisabled ? 'OutlinedCheckedCircleDisabled' : 'OutlinedCheckedCircle';
33
46
 
34
47
  return (
35
- <Grid key={key} item display="flex" flexDirection="row" flex={1} justifyContent="flex-start">
48
+ <Grid
49
+ key={key}
50
+ item
51
+ display="flex"
52
+ flexDirection="row"
53
+ flex={isScreenWiderThanMd ? 1 : 'auto'}
54
+ justifyContent="flex-start">
36
55
  {isLoadingCheckoutData ? (
37
56
  <Skeleton width={120} height={20} style={{ marginTop: 8 }} />
38
57
  ) : (
@@ -2,6 +2,7 @@ import styled from '@emotion/styled/macro';
2
2
  import Grid from '@mui/material/Grid';
3
3
 
4
4
  import { Button } from '../../components';
5
+ import { mq } from '../../../common/mediaQuery';
5
6
 
6
7
  export const CheckoutAddonsContainer = styled(Grid)`
7
8
  width: 100%;
@@ -10,9 +11,16 @@ export const CheckoutAddonsContainer = styled(Grid)`
10
11
 
11
12
  export const AddonListItemContainer = styled(Grid)`
12
13
  display: flex;
13
- justify-content: space-between;
14
- align-items: center;
15
- height: 80px;
14
+ flex-direction: column;
15
+ gap: 16px;
16
+
17
+ ${mq.md} {
18
+ gap: 0;
19
+ flex-direction: row;
20
+ justify-content: space-between;
21
+ height: 80px;
22
+ align-items: center;
23
+ }
16
24
  `;
17
25
 
18
26
  export const TrashButton = styled(Button)`
@@ -13,6 +13,7 @@ import { AddonListItemContainer, CheckoutAddonsContainer, TrashButton } from './
13
13
  import { CheckoutLocalization } from '../../configurations/textOverrides';
14
14
  import { useCheckoutModel, useProgressBarModel } from '../../hooks';
15
15
  import { ON_WHEEL_BLUR } from '../../../utils/onWheelBlur';
16
+ import { useIsScreenWiderThan } from '../../../hooks/useIsScreenWiderThan';
16
17
 
17
18
  type UseAddonsStepModel = ReturnType<typeof useAddonsStepModel>;
18
19
 
@@ -39,6 +40,7 @@ function AddonListItem({
39
40
  onAddonsValidationChange,
40
41
  isValid,
41
42
  }: AddonListItemProps) {
43
+ const isScreenWiderThanLg = useIsScreenWiderThan('lg');
42
44
  const addonPrice = addon.pricePoints.find((pricePoint) => pricePoint.billingPeriod === billingPeriod);
43
45
  const isAdded = !!addonState;
44
46
  const hasChanges =
@@ -84,7 +86,7 @@ function AddonListItem({
84
86
  </Typography>
85
87
  )}
86
88
  </Grid>
87
- <Grid item>
89
+ <Grid item sx={{ gap: '16px' }} container={!isScreenWiderThanLg}>
88
90
  {hasChanges && (
89
91
  <Button variant="text" size="small" sx={{ padding: '8px', minWidth: 'unset' }} onClick={handleUndo}>
90
92
  <Typography color="primary.main" variant="body1">
@@ -98,7 +100,7 @@ function AddonListItem({
98
100
  id={`${addon.id}-input`}
99
101
  type="number"
100
102
  onWheel={ON_WHEEL_BLUR}
101
- sx={{ width: 120, marginX: 2 }}
103
+ sx={isScreenWiderThanLg ? { marginX: 2, width: 120 } : { flex: 1 }}
102
104
  value={addonState?.quantity ?? ''}
103
105
  error={!isValid}
104
106
  helperText={!isValid ? 'Minimum 1' : undefined}
@@ -15,6 +15,8 @@ import { TiersSelectContainer } from '../../../common/TiersSelectContainer';
15
15
  import { getValidPriceQuantity } from '../../../utils/priceUtils';
16
16
  import { getFeatureDisplayNameText } from '../../../utils/getFeatureName';
17
17
  import { ON_WHEEL_BLUR } from '../../../utils/onWheelBlur';
18
+ import { mq } from '../../../common/mediaQuery';
19
+ import { useIsScreenWiderThan } from '../../../hooks/useIsScreenWiderThan';
18
20
 
19
21
  export type UsePlanStepModel = ReturnType<typeof usePlanStepModel>;
20
22
 
@@ -25,11 +27,15 @@ type CheckoutChargeListProps = {
25
27
 
26
28
  const StyledPlanCharge = styled.div`
27
29
  display: flex;
28
- flex-direction: row;
29
- justify-content: space-between;
30
- align-items: center;
31
30
  min-height: 60px;
32
31
  margin-top: 16px;
32
+ flex-direction: column;
33
+
34
+ ${mq.md} {
35
+ flex-direction: row;
36
+ align-items: center;
37
+ justify-content: space-between;
38
+ }
33
39
  `;
34
40
 
35
41
  const getValidationText = (charge: Price, quantity?: number) => {
@@ -58,6 +64,7 @@ export function PlanCharge({
58
64
  setBillableFeature: UsePlanStepModel['setBillableFeature'];
59
65
  onValidationChange: ({ featureId, isValid }: { featureId: string; isValid: boolean }) => void;
60
66
  }) {
67
+ const isScreenWiderThanMd = useIsScreenWiderThan('md');
61
68
  const featureId = charge.feature?.featureId;
62
69
  const isBaseCharge = !featureId;
63
70
  const isPayAsYouGo = charge.pricingModel === BillingModel.UsageBased;
@@ -120,7 +127,7 @@ export function PlanCharge({
120
127
  } else {
121
128
  chargeRow = (
122
129
  <InputField
123
- sx={{ width: 120 }}
130
+ sx={{ width: isScreenWiderThanMd ? 120 : '100%' }}
124
131
  id={`${featureId}-input`}
125
132
  type="number"
126
133
  onWheel={ON_WHEEL_BLUR}
@@ -172,7 +179,7 @@ export function CheckoutChargeList({ plan, billingPeriod }: CheckoutChargeListPr
172
179
  }, [chargesValidation, setIsDisabled, setIsValid]);
173
180
 
174
181
  return (
175
- <div>
182
+ <>
176
183
  {planCharges?.map((charge) => {
177
184
  const billableFeature = billableFeatures.find((x) => x.featureId === charge.feature?.featureId);
178
185
  return (
@@ -188,6 +195,6 @@ export function CheckoutChargeList({ plan, billingPeriod }: CheckoutChargeListPr
188
195
  />
189
196
  );
190
197
  })}
191
- </div>
198
+ </>
192
199
  );
193
200
  }
@@ -1,7 +1,7 @@
1
1
  import styled from '@emotion/styled/macro';
2
2
  import Box from '@mui/material/Box';
3
3
  import Color from 'color';
4
- import React from 'react';
4
+ import React, { useEffect, useRef } from 'react';
5
5
  import Lottie from 'lottie-react';
6
6
  import animationData from '../../../assets/lottie/checkout-success.json';
7
7
  import { Typography } from '../../common/Typography';
@@ -70,8 +70,14 @@ const StyledLottie = styled(Lottie)`
70
70
  `;
71
71
 
72
72
  export function CheckoutSuccess({ checkoutLocalization }: { checkoutLocalization: CheckoutLocalization }) {
73
+ const containerRef = useRef<HTMLDivElement>();
74
+ useEffect(() => {
75
+ if (containerRef.current) {
76
+ containerRef.current.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
77
+ }
78
+ }, []);
73
79
  return (
74
- <CheckoutSuccessContainer className="stigg-checkout-success-container">
80
+ <CheckoutSuccessContainer className="stigg-checkout-success-container" ref={containerRef}>
75
81
  <StyledLottie animationData={animationData} loop={false} autoplay />
76
82
  <CheckoutSuccessText variant="h1" color="primary.main">
77
83
  {checkoutLocalization.summary.checkoutSuccessText}
@@ -37,16 +37,21 @@ import { Icon } from '../../common/Icon';
37
37
  import { CheckoutLocalization } from '../configurations/textOverrides';
38
38
  import { CheckoutSuccess } from './CheckoutSuccess';
39
39
  import { getFeatureDisplayNameText } from '../../utils/getFeatureName';
40
+ import { mq } from '../../common/mediaQuery';
40
41
 
41
42
  export const SummaryContainer = styled(Box)`
43
+ width: 100%;
42
44
  max-width: 470px;
43
45
  flex: 1.5;
44
46
  `;
45
47
 
46
48
  export const SummaryCard = styled(Paper)`
47
- border-radius: 10px;
48
49
  background: ${({ theme }) => theme.stigg.palette.backgroundHighlight};
49
50
  padding: 16px;
51
+
52
+ ${mq.md} {
53
+ border-radius: 10px;
54
+ }
50
55
  `;
51
56
 
52
57
  SummaryCard.defaultProps = {
@@ -24,6 +24,8 @@ import { getPriceBreakdownString } from './getPriceBreakdownString';
24
24
  import { GraduatedPriceBreakdown } from './GraduatedPriceBreakdown';
25
25
  import { CollapsableSectionIcon } from '../../../common/CollapsableSectionIcon';
26
26
  import { calculateTierPrice } from '../../../utils/priceTierUtils';
27
+ import { useIsScreenWiderThan } from '../../../hooks/useIsScreenWiderThan';
28
+ import { mq } from '../../../common/mediaQuery';
27
29
 
28
30
  export const LineItemContainer = styled.div`
29
31
  & + & {
@@ -38,9 +40,14 @@ export const NestedBreakdownContainer = styled.div`
38
40
 
39
41
  export const LineItemRow = styled.div`
40
42
  display: flex;
41
- align-items: center;
42
- justify-content: space-between;
43
+ flex-direction: column;
43
44
  gap: 16px;
45
+
46
+ ${mq.lg} {
47
+ flex-direction: row;
48
+ align-items: center;
49
+ justify-content: space-between;
50
+ }
44
51
  `;
45
52
 
46
53
  const PayAsYouGoPriceTooltip = ({ checkoutLocalization }: { checkoutLocalization: CheckoutLocalization }) => {
@@ -63,6 +70,7 @@ export const BilledPriceLineItem = ({
63
70
  quantity: number;
64
71
  price: Price;
65
72
  }) => {
73
+ const isScreenWiderThanLg = useIsScreenWiderThan('lg');
66
74
  const [isNestedBreakdownOpen, setIsNestedBreakdownOpen] = useState(false);
67
75
  const toggleNestedBreakdown = () => setIsNestedBreakdownOpen((prev) => !prev);
68
76
 
@@ -100,7 +108,7 @@ export const BilledPriceLineItem = ({
100
108
  return (
101
109
  <LineItemContainer className="stigg-checkout-summary-base-charges-container">
102
110
  <LineItemRow style={{ alignItems: 'flex-start' }}>
103
- <Grid item display="flex" gap={0.5} style={{ whiteSpace: 'nowrap' }}>
111
+ <Grid item display="flex" gap={0.5} style={{ whiteSpace: isScreenWiderThanLg ? 'nowrap' : 'break-spaces' }}>
104
112
  {title}
105
113
  {nestedBreakdown && (
106
114
  <IconButton onClick={toggleNestedBreakdown} sx={{ padding: 0 }}>
@@ -110,7 +118,10 @@ export const BilledPriceLineItem = ({
110
118
  </Grid>
111
119
  <Grid item display="flex" gap={1} alignItems="center">
112
120
  {isPayAsYouGo && <PayAsYouGoPriceTooltip checkoutLocalization={checkoutLocalization} />}
113
- <Typography variant="body1" color="secondary" style={{ whiteSpace: 'nowrap' }}>
121
+ <Typography
122
+ variant="body1"
123
+ color="secondary"
124
+ style={{ whiteSpace: isScreenWiderThanLg ? 'nowrap' : 'break-spaces' }}>
114
125
  {getPriceBreakdownString({
115
126
  totalAmount,
116
127
  quantity,
@@ -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
  ))}
@@ -0,0 +1,19 @@
1
+ export const breakpoints = {
2
+ xs: 320,
3
+ sm: 640,
4
+ md: 768,
5
+ lg: 1024,
6
+ xl: 1280,
7
+ xxl: 1536,
8
+ } as const;
9
+
10
+ export type Breakpoints = typeof breakpoints;
11
+
12
+ export type Breakpoint = keyof Breakpoints;
13
+
14
+ export const mqMinWidth = (breakpoint: Breakpoint) => `(min-width: ${breakpoints[breakpoint]}px)`;
15
+
16
+ export const mq = Object.keys(breakpoints).reduce(
17
+ (obj, breakpoint) => ({ ...obj, [breakpoint]: `@media ${mqMinWidth(breakpoint as Breakpoint)}` }),
18
+ {} as Record<Breakpoint, string>,
19
+ );
@@ -16,6 +16,7 @@ const InformationGridRow = styled.div`
16
16
  align-items: flex-start;
17
17
  gap: 16px;
18
18
  align-self: stretch;
19
+ flex-wrap: wrap;
19
20
  `;
20
21
 
21
22
  export type InformationGridProps = {
@@ -9,11 +9,13 @@ import { ExternalLinkButton } from '../common/ExternalLinkButton';
9
9
  import { InformationGrid, InformationGridContainer } from './InformationGrid';
10
10
  import { SectionHeader } from '../common/SectionHeader';
11
11
  import { SkeletonButton } from '../common/SkeletonButton';
12
+ import { useIsScreenWiderThan } from '../../hooks/useIsScreenWiderThan';
12
13
 
13
14
  export const EMPTY_CHAR = '-';
14
15
 
15
16
  export function PaymentDetailsSection() {
16
17
  const { customerPortal, isLoading, textOverrides, theme } = useCustomerPortalContext();
18
+ const isScreenWiderThanMd = useIsScreenWiderThan('md');
17
19
  const { billingInformation } = customerPortal || {};
18
20
  const isLoadingData = !billingInformation || isLoading;
19
21
 
@@ -27,7 +29,11 @@ export function PaymentDetailsSection() {
27
29
  <Skeleton width={220} height={12} />
28
30
  <Skeleton width={220} height={12} />
29
31
  </InformationGridContainer>,
30
- <Divider key="information-loading-data-divider" orientation="vertical" style={{ minHeight: 93 }} />,
32
+ <Divider
33
+ key="information-loading-data-divider"
34
+ orientation="vertical"
35
+ style={{ minHeight: 93, display: isScreenWiderThanMd ? 'block' : 'none' }}
36
+ />,
31
37
  <InformationGridContainer key="information-loading-data-bottom">
32
38
  <Skeleton width={220} height={12} />
33
39
  <Skeleton width={220} height={12} />
@@ -64,7 +70,11 @@ export function PaymentDetailsSection() {
64
70
  billingInformation.defaultPaymentExpirationYear
65
71
  ) {
66
72
  items.unshift(
67
- <Divider key="information-billing-data-divider" orientation="vertical" style={{ minHeight: 93 }} />,
73
+ <Divider
74
+ key="information-billing-data-divider"
75
+ orientation="vertical"
76
+ style={{ minHeight: 93, display: isScreenWiderThanMd ? 'block' : 'none' }}
77
+ />,
68
78
  );
69
79
  items.unshift(
70
80
  <InformationGrid
@@ -122,7 +132,9 @@ export function PaymentDetailsSection() {
122
132
  {editButton}
123
133
  </SectionHeader>
124
134
 
125
- <div style={{ display: 'flex', alignItems: 'stretch', gap: 64 }}>{items}</div>
135
+ <div style={{ display: 'flex', alignItems: 'stretch', gap: isScreenWiderThanMd ? 64 : 32, flexWrap: 'wrap' }}>
136
+ {items}
137
+ </div>
126
138
  </SectionContainer>
127
139
  );
128
140
  }
@@ -1,4 +1,5 @@
1
1
  import styled from '@emotion/styled/macro';
2
+ import { mq } from '../../common/mediaQuery';
2
3
 
3
4
  export const SectionContainer = styled.div<{ $backgroundColor: string; $borderColor: string }>`
4
5
  width: 100%;
@@ -7,5 +8,15 @@ export const SectionContainer = styled.div<{ $backgroundColor: string; $borderCo
7
8
  border-radius: 10px;
8
9
  background-color: ${({ $backgroundColor }) => $backgroundColor};
9
10
  border: ${({ $borderColor }) => `1px solid ${$borderColor}`};
10
- padding: 64px;
11
+
12
+ padding: 16px;
13
+ ${mq.sm} {
14
+ padding: 32px;
15
+ }
16
+ ${mq.md} {
17
+ padding: 48px;
18
+ }
19
+ ${mq.lg} {
20
+ padding: 64px;
21
+ }
11
22
  `;
@@ -1,10 +1,12 @@
1
1
  import styled from '@emotion/styled/macro';
2
2
  import React from 'react';
3
3
  import Skeleton from 'react-loading-skeleton';
4
+ import { useIsScreenWiderThan } from '../../hooks/useIsScreenWiderThan';
4
5
 
5
6
  const SkeletonLayout = styled.div`
6
7
  display: flex;
7
8
  justify-content: space-between;
9
+ flex-wrap: wrap;
8
10
  `;
9
11
 
10
12
  const SkeletonLayoutLeft = styled.div`
@@ -14,13 +16,14 @@ const SkeletonLayoutLeft = styled.div`
14
16
  `;
15
17
 
16
18
  export function SubscriptionOverviewLoader() {
19
+ const isScreenWiderThanMd = useIsScreenWiderThan('md');
17
20
  return (
18
21
  <SkeletonLayout className="stigg-subscription-overview-skeleton-layout">
19
22
  <SkeletonLayoutLeft>
20
23
  <Skeleton width={120} />
21
24
  <Skeleton width={120} />
22
25
  </SkeletonLayoutLeft>
23
- <Skeleton width={295} height={193} />
26
+ <Skeleton width={isScreenWiderThanMd ? 295 : 260} height={193} />
24
27
  </SkeletonLayout>
25
28
  );
26
29
  }
@@ -56,7 +56,9 @@ export function SubscriptionsOverview({
56
56
  {isLoadingData || !mainSubscription ? (
57
57
  <SubscriptionOverviewLoader />
58
58
  ) : (
59
- <div className="stigg-overview-layout" style={{ display: 'flex', alignItems: 'flex-start', gap: 64 }}>
59
+ <div
60
+ className="stigg-overview-layout"
61
+ style={{ display: 'flex', alignItems: 'flex-start', gap: 64, flexWrap: 'wrap' }}>
60
62
  <div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
61
63
  <SubscriptionsOverviewHeader
62
64
  onManageSubscription={onManageSubscription}
@@ -3,16 +3,18 @@ import Grid from '@mui/material/Grid';
3
3
  import { range } from 'lodash';
4
4
  import Skeleton from 'react-loading-skeleton';
5
5
  import React from 'react';
6
+ import { useIsScreenWiderThan } from '../../hooks/useIsScreenWiderThan';
6
7
 
7
8
  export const Footer = styled.div`
8
9
  margin-top: 32px;
9
10
  `;
10
11
 
11
12
  export function CustomerUsageLoader() {
13
+ const isMdScreen = useIsScreenWiderThan('md');
12
14
  return (
13
- <Grid container spacing={4} className="stigg-subscription-usage-skeleton-layout">
15
+ <Grid container spacing={4} className="stigg-subscription-usage-skeleton-layout" sx={{ flexWrap: 'wrap' }}>
14
16
  {range(6).map((item) => (
15
- <Grid key={item} item xs={4}>
17
+ <Grid key={item} item xs={isMdScreen ? 4 : 12}>
16
18
  <Skeleton width={280} height={120} />
17
19
  </Grid>
18
20
  ))}
@@ -1,5 +1,5 @@
1
1
  import { MeterType, PricingType, SubscriptionStatus } from '@stigg/js-client-sdk';
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
  import { compact, keyBy } from 'lodash';
4
4
  import { Minus, Plus } from 'react-feather';
5
5
  import Grid from '@mui/material/Grid';
@@ -12,6 +12,7 @@ import { SectionTitle } from '../common/SectionTitle';
12
12
  import { StyledButton } from '../common/StyledButton';
13
13
  import { FilterEntitlementsFn, OnBuyMoreCallbackFn } from '../types';
14
14
  import { OnManageClick } from '../CustomerPortalContainer';
15
+ import { useIsScreenWiderThan } from '../../hooks/useIsScreenWiderThan';
15
16
 
16
17
  const MAX_BOXES = 6;
17
18
 
@@ -22,7 +23,9 @@ export type CustomerUsageDataProps = {
22
23
  };
23
24
 
24
25
  export function CustomerUsageData({ onManageSubscription, onBuyMore, filterEntitlements }: CustomerUsageDataProps) {
25
- const [showAll, setShowAll] = React.useState(false);
26
+ const [showAll, setShowAll] = useState(false);
27
+ const isMdScreen = useIsScreenWiderThan('md');
28
+
26
29
  const { customerPortal, isLoading, textOverrides, theme } = useCustomerPortalContext();
27
30
  const isLoadingData = isLoading || !customerPortal;
28
31
  const { entitlements, subscriptions } = customerPortal || {};
@@ -52,7 +55,7 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore, filterEntit
52
55
  const filteredEntitlements = filterEntitlements ? filterEntitlements(sortedEntitlements) : sortedEntitlements;
53
56
 
54
57
  // 4 -> 3 per row, 6 -> 2 per row
55
- const xs = filteredEntitlements.length > 2 ? 4 : 6;
58
+ const xs = isMdScreen ? (filteredEntitlements.length > 2 ? 4 : 6) : 12;
56
59
 
57
60
  const entitlementsToShow = showAll ? filteredEntitlements : filteredEntitlements.slice(0, MAX_BOXES);
58
61
 
@@ -0,0 +1,6 @@
1
+ import { useMediaQuery as useMediaQueryMui } from '@mui/material';
2
+ import { Breakpoint, mqMinWidth } from '../common/mediaQuery';
3
+
4
+ export function useIsScreenWiderThan(breakpoint: Breakpoint) {
5
+ return useMediaQueryMui(mqMinWidth(breakpoint));
6
+ }
@@ -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
+ }
@@ -51,7 +51,8 @@ export default {
51
51
  } as ComponentMeta<typeof Checkout>;
52
52
 
53
53
  const Wrapper = styled.div`
54
- width: 1000px;
54
+ max-width: 1280px;
55
+ margin: 0 auto;
55
56
  `;
56
57
 
57
58
  const Template: ComponentStory<any> = (args) => (
@@ -41,7 +41,8 @@ export default {
41
41
  } as ComponentMeta<typeof CustomerPortal>;
42
42
 
43
43
  const Wrapper = styled.div`
44
- width: 1000px;
44
+ max-width: 1280px;
45
+ margin: 0 auto;
45
46
  `;
46
47
 
47
48
  const ModularWrapper = styled.div`