@stigg/react-sdk 4.6.1 → 4.7.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 (77) hide show
  1. package/README.md +7 -0
  2. package/dist/components/checkout/CheckoutContainer.d.ts +4 -2
  3. package/dist/components/checkout/components/Button.d.ts +1 -1
  4. package/dist/components/checkout/components/InputField.d.ts +2 -2
  5. package/dist/components/checkout/components/Skeletons.style.d.ts +3 -3
  6. package/dist/components/checkout/hooks/useSubscriptionState.d.ts +2 -2
  7. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +2 -2
  8. package/dist/components/checkout/steps/addons/CheckoutAddonsStep.style.d.ts +2 -2
  9. package/dist/components/checkout/steps/payment/PaymentMethods.style.d.ts +4 -4
  10. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +9 -13
  11. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +2 -1
  12. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +1 -1
  13. package/dist/components/checkout/summary/CheckoutSummary.d.ts +1 -1
  14. package/dist/components/common/InformationTooltip.d.ts +1 -1
  15. package/dist/components/common/LongText.d.ts +1 -1
  16. package/dist/components/customerPortal/paywall/CustomerPortalPaywall.d.ts +0 -1
  17. package/dist/components/customerPortal/paywall/CustomerPortalPaywall.style.d.ts +0 -1
  18. package/dist/components/customerPortal/usage/featureUsage/FeatureUsageProgressBar.d.ts +2 -2
  19. package/dist/components/paywall/Paywall.d.ts +0 -1
  20. package/dist/components/paywall/PlanOffering.d.ts +2 -1
  21. package/dist/components/paywall/PlanOfferingButton.d.ts +1 -2
  22. package/dist/react-sdk.cjs.development.js +489 -426
  23. package/dist/react-sdk.cjs.development.js.map +1 -1
  24. package/dist/react-sdk.cjs.production.min.js +1 -1
  25. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  26. package/dist/react-sdk.esm.js +409 -347
  27. package/dist/react-sdk.esm.js.map +1 -1
  28. package/package.json +2 -2
  29. package/src/components/checkout/CheckoutContainer.tsx +13 -3
  30. package/src/components/checkout/components/Button.tsx +1 -1
  31. package/src/components/checkout/components/ChangePlanButton.tsx +1 -2
  32. package/src/components/checkout/components/ContentLoadingSkeleton.tsx +2 -1
  33. package/src/components/checkout/components/DowngradeToFreeContainer.tsx +2 -1
  34. package/src/components/checkout/components/InputField.tsx +2 -1
  35. package/src/components/checkout/components/Skeletons.style.ts +1 -1
  36. package/src/components/checkout/hooks/useSubscriptionState.ts +2 -3
  37. package/src/components/checkout/planHeader/PlanHeader.tsx +2 -1
  38. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +2 -1
  39. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +3 -1
  40. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +2 -1
  41. package/src/components/checkout/promotionCode/AppliedPromotionCode.tsx +1 -1
  42. package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +1 -1
  43. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +1 -1
  44. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +1 -1
  45. package/src/components/checkout/steps/payment/PaymentMethods.tsx +3 -1
  46. package/src/components/checkout/steps/payment/PaymentStep.tsx +2 -1
  47. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +1 -1
  48. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +31 -22
  49. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +63 -46
  50. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +2 -1
  51. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +2 -1
  52. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +1 -1
  53. package/src/components/checkout/steps/plan/CheckoutPlanStep.style.tsx +1 -1
  54. package/src/components/checkout/summary/CheckoutSuccess.tsx +1 -1
  55. package/src/components/checkout/summary/CheckoutSummary.tsx +6 -1
  56. package/src/components/checkout/summary/components/LineItems.tsx +1 -1
  57. package/src/components/common/InformationTooltip.tsx +13 -9
  58. package/src/components/common/LongText.tsx +3 -5
  59. package/src/components/common/TiersSelectContainer.tsx +3 -1
  60. package/src/components/customerPortal/CustomerPortalContainer.tsx +5 -8
  61. package/src/components/customerPortal/billing/PaymentDetailsSection.tsx +2 -3
  62. package/src/components/customerPortal/paywall/CustomerPortalPaywall.style.ts +0 -10
  63. package/src/components/customerPortal/paywall/CustomerPortalPaywall.tsx +2 -5
  64. package/src/components/customerPortal/subscriptionOverview/subscriptionScheduledUpdates/SubscriptionScheduledUpdateRow.tsx +2 -2
  65. package/src/components/customerPortal/subscriptionOverview/subscriptionScheduledUpdates/SubscriptionScheduledUpdatesAlert.tsx +6 -7
  66. package/src/components/customerPortal/subscriptionOverview/subscriptionView/TrialPanel.tsx +1 -1
  67. package/src/components/customerPortal/usage/CustomerUsageData.style.tsx +2 -2
  68. package/src/components/customerPortal/usage/CustomerUsageData.tsx +24 -16
  69. package/src/components/customerPortal/usage/featureUsage/FeatureUsageProgressBar.tsx +3 -9
  70. package/src/components/paywall/EntitlementRow.tsx +25 -7
  71. package/src/components/paywall/Paywall.tsx +36 -20
  72. package/src/components/paywall/PaywallContainer.tsx +2 -2
  73. package/src/components/paywall/PlanOffering.tsx +36 -22
  74. package/src/components/paywall/PlanOfferingButton.tsx +1 -3
  75. package/src/components/paywall/utils/mapPaywallData.ts +13 -11
  76. package/src/stories/Checkout.stories.tsx +2 -2
  77. package/src/stories/baseArgs.ts +3 -3
