@stigg/react-sdk 4.8.1 → 4.10.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 (55) hide show
  1. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.d.ts +1 -1
  2. package/dist/components/customerPortal/usage/featureUsage/EntitlementCTAButton.d.ts +1 -1
  3. package/dist/components/paywall/Paywall.d.ts +3 -2
  4. package/dist/components/paywall/PaywallContainer.d.ts +3 -2
  5. package/dist/components/paywall/types.d.ts +3 -0
  6. package/dist/components/paywall/utils/getPlansToDisplay.d.ts +2 -2
  7. package/dist/react-sdk.cjs.development.js +30 -23
  8. package/dist/react-sdk.cjs.development.js.map +1 -1
  9. package/dist/react-sdk.cjs.production.min.js +1 -1
  10. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  11. package/dist/react-sdk.esm.js +30 -23
  12. package/dist/react-sdk.esm.js.map +1 -1
  13. package/package.json +7 -4
  14. package/src/components/checkout/hooks/useCouponModel.ts +1 -1
  15. package/src/components/checkout/steps/addons/addon.utils.ts +6 -6
  16. package/src/components/common/PoweredByStigg.tsx +1 -2
  17. package/src/components/common/iconColor.ts +2 -4
  18. package/src/components/customerPortal/CustomerPortal.style.ts +2 -2
  19. package/src/components/customerPortal/CustomerPortalProvider.tsx +1 -2
  20. package/src/components/customerPortal/billing/InformationGrid.tsx +1 -2
  21. package/src/components/customerPortal/billing/InvoicesSection.tsx +9 -4
  22. package/src/components/customerPortal/common/ExternalLinkButton.tsx +2 -3
  23. package/src/components/customerPortal/common/SectionContainer.tsx +1 -1
  24. package/src/components/customerPortal/common/SectionHeader.ts +4 -2
  25. package/src/components/customerPortal/common/SkeletonButton.tsx +1 -1
  26. package/src/components/customerPortal/subscriptionOverview/ContactCustomerSupport.tsx +1 -2
  27. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverview.tsx +1 -2
  28. package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.tsx +3 -8
  29. package/src/components/customerPortal/subscriptionOverview/charges/ChargeItem.tsx +1 -1
  30. package/src/components/customerPortal/subscriptionOverview/charges/ChargeList.tsx +1 -1
  31. package/src/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.tsx +8 -4
  32. package/src/components/customerPortal/subscriptionOverview/tabs/AddonsList.tsx +1 -1
  33. package/src/components/customerPortal/subscriptionOverview/tabs/Promotions.tsx +1 -1
  34. package/src/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.tsx +2 -2
  35. package/src/components/customerPortal/subscriptionOverview/upcomingBilling/NoUpcomingBilling.tsx +4 -2
  36. package/src/components/customerPortal/subscriptionOverview/upcomingBilling/UpcomingBilling.tsx +1 -1
  37. package/src/components/customerPortal/types.ts +2 -2
  38. package/src/components/customerPortal/usage/featureUsage/EntitlementCTAButton.tsx +10 -3
  39. package/src/components/customerPortal/usage/featureUsage/FeatureUsage.style.ts +1 -1
  40. package/src/components/customerPortal/usage/featureUsage/FeatureUsage.tsx +2 -4
  41. package/src/components/hooks/useChargeSort.ts +2 -2
  42. package/src/components/paywall/Paywall.tsx +4 -2
  43. package/src/components/paywall/PaywallContainer.tsx +4 -1
  44. package/src/components/paywall/PlanEntitlements.tsx +4 -4
  45. package/src/components/paywall/paywallTextOverrides.ts +2 -2
  46. package/src/components/paywall/types.ts +2 -0
  47. package/src/components/paywall/utils/computeDefaultBillingPeriod.ts +2 -2
  48. package/src/components/paywall/utils/getPlansToDisplay.ts +10 -4
  49. package/src/components/paywall/utils/hasPricePoints.ts +3 -3
  50. package/src/components/utils/calculateDiscountRate.ts +3 -3
  51. package/src/components/utils/getFeatureName.ts +7 -3
  52. package/src/components/utils/getPlanPrice.ts +2 -2
  53. package/src/components/utils/priceTierUtils.ts +6 -4
  54. package/src/stories/Paywall.stories.tsx +1 -0
  55. package/src/types.ts +1 -1
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.8.1",
2
+ "version": "4.10.0",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -18,6 +18,8 @@
18
18
  "lint-fix": "yarn run lint --fix",
19
19
  "size": "size-limit",
20
20
  "analyze": "size-limit --why",
21
+ "fix:prettier": "prettier \"src/**/*.(js|jsx|ts|tsx)\" --write",
22
+ "pretty-quick": "pretty-quick --staged --pattern 'src/**/*.*(js|jsx|ts|tsx)'",
21
23
  "storybook": "export NODE_OPTIONS=--openssl-legacy-provider && start-storybook -p 6006",
22
24
  "build-storybook": "build-storybook",
23
25
  "prepare": "husky install",
@@ -87,14 +89,15 @@
87
89
  "eslint-plugin-import": "^2.28.1",
88
90
  "eslint-plugin-jest": "^25.3.2",
89
91
  "eslint-plugin-jsx-a11y": "^6.3.1",
90
- "eslint-plugin-prettier": "^5.0.0",
92
+ "eslint-plugin-prettier": "^4.0.0",
91
93
  "eslint-plugin-react": "^7.28.0",
92
94
  "eslint-plugin-react-hooks": "^4.2.0",
93
95
  "eslint-plugin-unused-imports": "^2.0.0",
94
96
  "husky": "^7.0.4",
95
97
  "lint-staged": "^14.0.1",
96
98
  "postcss": "^8.4.24",
97
- "prettier": "^3.0.2",
99
+ "prettier": "^2.4.1",
100
+ "pretty-quick": "^3.1.3",
98
101
  "react": "^18.0.0",
99
102
  "react-dom": "^18.0.0",
100
103
  "rollup-plugin-postcss": "^4.0.2",
@@ -119,10 +122,10 @@
119
122
  "immer": "^10.0.2",
120
123
  "lodash": "^4.17.21",
121
124
  "lodash-es": "^4.17.21",
125
+ "lottie-react": "^2.4.0",
122
126
  "moment": "^2.29.4",
123
127
  "react-feather": "^2.0.10",
124
128
  "react-loading-skeleton": "^3.1.0",
125
- "lottie-react": "^2.4.0",
126
129
  "react-spinners": "^0.13.3",
127
130
  "react-switch": "^7.0.0",
128
131
  "styled-components": "^5.3.6",