@@ -3,7 +3,7 @@ import { useCustomerPortalContext } from '../CustomerPortalProvider';
3
3
  import { SectionTitle } from '../common/SectionTitle';
4
4
  import { SectionContainer } from '../common/SectionContainer';
5
5
  import { ExternalLinkButton } from '../common/ExternalLinkButton';
6
- import { Divider } from '@mui/material';
6
+ import Divider from '@mui/material/Divider';
7
7
  import { InformationGrid, InformationGridContainer } from './InformationGrid';
8
8
  import { padStart } from 'lodash';
9
9
  import { SectionHeader } from '../common/SectionHeader';
@@ -108,8 +108,7 @@ export function PaymentDetailsSection() {
108
108
  <SectionContainer
109
109
  className="stigg-payment-details-section-layout"
110
110
  $backgroundColor={theme.backgroundColor}
111
- $borderColor={theme.borderColor}
112
- >
111
+ $borderColor={theme.borderColor}>
113
112
  <SectionHeader className="stigg-payment-details-section-header">
114
113
  <SectionTitle
115
114
  isLoading={isLoadingData}
@@ -1,10 +1,8 @@
1
- import { css } from '@emotion/react';
2
1
  import styled from '@emotion/styled/macro';
3
2
  import { STIGG_WATERMARK_CLASSNAME } from '../../common/PoweredByStigg';
4
3
  import { SectionContainer } from '../common/SectionContainer';
5
4
 
6
5
  export const CustomerPortalPaywallLayout = styled(SectionContainer)<{
7
- $hideButtons: boolean;
8
6
  $backgroundColor: string;
9
7
  $borderColor: string;
10
8
  }>`
@@ -29,14 +27,6 @@ export const CustomerPortalPaywallLayout = styled(SectionContainer)<{
29
27
  margin-right: auto;
30
28
  }
31
29
 
32
- ${({ $hideButtons }) =>
33
- $hideButtons &&
34
- css`
35
- .stigg-paywall-plan-button:not([disabled]) {
36
- display: none;
37
- }
38
- `}
39
-
40
30
  .${STIGG_WATERMARK_CLASSNAME} {
41
31
  display: none;
42
32
  }
@@ -6,14 +6,13 @@ import { SectionHeader } from '../common/SectionHeader';
6
6
 
7
7
  type CustomerPortalPaywallProps = {
8
8
  paywallComponent?: React.ReactNode;
9
- hidePaywallButtons: boolean;
10
9
  theme: CustomerPortalTheme;
11
10
  title: string;
12
11
  isLoading: boolean;
13
12
  };
14
13
 
15
14
  export const CustomerPortalPaywall = React.forwardRef<HTMLDivElement, CustomerPortalPaywallProps>(
16
- ({ paywallComponent, hidePaywallButtons, theme, title, isLoading }, ref) => {
15
+ ({ paywallComponent, theme, title, isLoading }, ref) => {
17
16
  if (!paywallComponent) {
18
17
  return null;
19
18
  }
@@ -22,10 +21,8 @@ export const CustomerPortalPaywall = React.forwardRef<HTMLDivElement, CustomerPo
22
21
  <CustomerPortalPaywallLayout
23
22
  className="stigg-customer-portal-paywall-section"
24
23
  ref={ref}
25
- $hideButtons={hidePaywallButtons}
26
24
  $backgroundColor={theme.backgroundColor}
27
- $borderColor={theme.borderColor}
28
- >
25
+ $borderColor={theme.borderColor}>
29
26
  <SectionHeader className="stigg-customer-portal-paywall-header">
30
27
  <SectionTitle isLoading={isLoading} className="stigg-customer-portal-paywall-section-title" title={title} />
31
28
  </SectionHeader>
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ArrowDown } from 'react-feather';
3
- import { Grid } from '@mui/material';
3
+ import Grid from '@mui/material/Grid';
4
4
  import {
5
5
  CustomerPortalSubscription,
6
6
  CustomerPortalSubscriptionScheduledUpdateDataFragment,
@@ -67,7 +67,7 @@ function SubscriptionScheduledUpdateUnitQuantityChangeRow({
67
67
  const newQuantityUnits = newUnitAmount === 1 ? featureUnits : featureUnitsPlural;
68
68
 
69
69
  return (
70
- <Grid container alignItems="flex-start" flexWrap='nowrap'>
70
+ <Grid container alignItems="flex-start" flexWrap="nowrap">
71
71
  <Grid>
72
72
  <ArrowDown color="#D94052" height={20} className="stigg-scheduled-updates-arrow-down" />
73
73
  </Grid>
@@ -1,5 +1,6 @@
1
1
  import React, { useState } from 'react';
2
- import { Box, Grid } from '@mui/material';
2
+ import Box from '@mui/material/Box';
3
+ import Grid from '@mui/material/Grid';
3
4
  import { CustomerPortalSubscription } from '@stigg/js-client-sdk';
4
5
  import styled from '@emotion/styled/macro';
5
6
  import { Theme, useTheme } from '@emotion/react';
@@ -51,7 +52,7 @@ function MultipleScheduledUpdates({ subscription }: Pick<SubscriptionScheduledUp
51
52
  </Grid>
52
53
  </Grid>
53
54
  <Grid>
54
- {(scheduledUpdates || []).map(scheduleUpdate => (
55
+ {(scheduledUpdates || []).map((scheduleUpdate) => (
55
56
  <SubscriptionScheduledUpdateRow
56
57
  key={scheduleUpdate.subscriptionScheduleType}
57
58
  scheduleUpdate={scheduleUpdate}
@@ -115,11 +116,10 @@ export function SubscriptionScheduledUpdatesAlert({
115
116
  return (
116
117
  <SubscriptionScheduleUpdateAlertContainer
117
118
  $borderColor={theme.borderColor}
118
- className="stigg-scheduled-updates-alert-container"
119
- >
119
+ className="stigg-scheduled-updates-alert-container">
120
120
  <Grid container alignItems={isSingleScheduledUpdate ? 'center' : 'flex-start'} gap={2}>
121
121
  <Grid item display="flex">
122
- <Icon icon='ScheduleBox' svgPathColor={theme.iconsColor} svgRectColor={theme.iconsBackgroundColor} />
122
+ <Icon icon="ScheduleBox" svgPathColor={theme.iconsColor} svgRectColor={theme.iconsBackgroundColor} />
123
123
  </Grid>
124
124
 
125
125
  <Grid item flex={1}>
@@ -137,8 +137,7 @@ export function SubscriptionScheduledUpdatesAlert({
137
137
  onClick={() => {
138
138
  setIsLoading(true);
139
139
  Promise.resolve(onCancelScheduledUpdates(subscription)).finally(() => setIsLoading(false));
140
- }}
141
- >
140
+ }}>
142
141
  {isLoading ? (
143
142
  <LoadingIndicator loading size={16} color={stiggTheme.stigg.palette.text.disabled} />
144
143
  ) : (
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import SandClockIcon from '../../../../assets/sand-clock.svg';
4
4
  import { Typography } from '../../../common/Typography';
5
5
  import { CustomerPortalSubscription, SubscriptionStatus } from '@stigg/js-client-sdk';
6
- import { Link } from '@mui/material';
6
+ import Link from '@mui/material/Link';
7
7
  import { LongText } from '../../../common/LongText';
8
8
 
9
9
  const OnTrialBadge = styled.div`
@@ -1,5 +1,5 @@
1
1
  import styled from '@emotion/styled/macro';
2
- import { Grid } from '@mui/material';
2
+ 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';
@@ -18,4 +18,4 @@ export function CustomerUsageLoader() {
18
18
  ))}
19
19
  </Grid>
20
20
  );
21
- }
21
+ }
@@ -9,7 +9,7 @@ import { SectionTitle } from '../common/SectionTitle';
9
9
  import { compact, keyBy } from 'lodash';
10
10
  import { StyledButton } from '../common/StyledButton';
11
11
  import { Minus, Plus } from 'react-feather';
12
- import { Grid } from '@mui/material';
12
+ import Grid from '@mui/material/Grid';
13
13
  import { OnBuyMoreCallbackFn } from '../types';
14
14
 
15
15
  const MAX_BOXES = 6;
@@ -25,20 +25,26 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore }: CustomerU
25
25
  const isLoadingData = isLoading || !customerPortal;
26
26
  const { entitlements, subscriptions } = customerPortal || {};
27
27
  const meteredEntitlements = entitlements?.filter(
28
- entitlement =>
28
+ (entitlement) =>
29
29
  entitlement.feature?.meterType === MeterType.Fluctuating ||
30
30
  entitlement.feature?.meterType === MeterType.Incremental,
31
31
  );
32
32
  const activeSubscription = subscriptions?.find(({ status }) => status === SubscriptionStatus.Active);
33
33
  const hasCustomSubscription = activeSubscription?.pricingType === PricingType.Custom;
34
- const canUpgradeSubscription = !!customerPortal?.canUpgradeSubscription
34
+ const canUpgradeSubscription = !!customerPortal?.canUpgradeSubscription;
35
35
 