@@ -13,7 +13,7 @@ function useSetPromotionCode() {
13
13
  const [, setState] = useCheckoutContext();
14
14
 
15
15
  return (promotionCode: string) =>
16
- setState(draft => {
16
+ setState((draft) => {
17
17
  draft.promotionCode = promotionCode;
18
18
  });
19
19
  }
@@ -23,8 +23,8 @@ export function filterAddons({
23
23
  }: { addons?: Addon[] } & filterAddonsBaseProps): Addon[] {
24
24
  return (
25
25
  addons
26
- ?.filter(addon => filterAddonPricePointsByBillingPeriod(addon, billingPeriod))
27
- ?.map(addon => mapAddonPricePointsByBillingCountryCode({ addon, currency, billingCountryCode })) || []
26
+ ?.filter((addon) => filterAddonPricePointsByBillingPeriod(addon, billingPeriod))
27
+ ?.map((addon) => mapAddonPricePointsByBillingCountryCode({ addon, currency, billingCountryCode })) || []
28
28
  );
29
29
  }
30
30
 
@@ -36,8 +36,8 @@ export function filterSubscriptionAddons({
36
36
  }: { addons?: SubscriptionAddon[] } & filterAddonsBaseProps): SubscriptionAddon[] {
37
37
  return (
38
38
  addons
39
- ?.filter(addon => filterAddonPricePointsByBillingPeriod(addon.addon, billingPeriod))
40
- ?.map(addon => ({
39
+ ?.filter((addon) => filterAddonPricePointsByBillingPeriod(addon.addon, billingPeriod))
40
+ ?.map((addon) => ({
41
41
  ...addon,
42
42
  addon: mapAddonPricePointsByBillingCountryCode({ addon: addon.addon, currency, billingCountryCode }),
43
43
  })) || []
@@ -45,7 +45,7 @@ export function filterSubscriptionAddons({
45
45
  }
46
46
 
47
47
  function filterAddonPricePointsByBillingPeriod(addon: Addon, billingPeriod: BillingPeriod) {
48
- return addon.pricePoints.some(pricePoint => pricePoint.billingPeriod === billingPeriod);
48
+ return addon.pricePoints.some((pricePoint) => pricePoint.billingPeriod === billingPeriod);
49
49
  }
50
50
 
51
51
  function mapAddonPricePointsByBillingCountryCode({
@@ -60,7 +60,7 @@ function mapAddonPricePointsByBillingCountryCode({
60
60
  return {
61
61
  ...addon,
62
62
  pricePoints: addon.pricePoints.filter(
63
- pricePoint =>
63
+ (pricePoint) =>
64
64
  pricePoint.currency === currency &&
65
65
  (billingCountryCode ? pricePoint.billingCountryCode === billingCountryCode : true),
66
66
  ),
@@ -45,8 +45,7 @@ export function PoweredByStigg({ source, showWatermark, align, style = {} }: Pow
45
45
  $alignSelf={align}
46
46
  className={STIGG_WATERMARK_CLASSNAME}
47
47
  style={{ cursor: 'pointer', ...style }}
48
- onClick={onWatermarkClick}
49
- >
48
+ onClick={onWatermarkClick}>
50
49
  <PoweredByStiggThemedSvg />
51
50
  </StyledPoweredByStigg>
52
51
  );
@@ -1,10 +1,8 @@
1
1
  import { Theme } from '@emotion/react';
2
2
 
3
- export type IconColor =
4
- | 'primary'
5
- | 'secondary'
3
+ export type IconColor = 'primary' | 'secondary';
6
4
 
7
- export const getIconColor = (color: IconColor | string | undefined, theme: Theme ) => {
5
+ export const getIconColor = (color: IconColor | string | undefined, theme: Theme) => {
8
6
  switch (color) {
9
7
  case 'primary':
10
8
  return theme.stigg.palette.text.primary;
@@ -5,7 +5,7 @@ export const CustomerPortalLayout = styled.div`
5
5
  display: flex;
6
6
  flex-direction: column;
7
7
  align-items: center;
8
-
8
+
9
9
  & * {
10
10
  box-sizing: border-box;
11
11
  }
@@ -17,4 +17,4 @@ export const CustomerPortalSections = styled.div`
17
17
  flex-direction: column;
18
18
  align-items: center;
19
19
  row-gap: 24px;
20
- `;
20
+ `;
@@ -65,8 +65,7 @@ export function CustomerPortalProvider({
65
65
  textOverrides: resolvedTextOverrides,
66
66
  theme: customerPortalTheme,
67
67
  resourceId,
68
- }}
69
- >
68
+ }}>
70
69
  {children}
71
70
  </CustomerPortalContext.Provider>
72
71
  </SdkThemeProvider>
@@ -42,8 +42,7 @@ export function InformationGrid({ title, rows }: InformationGridProps) {
42
42
  variant="body1"
43
43
  color="secondary"
44
44
  style={{ width: 80 }}
45
- {...labelTypographyProps}
46
- >
45
+ {...labelTypographyProps}>
47
46
  {label}
48
47
  </Typography>
49
48
  <Typography className={`${classNamePrefix}-text`} variant="body1" color="secondary" {...valueTypographyProps}>
@@ -10,7 +10,9 @@ export function InvoicesSection() {
10
10
  const { customerPortal, isLoading, textOverrides, theme } = useCustomerPortalContext();
11
11
  const isLoadingData = !customerPortal || isLoading;
12
12
 
13
- const viewInvoiceHistoryButton = isLoadingData ? <SkeletonButton /> : customerPortal?.billingPortalUrl ? (
13
+ const viewInvoiceHistoryButton = isLoadingData ? (
14
+ <SkeletonButton />
15
+ ) : customerPortal?.billingPortalUrl ? (
14
16
  <ExternalLinkButton
15
17
  url={customerPortal.billingPortalUrl}
16
18
  text={textOverrides.viewInvoiceHistory}
@@ -26,10 +28,13 @@ export function InvoicesSection() {
26
28
  <SectionContainer
27
29
  className="stigg-invoices-section-layout"
28
30
  $backgroundColor={theme.backgroundColor}
29
- $borderColor={theme.borderColor}
30
- >
31
+ $borderColor={theme.borderColor}>
31
32
  <SectionHeader className="stigg-invoices-section-header">
32
- <SectionTitle isLoading={isLoadingData} className="stigg-invoices-section-title" title={textOverrides.invoicesTitle} />
33
+ <SectionTitle
34
+ isLoading={isLoadingData}
35
+ className="stigg-invoices-section-title"
36
+ title={textOverrides.invoicesTitle}
37
+ />
33
38
  {viewInvoiceHistoryButton}
34
39
  </SectionHeader>
35
40
  </SectionContainer>
@@ -28,9 +28,8 @@ export function ExternalLinkButton({ text, url, className }: ExternalLinkButtonP
28
28
  className={className}
29
29
  variant="outlined"
30
30
  startIcon={<LinkIcon size={20} strokeWidth={2.5} />}
31
- onClick={onClick}
32
- >
31
+ onClick={onClick}>
33
32
  <ExternalLinkText color="primary.main">{text}</ExternalLinkText>
34
33
  </StyledButton>
35
34
  );
36
- }
35
+ }
@@ -8,4 +8,4 @@ export const SectionContainer = styled.div<{ $backgroundColor: string; $borderCo
8
8
  background-color: ${({ $backgroundColor }) => $backgroundColor};
9
9
  border: ${({ $borderColor }) => `1px solid ${$borderColor}`};
10
10
  padding: 64px;
11
- `;
11
+ `;
@@ -5,9 +5,11 @@ export const SectionHeader = styled.div<{ $disableMargin?: boolean }>`
5
5
  align-items: center;
6
6
  justify-content: space-between;
7
7
 
8
- ${({ $disableMargin }) => !$disableMargin && `
8
+ ${({ $disableMargin }) =>
9
+ !$disableMargin &&
10
+ `
9
11
  &:not(:last-child) {
10
12
  margin-bottom: 32px;
11
13
  }
12
14
  `};
13
- `;
15
+ `;
@@ -3,4 +3,4 @@ import React from 'react';
3
3
 
4
4
  export function SkeletonButton() {
5
5
  return <Skeleton width={220} height={42} />;
6
- }
6
+ }
@@ -38,8 +38,7 @@ export function ContactCustomerSupport({ onContactSupport, label, linkLabel }: C
38
38
  className="stigg-contact-support-button"
39
39
  style={{ textTransform: 'none' }}
40
40
  variant="text"
41
- onClick={onContactSupport}
42
- >
41
+ onClick={onContactSupport}>
43
42
  {contactSupportText}
44
43
  </ContactSupportButton>
45
44
  ) : (
@@ -42,8 +42,7 @@ export function SubscriptionsOverview({
42
42
  <SectionContainer
43
43
  className="stigg-customer-portal-subscriptions-overview"
44
44
  $backgroundColor={theme.backgroundColor}
45
- $borderColor={theme.borderColor}
46
- >
45
+ $borderColor={theme.borderColor}>
47
46
  {!isLoadingData && activeSubscription && activeSubscription.scheduledUpdates && (
48
47
  <SubscriptionScheduledUpdatesAlert
49
48
  theme={theme}
@@ -28,20 +28,15 @@ export function SubscriptionsOverviewHeader({
28
28
  }: SubscriptionsOverviewHeaderProps) {
29
29
  return (
30
30
  <SectionHeader className="stigg-customer-portal-overview-header" $disableMargin>
31
- <SectionTitle title='Subscription' className="stigg-overview-title" />
31
+ <SectionTitle title="Subscription" className="stigg-overview-title" />
32
32
  {!hideManageButton && (
33
- <StyledButton
34
- className="stigg-manage-subscription-button"
35
- variant="outlined"
36
- onClick={onManageSubscription}
37
- >
33
+ <StyledButton className="stigg-manage-subscription-button" variant="outlined" onClick={onManageSubscription}>
38
34
  <StyledEditIcon className="stigg-manage-subscription-button-image" />
39
35
  <Typography
40
36
  className="stigg-manage-subscription-button-text"
41
37
  color="primary.main"
42
38
  style={{ marginLeft: '8px' }}
43
- variant="body1"
44
- >
39
+ variant="body1">
45
40
  {textOverrides?.manageSubscription}
46
41
  </Typography>
47
42
  </StyledButton>
@@ -32,7 +32,7 @@ export function ChargeItem({
32
32
  hasCustomSubscription,
33
33
  }: UsageBasedChargeProps) {
34
34
  return (
35
- <div className='stigg-charge-list-item' style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
35
+ <div className="stigg-charge-list-item" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
36
36
  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}>
37
37
  <div style={{ display: 'flex', gap: 12 }}>
38
38
  <LongText variant="body1" color="primary">
@@ -32,7 +32,7 @@ export function ChargeList({
32
32
  }
33
33
 
34
34
  return (
35
- <div className='stigg-charge-list' style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 32 }}>
35
+ <div className="stigg-charge-list" style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 32 }}>
36
36
  {filteredSubscriptionPrices.map(({ feature, price, billingModel }) => {
37
37
  if (!feature || !price) {
38
38
  return null;
@@ -11,15 +11,19 @@ type SubscriptionViewProps = {
11
11
  theme: CustomerPortalTheme;
12
12
  };
13
13
 
14
- export function SubscriptionView({ mainSubscription, trialSubscription, onManageSubscription, theme }: SubscriptionViewProps) {
14
+ export function SubscriptionView({
15
+ mainSubscription,
16
+ trialSubscription,
17
+ onManageSubscription,
18
+ theme,
19
+ }: SubscriptionViewProps) {
15
20
  return (
16
21
  <div className="stigg-subscription-view-layout">
17
22
  <Typography
18
23
  className="stigg-subscription-plan-name"
19
- variant='h1'
24
+ variant="h1"
20
25
  overrideColor={theme.planNameColor}
21
- style={{ marginTop: 8 }}
22
- >
26
+ style={{ marginTop: 8 }}>
23
27
  {mainSubscription.planName} plan
24
28
  </Typography>
25
29
 
@@ -6,7 +6,7 @@ import { useCustomerPortalContext } from '../../CustomerPortalProvider';
6
6
 
7
7
  export function AddonsList() {
8
8
  const { customerPortal } = useCustomerPortalContext();
9
- const addons = flatMap(customerPortal?.subscriptions, subscription => subscription.addons);
9
+ const addons = flatMap(customerPortal?.subscriptions, (subscription) => subscription.addons);
10
10
  if (isEmpty(addons)) {
11
11
  return null;
12
12
  }
@@ -47,7 +47,7 @@ export function Promotions() {
47
47
  Expiration date
48
48
  </Typography>
49
49
  </Row>
50
- {promotionalEntitlements?.map(promotionalEntitlement => (
50
+ {promotionalEntitlements?.map((promotionalEntitlement) => (
51
51
  <Row $borderColor={theme.borderColor}>
52
52
  <Typography variant="body1">{getPromotionTitle(promotionalEntitlement)}</Typography>
53
53
  <Typography variant="body1" color="disabled">
@@ -50,9 +50,9 @@ function TabTitle({ isSelected, label, icon }: { isSelected: boolean; label: str
50
50
  }
51
51
 
52
52
  export function SubscriptionTabs({ customerPortal, hiddenSections, textOverrides, theme }: SubscriptionTabsProps) {
53
- const allAddons = flatMap(customerPortal.subscriptions, subscription => subscription.addons);
53
+ const allAddons = flatMap(customerPortal.subscriptions, (subscription) => subscription.addons);
54
54
  const isSectionHidden = (sectionName: CustomerPortalSection) =>
55
- hiddenSections?.some(section => section === sectionName);
55
+ hiddenSections?.some((section) => section === sectionName);
56
56
  const showAddons = allAddons.length > 0 && !isSectionHidden('addons');
57
57
  const showPromotions =
58
58
  customerPortal.promotionalEntitlements.length > 0 && !isSectionHidden('promotionalEntitlements');
@@ -8,8 +8,10 @@ type NoUpcomingBillingProps = {
8
8
  export function NoUpcomingBilling({ description }: NoUpcomingBillingProps) {
9
9
  return (
10
10
  <>
11
- <Typography variant='h6' color='secondary'>No upcoming bill</Typography>
12
- <Typography variant='body1' color='secondary'>
11
+ <Typography variant="h6" color="secondary">
12
+ No upcoming bill
13
+ </Typography>
14
+ <Typography variant="body1" color="secondary">
13
15
  {description}
14
16
  </Typography>
15
17
  </>
@@ -35,7 +35,7 @@ export function UpcomingBilling({ subscription, theme, textOverrides, onContactS
35
35
  const { pricingType } = subscription;
36
36
  let content: ReactNode;
37
37
  const noUsageBasedPrices =
38
- subscription.prices?.every(price => price.billingModel !== BillingModel.UsageBased) ?? true;
38
+ subscription.prices?.every((price) => price.billingModel !== BillingModel.UsageBased) ?? true;
39
39
  const scheduledDowngradeToFree = subscription.scheduledUpdates?.find(
40
40
  ({ subscriptionScheduleType, targetPackage }) =>
41
41
  subscriptionScheduleType === SubscriptionScheduleType.Downgrade &&
@@ -1,4 +1,4 @@
1
1
  import { CustomerPortalEntitlement } from '@stigg/js-client-sdk';
2
- import { FeatureFragment, } from '@stigg/api-client-js/src/generated/sdk';
2
+ import { FeatureFragment } from '@stigg/api-client-js/src/generated/sdk';
3
3
 
4
- export type OnBuyMoreCallbackFn = (feature: FeatureFragment, entitlement: CustomerPortalEntitlement) => void
4
+ export type OnBuyMoreCallbackFn = (feature: FeatureFragment, entitlement: CustomerPortalEntitlement) => void;
@@ -23,8 +23,15 @@ export type EntitlementCtaButtonProps = {
23
23
  hasCustomSubscription: boolean;
24
24
  };
25
25
 
26
- export function EntitlementCtaButton({ entitlement, feature, onManageSubscription, onBuyMore, canBuyMore, canUpgradeSubscription, hasCustomSubscription }: EntitlementCtaButtonProps) {
27
-
26
+ export function EntitlementCtaButton({
27
+ entitlement,
28
+ feature,
29
+ onManageSubscription,
30
+ onBuyMore,
31
+ canBuyMore,
32
+ canUpgradeSubscription,
33
+ hasCustomSubscription,
34
+ }: EntitlementCtaButtonProps) {
28
35
  if (hasCustomSubscription || entitlement.hasUnlimitedUsage) {
29
36
  return null;
30
37
  }
@@ -50,4 +57,4 @@ export function EntitlementCtaButton({ entitlement, feature, onManageSubscriptio
50
57
  }
51
58
 
52
59
  return null;
53
- }
60
+ }
@@ -10,4 +10,4 @@ export const FeatureUsageContainer = styled.div<{ $highlight: boolean; $borderCo
10
10
  height: 100%;
11
11
 
12
12
  ${({ theme, $highlight }) => $highlight && `background-color: ${theme.stigg.palette.backgroundSection}`};
13
- `;
13
+ `;
@@ -51,8 +51,7 @@ export function FeatureUsage({
51
51
  ? 'Billed for committed usage'
52
52
  : 'Billed for actual usage'}
53
53
  </Typography>
54
- }
55
- >
54
+ }>
56
55
  <Icon icon="DollarCoin" svgStrokeColor={theme.iconsColor} />
57
56
  </InformationTooltip>
58
57
  )}
@@ -62,8 +61,7 @@ export function FeatureUsage({
62
61
  <LongText
63
62
  variant="body1"
64
63
  color={hasOverageUsage ? 'error' : 'primary'}
65
- data-testid={`usage-data-${entitlement.feature?.refId}`}
66
- >
64
+ data-testid={`usage-data-${entitlement.feature?.refId}`}>
67
65
  {entitlement.currentUsage?.toLocaleString()}
68
66
  {!entitlement.hasUnlimitedUsage &&
69
67
  ` / ${entitlement.usageLimit?.toLocaleString()} (${getUsagePercentage(
@@ -7,8 +7,8 @@ const CHARGES_BILLING_MODEL_ORDER = [BillingModel.FlatFee, BillingModel.PerUnit,
7
7
 
8
8
  export const sortCharges = (charges: Price[]) => {
9
9
  return sortBy(charges, [
10
- charge => CHARGES_BILLING_MODEL_ORDER.indexOf(charge.pricingModel),
11
- charge => charge.feature?.displayName,
10
+ (charge) => CHARGES_BILLING_MODEL_ORDER.indexOf(charge.pricingModel),
11
+ (charge) => charge.feature?.displayName,
12
12
  ]);
13
13
  };
14
14
 
@@ -4,7 +4,7 @@ import styled from '@emotion/styled/macro';
4
4
  import { PlanOffering } from './PlanOffering';
5
5
  import { BillingPeriodPicker } from './BillingPeriodPicker';
6
6
  import { calculatePaywallDiscountRate } from '../utils/calculateDiscountRate';
7
- import { OnPlanSelectedCallbackFn, PaywallPlan, SubscribeIntentionType } from './types';
7
+ import { ShouldHidePlanFn, OnPlanSelectedCallbackFn, PaywallPlan, SubscribeIntentionType } from './types';
8
8
  import { PaywallLocalization } from './paywallTextOverrides';
9
9
  import { PoweredByStigg } from '../common/PoweredByStigg';
10
10
  import { useStiggContext } from '../..';
@@ -51,6 +51,7 @@ type PaywallProps = {
51
51
  onPlanSelected: OnPlanSelectedCallbackFn;
52
52
  paywallLocale: PaywallLocalization;
53
53
  locale: string;
54
+ shouldHidePlan?: ShouldHidePlanFn;
54
55
  };
55
56
 
56
57
  export const Paywall = ({
@@ -65,13 +66,14 @@ export const Paywall = ({
65
66
  onPlanSelected,
66
67
  paywallLocale,
67
68
  locale,
69
+ shouldHidePlan,
68
70
  }: PaywallProps) => {
69
71
  const { stigg } = useStiggContext();
70
72
  const discountRate = calculatePaywallDiscountRate(plans);
71
73
  const shouldShowDescriptionSection = plans.some((plan) => !!plan.description);
72
74
  const hasMonthlyPrice = hasPricePointsForPlans(plans, BillingPeriod.Monthly);
73
75
  const hasAnnuallyPrice = hasPricePointsForPlans(plans, BillingPeriod.Annually);
74
- const plansToShow = getPlansToDisplay(plans, selectedBillingPeriod);
76
+ const plansToShow = getPlansToDisplay(plans, selectedBillingPeriod, shouldHidePlan);
75
77
 
76
78
  const handleOnSubscribe = useCallback(
77
79
  (plan: Plan, intentionType: SubscribeIntentionType, billableFeatures: BillableFeature[]) => {
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { BillingPeriod } from '@stigg/js-client-sdk';
3
3
  import { Paywall } from './Paywall';
4
4
  import { useLoadPaywallData } from './hooks/useLoadPaywallData';
5
- import { OnPlanSelectedCallbackFn } from './types';
5
+ import { ShouldHidePlanFn, OnPlanSelectedCallbackFn } from './types';
6
6
  import { getResolvedPaywallLocalize, PaywallLocalization } from './paywallTextOverrides';
7
7
  import { DeepPartial } from '../../types';
8
8
  import { PaywallLoader } from './PaywallLoader';
@@ -23,6 +23,7 @@ export type PaywallContainerProps = {
23
23
  onBillingPeriodChange?: (billingPeriod: BillingPeriod) => void;
24
24
  textOverrides?: DeepPartial<PaywallLocalization>;
25
25
  billingCountryCode?: string;
26
+ shouldHidePlan?: ShouldHidePlanFn;
26
27
  };
27
28
 
28
29
  export const PaywallContainer = ({
@@ -35,6 +36,7 @@ export const PaywallContainer = ({
35
36
  preferredBillingPeriod,
36
37
  onBillingPeriodChange,
37
38
  billingCountryCode,
39
+ shouldHidePlan,
38
40
  }: PaywallContainerProps) => {
39
41
  const hasCustomerPortalContext = useCheckContextExists(CustomerPortalContext);
40
42
  let isCustomerPortalLoading = false;
@@ -86,6 +88,7 @@ export const PaywallContainer = ({
86
88
  onPlanSelected={onPlanSelected}
87
89
  paywallLocale={paywallLocale}
88
90
  locale={locale}
91
+ shouldHidePlan={shouldHidePlan}
89
92
  />
90
93
  );
91
94
 
@@ -33,8 +33,8 @@ export function PlanEntitlements({
33
33
  billingPeriod: BillingPeriod;
34
34
  paywallLocale: PaywallLocalization;
35
35
  }) {
36
- const prices = plan.pricePoints?.filter(price => price.billingPeriod === billingPeriod);
37
- const unitBasedEntitlements = prices?.map(price => {
36
+ const prices = plan.pricePoints?.filter((price) => price.billingPeriod === billingPeriod);
37
+ const unitBasedEntitlements = prices?.map((price) => {
38
38
  const shouldRenderUnitBasedEntitlement =
39
39
  (price?.minUnitQuantity && price?.minUnitQuantity > 1) || price?.maxUnitQuantity;
40
40
 
@@ -59,8 +59,8 @@ export function PlanEntitlements({
59
59
  </Typography>
60
60
  {unitBasedEntitlements}
61
61
  {plan.entitlements
62
- .filter(entitlement => !(entitlement.hiddenFromWidgets || []).includes(WidgetType.Paywall))
63
- .map(entitlement => (
62
+ .filter((entitlement) => !(entitlement.hiddenFromWidgets || []).includes(WidgetType.Paywall))
63
+ .map((entitlement) => (
64
64
  <EntitlementRow
65
65
  key={entitlement.feature?.id}
66
66
  displayNameOverride={entitlement.displayNameOverride}
@@ -51,7 +51,7 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
51
51
  custom: 'Contact us',
52
52
  currentPlan: 'Current plan',
53
53
  startNew: 'Get started',
54
- switchToBillingPeriod: billingPeriod => {
54
+ switchToBillingPeriod: (billingPeriod) => {
55
55
  return billingPeriod === BillingPeriod.Monthly ? 'Switch to monthly billing' : 'Switch to annual billing';
56
56
  },
57
57
  cancelScheduledUpdate: 'Cancel',
@@ -59,7 +59,7 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
59
59
  price: {
60
60
  startingAtCaption: 'Starts at',
61
61
  pricePeriod: (billingPeriod: BillingPeriod) => (billingPeriod === BillingPeriod.Monthly ? '/ month' : '/ year'),
62
- free: currency => ({
62
+ free: (currency) => ({
63
63
  price: `${currency?.symbol}0`,
64
64
  }),
65
65
  custom: 'Custom',
@@ -61,3 +61,5 @@ export type OnPlanSelectedCallbackFn = ({
61
61
  selectedBillingPeriod: BillingPeriod;
62
62
  billableFeatures?: BillableFeature[];
63
63
  }) => void | Promise<void>;
64
+
65
+ export type ShouldHidePlanFn = ({ plan }: { plan: PaywallPlan }) => boolean | Promise<boolean>;
@@ -6,7 +6,7 @@ export function computeBillingPeriods(
6
6
  activeSubscriptions?: Subscription[] | null,
7
7
  preferredBillingPeriod?: BillingPeriod,
8
8
  ): { defaultBillingPeriod: BillingPeriod; availableBillingPeriods: BillingPeriod[] } {
9
- const billingPeriods = plans.flatMap(x => x.pricePoints).map(x => x.billingPeriod);
9
+ const billingPeriods = plans.flatMap((x) => x.pricePoints).map((x) => x.billingPeriod);
10
10
  const counts = countBy(billingPeriods);
11
11
 
12
12
  const availableBillingPeriods = uniq(billingPeriods);
@@ -15,7 +15,7 @@ export function computeBillingPeriods(
15
15
  if (preferredBillingPeriod && availableBillingPeriods.includes(preferredBillingPeriod)) {
16
16
  defaultBillingPeriod = preferredBillingPeriod;
17
17
  } else if (activeSubscriptions) {
18
- const activeSubscription = activeSubscriptions.find(x => x.status == SubscriptionStatus.Active);
18
+ const activeSubscription = activeSubscriptions.find((x) => x.status == SubscriptionStatus.Active);
19
19
 
20
20
  if (activeSubscription && activeSubscription.prices.length > 0) {
21
21
  defaultBillingPeriod = activeSubscription?.prices[0].billingPeriod;
@@ -1,7 +1,13 @@
1
1
  import { BillingPeriod, PricingType } from '@stigg/js-client-sdk';
2
- import { PaywallPlan } from '../types';
2
+ import { ShouldHidePlanFn, PaywallPlan } from '../types';
3
3
  import { hasPricePoints } from './hasPricePoints';
4
4
 
5
- export function getPlansToDisplay(plans: PaywallPlan[], selectedBillingPeriod: BillingPeriod): PaywallPlan[] {
6
- return plans.filter(plan => plan.pricingType !== PricingType.Paid || hasPricePoints(plan, selectedBillingPeriod));
7
- }
5
+ export function getPlansToDisplay(
6
+ plans: PaywallPlan[],
7
+ selectedBillingPeriod: BillingPeriod,
8
+ shouldHidePlan?: ShouldHidePlanFn,
9
+ ): PaywallPlan[] {
10
+ return plans
11
+ .filter((plan) => plan.pricingType !== PricingType.Paid || hasPricePoints(plan, selectedBillingPeriod))
12
+ .filter((plan) => !shouldHidePlan || !shouldHidePlan({ plan }));
13
+ }
@@ -2,9 +2,9 @@ import { PaywallPlan } from '../types';
2
2
  import { BillingPeriod } from '@stigg/js-client-sdk';
3
3
 
4
4
  export function hasPricePointsForPlans(plans: PaywallPlan[], billingPeriod: BillingPeriod): boolean {
5
- return plans.some(plan => hasPricePoints(plan, billingPeriod));
5
+ return plans.some((plan) => hasPricePoints(plan, billingPeriod));
6
6
  }
7
7
 
8
8
  export function hasPricePoints(plan: PaywallPlan, billingPeriod: BillingPeriod): boolean {
9
- return plan.pricePoints.some(pricePoint => pricePoint.billingPeriod === billingPeriod);
10
- }
9
+ return plan.pricePoints.some((pricePoint) => pricePoint.billingPeriod === billingPeriod);
10
+ }
@@ -14,14 +14,14 @@ export function calculateDiscountRate(monthlyPrice?: number | null, annuallyPric
14
14
  function getPlanBillingPeriodAmount(plan: PaywallPlan, billingPeriod: BillingPeriod) {
15
15
  let pricePoint: PaywallCalculatedPricePoint | Price | undefined;
16
16
 
17
- pricePoint = plan.paywallCalculatedPricePoints?.find(price => price.billingPeriod === billingPeriod);
17
+ pricePoint = plan.paywallCalculatedPricePoints?.find((price) => price.billingPeriod === billingPeriod);
18
18
 
19
19
  if (!pricePoint) {
20
- pricePoint = plan.pricePoints.find(price => price.billingPeriod === billingPeriod);
20
+ pricePoint = plan.pricePoints.find((price) => price.billingPeriod === billingPeriod);
21
21
  }
22
22
 
23
23
  if (!pricePoint?.amount) {
24
- const tieredPrice = plan.pricePoints.find(price => {
24
+ const tieredPrice = plan.pricePoints.find((price) => {
25
25
  return price.isTieredPrice && price.billingPeriod === billingPeriod;
26
26
  });
27
27