36
36
  const subscriptionPriceByFeature = keyBy(activeSubscription?.prices, 'feature.refId');
37
37
  const entitlementByFeature = keyBy(meteredEntitlements, 'feature.refId');
38
38
 
39
39
  // sort features by prices first, then other entitlements
40
- const priceEntitlements = compact(activeSubscription?.prices.map((subscriptionPrice) => subscriptionPrice.feature && entitlementByFeature[subscriptionPrice.feature.refId]));
41
- const otherEntitlements = compact(meteredEntitlements?.filter((entitlement) => !subscriptionPriceByFeature[entitlement.feature!.refId]));
40
+ const priceEntitlements = compact(
41
+ activeSubscription?.prices.map(
42
+ (subscriptionPrice) => subscriptionPrice.feature && entitlementByFeature[subscriptionPrice.feature.refId],
43
+ ),
44
+ );
45
+ const otherEntitlements = compact(
46
+ meteredEntitlements?.filter((entitlement) => !subscriptionPriceByFeature[entitlement.feature!.refId]),
47
+ );
42
48
  const sortedEntitlements = [...priceEntitlements, ...otherEntitlements];
43
49
 
44
50
  // 4 -> 3 per row, 6 -> 2 per row
@@ -46,7 +52,7 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore }: CustomerU
46
52
 
47
53
  const entitlementsToShow = showAll ? sortedEntitlements : sortedEntitlements.slice(0, MAX_BOXES);
48
54
 
49
- const toggleShowAll = () => setShowAll(prevState => !prevState);
55
+ const toggleShowAll = () => setShowAll((prevState) => !prevState);
50
56
 
51
57
  if (!isLoadingData && !meteredEntitlements?.length) {
52
58
  return null;
@@ -57,9 +63,12 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore }: CustomerU
57
63
  className="stigg-subscription-usage-layout"
58
64
  $backgroundColor={theme.backgroundColor}
59
65
  $borderColor={theme.borderColor}>
60
-
61
66
  <SectionHeader>
62
- <SectionTitle title={textOverrides.usageTabTitle} className="stigg-customer-portal-usage-section-title" isLoading={isLoadingData} />
67
+ <SectionTitle
68
+ title={textOverrides.usageTabTitle}
69
+ className="stigg-customer-portal-usage-section-title"
70
+ isLoading={isLoadingData}
71
+ />
63
72
  </SectionHeader>
64
73
 
65
74
  {isLoadingData ? (
@@ -71,7 +80,7 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore }: CustomerU
71
80
  <Grid item xs={xs}>
72
81
  <FeatureUsage
73
82
  key={entitlement.feature!.refId}
74
- subscriptionPrice={subscriptionPriceByFeature[(entitlement.feature!.refId)]}
83
+ subscriptionPrice={subscriptionPriceByFeature[entitlement.feature!.refId]}
75
84
  entitlement={entitlement}
76
85
  onManageSubscription={onManageSubscription}
77
86
  onBuyMore={onBuyMore}
@@ -85,17 +94,16 @@ export function CustomerUsageData({ onManageSubscription, onBuyMore }: CustomerU
85
94
  {sortedEntitlements.length > MAX_BOXES && (
86
95
  <Footer>
87
96
  <StyledButton
88
- className="stigg-usage-toggle-many-button"
89
- variant="text"
90
- startIcon={showAll ? <Minus /> : <Plus />}
91
- onClick={toggleShowAll}
92
- >
97
+ className="stigg-usage-toggle-many-button"
98
+ variant="text"
99
+ startIcon={showAll ? <Minus /> : <Plus />}
100
+ onClick={toggleShowAll}>
93
101
  {showAll ? 'Show less' : 'Show more'}
94
102
  </StyledButton>
95
103
  </Footer>
96
104
  )}
97
- </>
105
+ </>
98
106
  )}
99
107
  </SectionContainer>
100
108
  );
101
- }
109
+ }
@@ -3,15 +3,12 @@ import LinearProgress from '@mui/material/LinearProgress';
3
3
  import { getUsagePercentage, getUsageProgressStatus } from './FeatureUsage.helper';
4
4
  import React from 'react';
5
5
  import { CustomerPortalEntitlement } from '@stigg/js-client-sdk';
6
- import { Divider } from '@mui/material';
6
+ import Divider from '@mui/material/Divider';
7
7
  import Color from 'color';
8
8
 
9
9
  export const StyledLinearProgress = styled(LinearProgress)<{ $progressStatus: 'standard' | 'warning' | 'error' }>`
10
10
  height: 4px;
11
- background-color: ${({ theme }) =>
12
- Color(theme.stigg.palette.primary)
13
- .alpha(0.4)
14
- .string()};
11
+ background-color: ${({ theme }) => Color(theme.stigg.palette.primary).alpha(0.4).string()};
15
12
 
16
13
  span {
17
14
  background-color: ${({ $progressStatus, theme }) => {
@@ -32,10 +29,7 @@ export const StyledLinearProgress = styled(LinearProgress)<{ $progressStatus: 's
32
29
  export const StyledDivider = styled(Divider)`
33
30
  border-style: dotted;
34
31
  border-bottom-width: 2px;
35
- border-color: ${({ theme }) =>
36
- Color(theme.stigg.palette.outlinedRestingBorder)
37
- .alpha(0.4)
38
- .string()};
32
+ border-color: ${({ theme }) => Color(theme.stigg.palette.outlinedRestingBorder).alpha(0.4).string()};
39
33
  `;
40
34
 
41
35
  export type FeatureUsageProgressBarProps = {
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import CheckUrl from '../../assets/check-stigg.svg';
3
2
  import styled from '@emotion/styled/macro';
4
- import { calculateUnitQuantityText } from './utils/calculateUnitQuantityText';
5
3
  import { EntitlementResetPeriod } from '@stigg/js-client-sdk';
4
+ import CheckUrl from '../../assets/check-stigg.svg';
5
+ import { calculateUnitQuantityText } from './utils/calculateUnitQuantityText';
6
6
  import { Typography } from '../common/Typography';
7
7
 
8
8
  const EntitlementName = styled(Typography)`
@@ -10,12 +10,19 @@ const EntitlementName = styled(Typography)`
10
10
  `;
11
11
 
12
12
  const EntitlementRowContainer = styled.div`
13
+ display: flex;
14
+ align-items: baseline;
15
+ `;
16
+
17
+ const EntitlementIconContainer = styled.div`
13
18
  display: flex;
14
19
  align-items: center;
20
+ margin-right: 16px;
21
+ height: ${({ theme }) => theme.stigg.typography.h3.fontSize};
22
+ flex-shrink: 0;
15
23
  `;
16
24
 
17
25
  const EntitlementCheckIcon = styled(CheckUrl)`
18
- margin-right: 16px;
19
26
  flex-shrink: 0;
20
27
  * {
21
28
  fill: ${({ theme }) => theme.stigg.palette.text.disabled};
@@ -62,6 +69,9 @@ function getResetPeriodText(resetPeriod?: EntitlementResetPeriod) {
62
69
  case EntitlementResetPeriod.Month: {
63
70
  return 'per month';
64
71
  }
72
+ default: {
73
+ return '';
74
+ }
65
75
  }
66
76
  }
67
77
 
@@ -79,12 +89,18 @@ function getEntitlementDisplay({
79
89
 
80
90
  if (hasUnlimitedUsage) {
81
91
  return `Unlimited ${feature?.unitsPlural}`;
82
- } else if (isCustom) {
92
+ }
93
+
94
+ if (isCustom) {
83
95
  return `Custom ${feature?.unitsPlural}`;
84
- } else if (usageLimit) {
96
+ }
97
+
98
+ if (usageLimit) {
85
99
  const featureUnits = usageLimit === 1 ? feature?.units : feature?.unitsPlural;
86
100
  return `${formatUsageNumber(usageLimit)} ${featureUnits} ${resetPeriodSuffix}`;
87
- } else if (unitBasedEntitlement) {
101
+ }
102
+
103
+ if (unitBasedEntitlement) {
88
104
  return calculateUnitQuantityText(minUnitQuantity, maxUnitQuantity, feature?.unitsPlural);
89
105
  }
90
106
 
@@ -97,7 +113,9 @@ export function EntitlementRow(props: EntitlementRowProps) {
97
113
 
98
114
  return (
99
115
  <EntitlementRowContainer className="stigg-entitlement-row-container">
100
- <EntitlementCheckIcon className="stigg-entitlement-row-icon" />
116
+ <EntitlementIconContainer>
117
+ <EntitlementCheckIcon className="stigg-entitlement-row-icon" />
118
+ </EntitlementIconContainer>
101
119
  <EntitlementName className="stigg-entitlement-name" variant="h6" color="secondary">
102
120
  {displayNameOverride || displayName}
103
121
  </EntitlementName>
@@ -1,5 +1,5 @@
1
- import { BillableFeature, BillingPeriod, Customer, Plan, Subscription } from '@stigg/js-client-sdk';
2
- import React, { useCallback } from 'react';
1
+ import { BillableFeature, BillingPeriod, Customer, Plan, PricingType, Subscription } from '@stigg/js-client-sdk';
2
+ import React, { useCallback, useMemo } from 'react';
3
3
  import styled from '@emotion/styled/macro';
4
4
  import { PlanOffering } from './PlanOffering';
5
5
  import { BillingPeriodPicker } from './BillingPeriodPicker';
@@ -47,7 +47,6 @@ type PaywallProps = {
47
47
  highlightedPlanId?: string;
48
48
  onBillingPeriodChanged: (billingPeriod: BillingPeriod) => void;
49
49
  availableBillingPeriods: BillingPeriod[];
50
- isLoading: boolean;
51
50
  isCustomerOnTrial: boolean;
52
51
  onPlanSelected: OnPlanSelectedCallbackFn;
53
52
  paywallLocale: PaywallLocalization;
@@ -69,7 +68,7 @@ export const Paywall = ({
69
68
  }: PaywallProps) => {
70
69
  const { stigg } = useStiggContext();
71
70
  const discountRate = calculatePaywallDiscountRate(plans);
72
- const shouldShowDescriptionSection = plans.some(plan => !!plan.description);
71
+ const shouldShowDescriptionSection = plans.some((plan) => !!plan.description);
73
72
  const hasMonthlyPrice = hasPricePointsForPlans(plans, BillingPeriod.Monthly);
74
73
  const hasAnnuallyPrice = hasPricePointsForPlans(plans, BillingPeriod.Annually);
75
74
  const plansToShow = getPlansToDisplay(plans, selectedBillingPeriod);
@@ -85,26 +84,42 @@ export const Paywall = ({
85
84
  billableFeatures,
86
85
  });
87
86
  },
88
- [customer, selectedBillingPeriod],
87
+ [customer, selectedBillingPeriod, currentSubscription, onPlanSelected],
89
88
  );
90
89
 
91
- const withStartingAtRow = plansToShow.some(plan => {
92
- const planPrices = plan.pricePoints.filter(pricePoint => pricePoint.billingPeriod === selectedBillingPeriod);
93
- const paywallCalculatedPrice = plan.paywallCalculatedPricePoints?.find(
94
- pricePoint => pricePoint.billingPeriod === selectedBillingPeriod,
95
- );
96
- return planPrices.length > 1 && !!paywallCalculatedPrice?.additionalChargesMayApply;
97
- });
90
+ const isCustomerInCustomPlan = !!currentSubscription && currentSubscription.plan.pricingType === PricingType.Custom;
98
91
 
99
- const withUnitPriceRow = plansToShow.some(plan => {
100
- return !!getPlanPrice(plan, selectedBillingPeriod, paywallLocale, locale, hasMonthlyPrice).unit;
101
- });
92
+ const withStartingAtRow = useMemo(
93
+ () =>
94
+ plansToShow.some((plan) => {
95
+ const planPrices = plan.pricePoints.filter((pricePoint) => pricePoint.billingPeriod === selectedBillingPeriod);
96
+ const paywallCalculatedPrice = plan.paywallCalculatedPricePoints?.find(
97
+ (pricePoint) => pricePoint.billingPeriod === selectedBillingPeriod,
98
+ );
99
+ return planPrices.length > 1 && !!paywallCalculatedPrice?.additionalChargesMayApply;
100
+ }),
101
+ [selectedBillingPeriod, plansToShow],
102
+ );
102
103
 
103
- const withTiersRow = plansToShow.some(plan => {
104
- return !!getSelectedTier(plan, selectedBillingPeriod, currentSubscription, {});
105
- });
104
+ const withUnitPriceRow = useMemo(
105
+ () =>
106
+ plansToShow.some((plan) => {
107
+ return !!getPlanPrice(plan, selectedBillingPeriod, paywallLocale, locale, hasMonthlyPrice).unit;
108
+ }),
109
+ [selectedBillingPeriod, hasMonthlyPrice, locale, paywallLocale, plansToShow],
110
+ );
111
+
112
+ const withTiersRow = useMemo(() => {
113
+ return (
114
+ !isCustomerInCustomPlan &&
115
+ plansToShow.some((plan) => {
116
+ const tiers = getSelectedTier(plan, selectedBillingPeriod, currentSubscription, {});
117
+ return Object.values(tiers).length > 0;
118
+ })
119
+ );
120
+ }, [selectedBillingPeriod, currentSubscription, isCustomerInCustomPlan, plansToShow]);
106
121
 
107
- const withTrialLeftRow = plansToShow.some(plan => {
122
+ const withTrialLeftRow = plansToShow.some((plan) => {
108
123
  return plan.isCurrentCustomerPlan && plan.trialDaysLeft;
109
124
  });
110
125
 
@@ -119,7 +134,7 @@ export const Paywall = ({
119
134
  />
120
135
 
121
136
  <PaywallPlansContainer className="stigg-paywall-plans-layout">
122
- {plansToShow.map(plan => (
137
+ {plansToShow.map((plan) => (
123
138
  <PlanOffering
124
139
  withUnitPriceRow={withUnitPriceRow}
125
140
  withTiersRow={withTiersRow}
@@ -140,6 +155,7 @@ export const Paywall = ({
140
155
  paywallLocale={paywallLocale}
141
156
  locale={locale}
142
157
  customer={customer}
158
+ isCustomerInCustomPlan={isCustomerInCustomPlan}
143
159
  />
144
160
  ))}
145
161
  </PaywallPlansContainer>
@@ -22,7 +22,7 @@ export type PaywallContainerProps = {
22
22
  preferredBillingPeriod?: BillingPeriod;
23
23
  onBillingPeriodChange?: (billingPeriod: BillingPeriod) => void;
24
24
  textOverrides?: DeepPartial<PaywallLocalization>;
25
- billingCountryCode?: string
25
+ billingCountryCode?: string;
26
26
  };
27
27
 
28
28
  export const PaywallContainer = ({
@@ -39,6 +39,7 @@ export const PaywallContainer = ({
39
39
  const hasCustomerPortalContext = useCheckContextExists(CustomerPortalContext);
40
40
  let isCustomerPortalLoading = false;
41
41
  if (hasCustomerPortalContext) {
42
+ // eslint-disable-next-line react-hooks/rules-of-hooks
42
43
  const { isLoading, resourceId: customerPortalResourceId } = useCustomerPortalContext();
43
44
  isCustomerPortalLoading = isLoading;
44
45
  resourceId = customerPortalResourceId;
@@ -81,7 +82,6 @@ export const PaywallContainer = ({
81
82
  onBillingPeriodChanged={handlePeriodChange}
82
83
  availableBillingPeriods={availableBillingPeriods}
83
84
  highlightedPlanId={highlightedPlanId}
84
- isLoading={isLoading}
85
85
  isCustomerOnTrial={isCustomerOnTrial}
86
86
  onPlanSelected={onPlanSelected}
87
87
  paywallLocale={paywallLocale}
@@ -1,18 +1,27 @@
1
1
  import React, { useEffect } from 'react';
2
- import { BillableFeature, BillingPeriod, Customer, PriceTierFragment, Subscription } from '@stigg/js-client-sdk';
2
+ import {
3
+ BillableFeature,
4
+ BillingPeriod,
5
+ Customer,
6
+ PriceTierFragment,
7
+ PricingType,
8
+ Subscription,
9
+ } from '@stigg/js-client-sdk';
3
10
  import styled from '@emotion/styled/macro';
11
+ import classNames from 'classnames';
12
+ import Grid from '@mui/material/Grid';
4
13
  import { PlanEntitlements } from './PlanEntitlements';
5
14
  import { PlanOfferingButton } from './PlanOfferingButton';
6
15
  import { PaywallPlan, SubscribeIntentionType } from './types';
7
16
  import { PaywallLocalization } from './paywallTextOverrides';
8
17
  import { flexLayoutMapper } from '../../theme/getResolvedTheme';
9
18
  import { Typography } from '../common/Typography';
10
- import classNames from 'classnames';
11
- import { Grid } from '@mui/material';
12
19
  import MiniSchedule from '../../assets/mini-schedule.svg';
13
20
  import { PlanPrice } from './PlanPrice';
14
21
  import { getSelectedTier } from '../utils/priceTierUtils';
15
22
 
23
+ const PlanOfferingButtonHeight = '66px';
24
+
16
25
  const PlanOfferingContainer = styled.div<{ $isHighlighted: boolean; $isCurrentPlan: boolean }>`
17
26
  position: relative;
18
27
  background-color: ${({ theme, $isCurrentPlan }) =>
@@ -82,6 +91,7 @@ type PlanOfferingProps = {
82
91
  paywallLocale: PaywallLocalization;
83
92
  locale: string;
84
93
  withStartingAtRow: boolean;
94
+ isCustomerInCustomPlan: boolean;
85
95
  };
86
96
 
87
97
  const NextPlanTagContainer = styled.div`
@@ -132,13 +142,15 @@ export function PlanOffering({
132
142
  paywallLocale,
133
143
  locale,
134
144
  withStartingAtRow,
145
+ isCustomerInCustomPlan,
135
146
  }: PlanOfferingProps) {
136
147
  const isNextPlan = plan.isNextPlan && plan.isNextPlan(billingPeriod);
137
- const planPrices = plan.pricePoints.filter(pricePoint => pricePoint.billingPeriod === billingPeriod);
148
+ const planPrices = plan.pricePoints.filter((pricePoint) => pricePoint.billingPeriod === billingPeriod);
138
149
  const paywallCalculatedPrice = plan.paywallCalculatedPricePoints?.find(
139
- pricePoint => pricePoint.billingPeriod === billingPeriod,
150
+ (pricePoint) => pricePoint.billingPeriod === billingPeriod,
140
151
  );
141
152
  const showStartingAt = planPrices.length > 1 && !!paywallCalculatedPrice?.additionalChargesMayApply;
153
+ const showCTAButton = !isCustomerInCustomPlan || plan.pricingType === PricingType.Custom;
142
154
 
143
155
  let planBadge = null;
144
156
  if (isNextPlan) {
@@ -159,10 +171,10 @@ export function PlanOffering({
159
171
 
160
172
  useEffect(() => {
161
173
  setSelectedTierByFeature(getSelectedTier(plan, billingPeriod, currentSubscription, selectedTierByFeature));
162
- }, [billingPeriod]);
174
+ }, [billingPeriod, currentSubscription, plan, selectedTierByFeature]);
163
175
 
164
176
  const onPlanButtonClick = (intentionType: SubscribeIntentionType) => {
165
- const billableFeatures: BillableFeature[] = Object.keys(selectedTierByFeature).map(featureId => ({
177
+ const billableFeatures: BillableFeature[] = Object.keys(selectedTierByFeature).map((featureId) => ({
166
178
  featureId,
167
179
  quantity: selectedTierByFeature[featureId].upTo,
168
180
  }));
@@ -176,8 +188,7 @@ export function PlanOffering({
176
188
  'stigg-current-plan': plan.isCurrentCustomerPlan,
177
189
  })}
178
190
  $isHighlighted={isHighlighted}
179
- $isCurrentPlan={plan.isCurrentCustomerPlan}
180
- >
191
+ $isCurrentPlan={plan.isCurrentCustomerPlan}>
181
192
  {planBadge}
182
193
 
183
194
  <HeaderWrapper className="stigg-header-wrapper">
@@ -206,19 +217,22 @@ export function PlanOffering({
206
217
  hasMonthlyPrice={hasMonthlyPrice}
207
218
  />
208
219
 
209
- <PlanOfferingButton
210
- isNextPlan={isNextPlan}
211
- customer={customer}
212
- plan={plan}
213
- currentSubscription={currentSubscription}
214
- billingPeriod={billingPeriod}
215
- isCustomerOnTrial={isCustomerOnTrial}
216
- onPlanSelected={onPlanButtonClick}
217
- paywallLocale={paywallLocale}
218
- hasTiersRow={withTiersRow}
219
- withTrialLeftRow={withTrialLeftRow}
220
- selectedTierByFeature={selectedTierByFeature}
221
- />
220
+ {showCTAButton ? (
221
+ <PlanOfferingButton
222
+ isNextPlan={isNextPlan}
223
+ customer={customer}
224
+ plan={plan}
225
+ currentSubscription={currentSubscription}
226
+ billingPeriod={billingPeriod}
227
+ isCustomerOnTrial={isCustomerOnTrial}
228
+ onPlanSelected={onPlanButtonClick}
229
+ paywallLocale={paywallLocale}
230
+ withTrialLeftRow={withTrialLeftRow}
231
+ selectedTierByFeature={selectedTierByFeature}
232
+ />
233
+ ) : (
234
+ <div style={{ height: PlanOfferingButtonHeight }} />
235
+ )}
222
236
 
223
237
  <Divider className="stigg-plan-header-divider" />
224
238
  </HeaderWrapper>
@@ -81,7 +81,6 @@ type PlanOfferingButtonProps = {
81
81
  isCustomerOnTrial: boolean;
82
82
  paywallLocale: PaywallLocalization;
83
83
  onPlanSelected: (intentionType: SubscribeIntentionType) => void | Promise<void>;
84
- hasTiersRow: boolean;
85
84
  withTrialLeftRow: boolean;
86
85
  selectedTierByFeature: Record<string, PriceTierFragment>;
87
86
  };
@@ -94,7 +93,6 @@ export function PlanOfferingButton({
94
93
  isCustomerOnTrial,
95
94
  onPlanSelected,
96
95
  paywallLocale,
97
- hasTiersRow,
98
96
  withTrialLeftRow,
99
97
  currentSubscription,
100
98
  selectedTierByFeature,
@@ -208,7 +206,7 @@ export function PlanOfferingButton({
208
206
  {isLoading && <LoadingIndicator color={theme.stigg.palette.text.disabled} loading size={16} />}
209
207
  </OfferingButton>
210
208
 
211
- {hasTiersRow && !withTrialLeftRow ? (
209
+ {!withTrialLeftRow ? (
212
210
  <div style={{ height: '20px' }} />
213
211
  ) : (
214
212
  <TrialDaysLeft className="stigg-trial-days-left-text" variant="h6" color="secondary">