@stigg/react-sdk 4.3.1 → 4.4.0-beta.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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/components/checkout/Checkout.d.ts +5 -0
  3. package/dist/components/checkout/CheckoutContainer.d.ts +22 -0
  4. package/dist/components/checkout/CheckoutContainer.style.d.ts +26 -0
  5. package/dist/components/checkout/CheckoutProvider.d.ts +34 -0
  6. package/dist/components/checkout/components/Button.d.ts +8 -0
  7. package/dist/components/checkout/components/ContentLoadingSkeleton.d.ts +2 -0
  8. package/dist/components/checkout/components/InputField.d.ts +8 -0
  9. package/dist/components/checkout/components/Skeletons.style.d.ts +97 -0
  10. package/dist/components/checkout/components/index.d.ts +3 -0
  11. package/dist/components/checkout/formatting.d.ts +2 -0
  12. package/dist/components/checkout/hooks/index.d.ts +8 -0
  13. package/dist/components/checkout/hooks/useAddonsStepModel.d.ts +21 -0
  14. package/dist/components/checkout/hooks/useCheckoutModel.d.ts +10 -0
  15. package/dist/components/checkout/hooks/useCouponModel.d.ts +7 -0
  16. package/dist/components/checkout/hooks/useLoadCheckout.d.ts +11 -0
  17. package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +16 -0
  18. package/dist/components/checkout/hooks/usePlanStepModel.d.ts +23 -0
  19. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +13 -0
  20. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +26 -0
  21. package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +5 -0
  22. package/dist/components/checkout/hooks/useSubscriptionState.d.ts +2 -0
  23. package/dist/components/checkout/index.d.ts +3 -0
  24. package/dist/components/checkout/planHeader/PlanHeader.d.ts +7 -0
  25. package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +25 -0
  26. package/dist/components/checkout/planHeader/index.d.ts +1 -0
  27. package/dist/components/checkout/progressBar/CheckoutProgressBar.d.ts +2 -0
  28. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +48 -0
  29. package/dist/components/checkout/promotionCode/AddPromotionCode.d.ts +5 -0
  30. package/dist/components/checkout/promotionCode/AddPromotionCodeButton.d.ts +7 -0
  31. package/dist/components/checkout/promotionCode/AppliedPromotionCode.d.ts +6 -0
  32. package/dist/components/checkout/promotionCode/PromotionCodeSection.d.ts +5 -0
  33. package/dist/components/checkout/promotionCode/index.d.ts +1 -0
  34. package/dist/components/checkout/steps/addons/CheckoutAddonsStep.d.ts +2 -0
  35. package/dist/components/checkout/steps/addons/CheckoutAddonsStep.style.d.ts +93 -0
  36. package/dist/components/checkout/steps/addons/addon.utils.d.ts +15 -0
  37. package/dist/components/checkout/steps/addons/index.d.ts +1 -0
  38. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +20 -0
  39. package/dist/components/checkout/steps/payment/PaymentMethods.style.d.ts +117 -0
  40. package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -0
  41. package/dist/components/checkout/steps/payment/index.d.ts +1 -0
  42. package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -0
  43. package/dist/components/checkout/steps/payment/stripe/index.d.ts +3 -0
  44. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +33 -0
  45. package/dist/components/checkout/steps/payment/stripe/useStripeIntegration.d.ts +5 -0
  46. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +13 -0
  47. package/dist/components/checkout/steps/plan/BillingPeriodPicker.d.ts +9 -0
  48. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +52 -0
  49. package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +16 -0
  50. package/dist/components/checkout/steps/plan/CheckoutPlanStep.d.ts +2 -0
  51. package/dist/components/checkout/steps/plan/CheckoutPlanStep.style.d.ts +12 -0
  52. package/dist/components/checkout/steps/plan/index.d.ts +1 -0
  53. package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +2 -0
  54. package/dist/components/checkout/summary/CheckoutSuccess.d.ts +3 -0
  55. package/dist/components/checkout/summary/CheckoutSummary.d.ts +16 -0
  56. package/dist/components/checkout/summary/CheckoutSummarySkeleton.d.ts +2 -0
  57. package/dist/components/checkout/summary/components/CheckoutCaptions.d.ts +11 -0
  58. package/dist/components/checkout/summary/components/LineItems.d.ts +36 -0
  59. package/dist/components/checkout/summary/components/WithSkeleton.d.ts +6 -0
  60. package/dist/components/checkout/summary/index.d.ts +2 -0
  61. package/dist/components/checkout/textOverrides.d.ts +32 -0
  62. package/dist/components/checkout/theme.d.ts +12 -0
  63. package/dist/components/common/Icon.d.ts +3 -2
  64. package/dist/components/common/PoweredByStigg.d.ts +1 -1
  65. package/dist/components/{paywall/TiersLayout.d.ts → common/TiersSelectContainer.d.ts} +2 -3
  66. package/dist/components/common/customIcons.d.ts +19 -5
  67. package/dist/components/common/mapExternalTheme.d.ts +2 -1
  68. package/dist/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.d.ts +1 -1
  69. package/dist/components/hooks/useChargeSort.d.ts +3 -0
  70. package/dist/components/paywall/paywallTextOverrides.d.ts +0 -4
  71. package/dist/components/utils/calculateDiscountRate.d.ts +1 -0
  72. package/dist/components/utils/currencyUtils.d.ts +1 -1
  73. package/dist/components/utils/getPaidPriceText.d.ts +1 -3
  74. package/dist/components/{paywall/planPriceTier.d.ts → utils/priceTierUtils.d.ts} +3 -1
  75. package/dist/components/utils/priceUtils.d.ts +2 -0
  76. package/dist/index.d.ts +1 -0
  77. package/dist/react-sdk.cjs.development.js +6934 -238
  78. package/dist/react-sdk.cjs.development.js.map +1 -1
  79. package/dist/react-sdk.cjs.production.min.js +1 -1
  80. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  81. package/dist/react-sdk.esm.js +7093 -242
  82. package/dist/react-sdk.esm.js.map +1 -1
  83. package/dist/stories/Checkout.stories.d.ts +3 -0
  84. package/dist/stories/CustomerPortal.stories.d.ts +1 -1
  85. package/dist/theme/getResolvedTheme.d.ts +4 -0
  86. package/dist/theme/types.d.ts +4 -0
  87. package/package.json +11 -5
  88. package/src/assets/arrow-forward.svg +3 -0
  89. package/src/assets/arrow-right.svg +6 -0
  90. package/src/assets/check.svg +5 -0
  91. package/src/assets/close.svg +3 -0
  92. package/src/assets/lottie/checkout-success.json +1 -0
  93. package/src/assets/nyancat.svg +634 -0
  94. package/src/assets/outlined-checked-circle-disabled.svg +6 -0
  95. package/src/assets/outlined-checked-circle.svg +6 -0
  96. package/src/assets/outlined-circle.svg +3 -0
  97. package/src/assets/payment-method.svg +11 -0
  98. package/src/assets/plus-icon.svg +6 -0
  99. package/src/assets/trash.svg +8 -0
  100. package/src/components/checkout/Checkout.tsx +30 -0
  101. package/src/components/checkout/CheckoutContainer.style.ts +35 -0
  102. package/src/components/checkout/CheckoutContainer.tsx +99 -0
  103. package/src/components/checkout/CheckoutProvider.tsx +149 -0
  104. package/src/components/checkout/components/Button.tsx +51 -0
  105. package/src/components/checkout/components/ContentLoadingSkeleton.tsx +41 -0
  106. package/src/components/checkout/components/InputField.tsx +22 -0
  107. package/src/components/checkout/components/Skeletons.style.ts +27 -0
  108. package/src/components/checkout/components/index.ts +3 -0
  109. package/src/components/checkout/formatting.ts +12 -0
  110. package/src/components/checkout/hooks/index.ts +8 -0
  111. package/src/components/checkout/hooks/useAddonsStepModel.ts +96 -0
  112. package/src/components/checkout/hooks/useCheckoutModel.ts +32 -0
  113. package/src/components/checkout/hooks/useCouponModel.ts +28 -0
  114. package/src/components/checkout/hooks/useLoadCheckout.ts +39 -0
  115. package/src/components/checkout/hooks/usePaymentStepModel.ts +49 -0
  116. package/src/components/checkout/hooks/usePlanStepModel.ts +169 -0
  117. package/src/components/checkout/hooks/usePreviewSubscription.ts +82 -0
  118. package/src/components/checkout/hooks/useProgressBarModel.ts +89 -0
  119. package/src/components/checkout/hooks/useSubscriptionModel.ts +16 -0
  120. package/src/components/checkout/hooks/useSubscriptionState.ts +26 -0
  121. package/src/components/checkout/index.ts +3 -0
  122. package/src/components/checkout/planHeader/PlanHeader.style.tsx +23 -0
  123. package/src/components/checkout/planHeader/PlanHeader.tsx +59 -0
  124. package/src/components/checkout/planHeader/index.ts +1 -0
  125. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +34 -0
  126. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +53 -0
  127. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +85 -0
  128. package/src/components/checkout/promotionCode/AddPromotionCodeButton.tsx +39 -0
  129. package/src/components/checkout/promotionCode/AppliedPromotionCode.tsx +37 -0
  130. package/src/components/checkout/promotionCode/PromotionCodeSection.tsx +27 -0
  131. package/src/components/checkout/promotionCode/index.ts +1 -0
  132. package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +24 -0
  133. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +125 -0
  134. package/src/components/checkout/steps/addons/addon.utils.ts +68 -0
  135. package/src/components/checkout/steps/addons/index.ts +1 -0
  136. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +26 -0
  137. package/src/components/checkout/steps/payment/PaymentMethods.tsx +86 -0
  138. package/src/components/checkout/steps/payment/PaymentStep.tsx +50 -0
  139. package/src/components/checkout/steps/payment/index.ts +1 -0
  140. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +45 -0
  141. package/src/components/checkout/steps/payment/stripe/index.ts +3 -0
  142. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +109 -0
  143. package/src/components/checkout/steps/payment/stripe/useStripeIntegration.ts +27 -0
  144. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +104 -0
  145. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +46 -0
  146. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +63 -0
  147. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +138 -0
  148. package/src/components/checkout/steps/plan/CheckoutPlanStep.style.tsx +6 -0
  149. package/src/components/checkout/steps/plan/CheckoutPlanStep.tsx +20 -0
  150. package/src/components/checkout/steps/plan/index.ts +1 -0
  151. package/src/components/checkout/steps/surprise/SurpriseStep.tsx +27 -0
  152. package/src/components/checkout/summary/CheckoutSuccess.tsx +32 -0
  153. package/src/components/checkout/summary/CheckoutSummary.tsx +288 -0
  154. package/src/components/checkout/summary/CheckoutSummarySkeleton.tsx +40 -0
  155. package/src/components/checkout/summary/components/CheckoutCaptions.tsx +120 -0
  156. package/src/components/checkout/summary/components/LineItems.tsx +177 -0
  157. package/src/components/checkout/summary/components/WithSkeleton.tsx +16 -0
  158. package/src/components/checkout/summary/index.ts +2 -0
  159. package/src/components/checkout/textOverrides.ts +62 -0
  160. package/src/components/checkout/theme.ts +43 -0
  161. package/src/components/common/Icon.tsx +17 -22
  162. package/src/components/common/PoweredByStigg.tsx +1 -1
  163. package/src/components/{paywall/TiersLayout.tsx → common/TiersSelectContainer.tsx} +8 -7
  164. package/src/components/common/Typography.tsx +11 -1
  165. package/src/components/common/customIcons.ts +19 -28
  166. package/src/components/common/mapExternalTheme.ts +29 -9
  167. package/src/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.tsx +6 -12
  168. package/src/components/hooks/useChargeSort.ts +17 -0
  169. package/src/components/paywall/Paywall.tsx +1 -1
  170. package/src/components/paywall/PlanOffering.tsx +1 -1
  171. package/src/components/paywall/PlanOfferingButton.tsx +1 -1
  172. package/src/components/paywall/PlanPrice.tsx +5 -13
  173. package/src/components/paywall/paywallTextOverrides.ts +0 -3
  174. package/src/components/paywall/utils/calculateUnitQuantityText.ts +9 -4
  175. package/src/components/utils/calculateDiscountRate.ts +1 -1
  176. package/src/components/utils/currencyUtils.ts +1 -1
  177. package/src/components/utils/getPaidPriceText.ts +4 -10
  178. package/src/components/utils/getPlanPrice.ts +1 -1
  179. package/src/components/{paywall/planPriceTier.ts → utils/priceTierUtils.ts} +25 -3
  180. package/src/components/utils/priceUtils.ts +10 -0
  181. package/src/index.ts +1 -0
  182. package/src/stories/Checkout.stories.tsx +61 -0
  183. package/src/stories/CustomerPortal.stories.tsx +1 -1
  184. package/src/theme/Theme.tsx +6 -6
  185. package/src/theme/getResolvedTheme.ts +7 -1
  186. package/src/theme/types.ts +4 -0
@@ -0,0 +1,62 @@
1
+ import { BillingPeriod, SubscriptionPreviewTaxDetails } from '@stigg/js-client-sdk';
2
+ import moment from 'moment';
3
+ import merge from 'lodash/merge';
4
+ import { DeepPartial } from '../../types';
5
+ import { formatBillingPeriod } from './formatting';
6
+
7
+ export type CheckoutLocalization = {
8
+ changePlan: string;
9
+ billingPeriodsTitle: string;
10
+ addAddonText: string;
11
+ newPaymentMethodText: string;
12
+ newPaymentMethodCardTitle: string;
13
+ newPaymentMethodBillingAddressTitle: string;
14
+ baseChargeText: string | ((params: { billingPeriod: BillingPeriod }) => string);
15
+ totalText: string;
16
+ subTotalText: string;
17
+ addCouponCodeText: string;
18
+ couponCodeTitle: string;
19
+ addonsSectionTitle: string;
20
+ changesWillApplyAtEndOfBillingPeriod: string | ((params: { billingPeriodEnd: Date }) => string);
21
+ checkoutButton: {
22
+ nextText: string;
23
+ downgradeText: string;
24
+ upgradeText: string;
25
+ purchaseText: string;
26
+ };
27
+ appliedCreditsTitle: string;
28
+ taxTitle: (params: { taxDetails: SubscriptionPreviewTaxDetails }) => string;
29
+ };
30
+
31
+ export function getResolvedCheckoutLocalize(
32
+ localizeOverride?: DeepPartial<CheckoutLocalization>,
33
+ ): CheckoutLocalization {
34
+ const checkoutDefaultLocalization: CheckoutLocalization = {
35
+ changePlan: 'Change plan',
36
+ billingPeriodsTitle: 'Billing cycle',
37
+ addAddonText: 'Add',
38
+ newPaymentMethodText: 'New payment method',
39
+ newPaymentMethodBillingAddressTitle: 'Billing address',
40
+ newPaymentMethodCardTitle: 'Payment method',
41
+ baseChargeText: ({ billingPeriod }) => `${formatBillingPeriod(billingPeriod)} charge`,
42
+ totalText: 'Total due today',
43
+ subTotalText: 'Subtotal',
44
+ addCouponCodeText: 'Add coupon code',
45
+ couponCodeTitle: 'Coupon code',
46
+ addonsSectionTitle: 'Add-ons',
47
+ changesWillApplyAtEndOfBillingPeriod: ({ billingPeriodEnd }) =>
48
+ `Your changes will apply on the end of your current billing cycle on ${moment(billingPeriodEnd).format(
49
+ 'MMM D, YYYY',
50
+ )}.`,
51
+ checkoutButton: {
52
+ nextText: 'Next',
53
+ downgradeText: 'Downgrade',
54
+ upgradeText: 'Upgrade',
55
+ purchaseText: 'Purchase',
56
+ },
57
+ appliedCreditsTitle: 'Applied credits',
58
+ taxTitle: ({ taxDetails }) => `${taxDetails.displayName} (${taxDetails?.percentage}%)`,
59
+ };
60
+
61
+ return merge(checkoutDefaultLocalization, localizeOverride);
62
+ }
@@ -0,0 +1,43 @@
1
+ import { CheckoutConfiguration } from '@stigg/js-client-sdk';
2
+ import { StiggTheme } from '../../theme/types';
3
+ import { DeepPartial } from '../../types';
4
+
5
+ export type CheckoutTheme = {
6
+ primary: string;
7
+ textColor: string;
8
+ backgroundColor: string;
9
+ borderColor: string;
10
+ selectionColor: string;
11
+ summaryBackgroundColor: string;
12
+ };
13
+
14
+ const defaultCheckoutTheme: CheckoutTheme = {
15
+ primary: 'rgb(50, 126, 238)',
16
+ textColor: 'rgb(0, 30, 108)',
17
+ backgroundColor: 'rgb(255, 255, 255)',
18
+ borderColor: 'rgb(235, 237, 243)',
19
+ selectionColor: 'rgb(229, 242, 255)',
20
+ summaryBackgroundColor: 'rgb(109, 121, 144)',
21
+ };
22
+
23
+ export function getResolvedCheckoutTheme(
24
+ globalTheme: StiggTheme,
25
+ themeOverride?: DeepPartial<CheckoutTheme>,
26
+ _remoteConfiguration?: CheckoutConfiguration | null, // all the remote colors override theme colors, no need to use them here
27
+ ): CheckoutTheme {
28
+ const { palette: globalPalette } = globalTheme || {};
29
+
30
+ return {
31
+ primary: themeOverride?.primary || globalPalette?.primary || defaultCheckoutTheme.primary,
32
+ textColor: themeOverride?.textColor || globalPalette?.text.primary || defaultCheckoutTheme.textColor,
33
+ backgroundColor:
34
+ themeOverride?.backgroundColor || globalPalette?.backgroundPaper || defaultCheckoutTheme.backgroundColor,
35
+ borderColor: themeOverride?.borderColor || globalPalette?.outlinedBorder || defaultCheckoutTheme.borderColor,
36
+ selectionColor:
37
+ themeOverride?.selectionColor || globalPalette?.backgroundSection || defaultCheckoutTheme.selectionColor,
38
+ summaryBackgroundColor:
39
+ themeOverride?.summaryBackgroundColor ||
40
+ globalPalette?.backgroundHighlight ||
41
+ defaultCheckoutTheme.summaryBackgroundColor,
42
+ };
43
+ }
@@ -2,12 +2,14 @@ import React from 'react';
2
2
  import styled from '@emotion/styled/macro';
3
3
  import { CSSProperties } from 'react';
4
4
  import { css, Theme, useTheme } from '@emotion/react';
5
- import { ICON_COMPONENTS, Icons } from './customIcons';
6
5
  import { getIconColor, IconColor } from './iconColor';
6
+ import * as customIcons from './customIcons';
7
7
 
8
- const IconWrapper = styled.div<{ $pathColor?: string, $rectColor?: string; $strokeColor?: string }>`
8
+ export type Icons = keyof typeof customIcons;
9
+
10
+ const IconWrapper = styled.div<{ $pathColor?: string; $rectColor?: string; $strokeColor?: string }>`
9
11
  ${({ $pathColor }) =>
10
- $pathColor &&
12
+ $pathColor &&
11
13
  css`
12
14
  path {
13
15
  fill: ${$pathColor};
@@ -15,20 +17,20 @@ const IconWrapper = styled.div<{ $pathColor?: string, $rectColor?: string; $stro
15
17
  `}
16
18
 
17
19
  ${({ $rectColor }) =>
18
- $rectColor &&
19
- css`
20
- svg rect {
21
- fill: ${$rectColor};
22
- }
20
+ $rectColor &&
21
+ css`
22
+ svg rect {
23
+ fill: ${$rectColor};
24
+ }
23
25
  `}
24
26
 
25
27
 
26
28
  ${({ $strokeColor }) =>
27
- $strokeColor &&
28
- css`
29
- g {
30
- stroke: ${$strokeColor};
31
- }
29
+ $strokeColor &&
30
+ css`
31
+ g {
32
+ stroke: ${$strokeColor};
33
+ }
32
34
  `}
33
35
  `;
34
36
 
@@ -41,15 +43,8 @@ export type IconProps = {
41
43
  svgStrokeColor?: IconColor | string;
42
44
  };
43
45
 
44
- export function Icon({
45
- icon,
46
- className,
47
- style,
48
- svgPathColor,
49
- svgRectColor,
50
- svgStrokeColor,
51
- }: IconProps) {
52
- const IconComponent = ICON_COMPONENTS[icon];
46
+ export function Icon({ icon, className, style, svgPathColor, svgRectColor, svgStrokeColor }: IconProps) {
47
+ const IconComponent = (customIcons as any)[icon];
53
48
  const theme = useTheme() as Theme;
54
49
 
55
50
  return (
@@ -4,7 +4,7 @@ import styled from '@emotion/styled/macro';
4
4
 
5
5
  export const STIGG_WATERMARK_CLASSNAME = 'stigg-watermark';
6
6
 
7
- export type PoweredByStiggSources = 'paywall' | 'customer_portal';
7
+ export type PoweredByStiggSources = 'paywall' | 'customer_portal' | 'checkout';
8
8
 
9
9
  const PoweredByStiggThemedSvg = styled(PoweredByStiggSvg)`
10
10
  * {
@@ -1,10 +1,10 @@
1
- import { PaywallPlan } from './types';
2
1
  import { PriceTierFragment } from '@stigg/js-client-sdk';
3
2
  import { MenuItem, OutlinedInput, Select, SelectChangeEvent } from '@mui/material';
4
3
  import { Typography } from '../common/Typography';
5
4
  import { map } from 'lodash';
6
5
  import React, { ReactNode } from 'react';
7
6
  import styled from '@emotion/styled/macro';
7
+ import { getTierByQuantity } from '../utils/priceTierUtils';
8
8
 
9
9
  const TierSelect = styled(Select)`
10
10
  border-radius: 10px;
@@ -24,32 +24,33 @@ const TierInput = styled(OutlinedInput)`
24
24
  }
25
25
  `;
26
26
 
27
- export function TiersLayout({
28
- plan,
27
+ export function TiersSelectContainer({
28
+ componentId,
29
29
  tiers,
30
30
  tierUnits,
31
31
  selectedTier,
32
32
  handleTierChange,
33
33
  }: {
34
- plan: PaywallPlan;
34
+ componentId: string;
35
35
  tiers?: PriceTierFragment[] | null;
36
36
  tierUnits?: string;
37
37
  selectedTier?: PriceTierFragment;
38
38
  handleTierChange: (tier: PriceTierFragment) => void;
39
39
  }) {
40
40
  const handleChange = (event: SelectChangeEvent<unknown>, _: ReactNode) => {
41
- handleTierChange(tiers!.find(tier => tier.upTo.toString() === event.target.value)!);
41
+ if (!tiers) return;
42
+
43
+ handleTierChange(getTierByQuantity(tiers, event.target.value as number)!);
42
44
  };
43
45
 
44
46
  return (
45
47
  <Typography className="stigg-price-tier-select" style={{ minHeight: '46px' }}>
46
48
  {tiers ? (
47
49
  <TierSelect
48
- labelId="demo-simple-select-label"
49
- id={`select_${plan.id}`}
50
50
  value={selectedTier ? selectedTier.upTo.toString() : tiers[0].upTo.toString()}
51
51
  fullWidth
52
52
  onChange={handleChange}
53
+ id={componentId}
53
54
  input={<TierInput />}
54
55
  MenuProps={{
55
56
  MenuListProps: { disablePadding: true },
@@ -86,7 +86,17 @@ function getFontWeight(theme: Theme, variant: TypographyProps['variant']) {
86
86
  }
87
87
 
88
88
  export const Typography = forwardRef((props: TypographyProps, ref) => {
89
- const { children, span, style, fontWeight, variant = 'body1', color = 'primary', overrideColor, bold, ...rest } = props;
89
+ const {
90
+ children,
91
+ span,
92
+ style,
93
+ fontWeight,
94
+ variant = 'body1',
95
+ color = 'primary',
96
+ overrideColor,
97
+ bold,
98
+ ...rest
99
+ } = props;
90
100
  const theme = useTheme() as Theme;
91
101
  const level = getLevel(variant);
92
102
  const levelClassName = `typography-level-${level}`;
@@ -1,28 +1,19 @@
1
- import { ReactElement, SVGProps } from 'react';
2
- import RenewSubscription from '../../assets/subscription-renews-icon.svg';
3
- import BillingInfoCustomer from '../../assets/billing-info-customer.svg';
4
- import CreditCard from '../../assets/credit-card.svg';
5
- import ScheduleBox from '../../assets/schedule-box.svg';
6
- import ScheduleClock from '../../assets/schedule.svg';
7
- import Restore from '../../assets/restore.svg';
8
- import MiniSchedule from '../../assets/mini-schedule.svg';
9
- import DollarCoin from '../../assets/dollar-coin.svg';
10
- import Promotions from '../../assets/promotions.svg';
11
- import Addons from '../../assets/addons.svg';
12
- import ContactSupport from '../../assets/contact-support.svg';
13
-
14
- export const ICON_COMPONENTS: {[name: string]: ((props: SVGProps<SVGElement>) => ReactElement)} = {
15
- RenewSubscription,
16
- BillingInfoCustomer,
17
- CreditCard,
18
- ScheduleBox,
19
- ScheduleClock,
20
- Restore,
21
- MiniSchedule,
22
- DollarCoin,
23
- Promotions,
24
- Addons,
25
- ContactSupport,
26
- };
27
-
28
- export type Icons = keyof typeof ICON_COMPONENTS;
1
+ export { default as Addons } from '../../assets/addons.svg';
2
+ export { default as BillingInfoCustomer } from '../../assets/billing-info-customer.svg';
3
+ export { default as ContactSupport } from '../../assets/contact-support.svg';
4
+ export { default as CreditCard } from '../../assets/credit-card.svg';
5
+ export { default as DollarCoin } from '../../assets/dollar-coin.svg';
6
+ export { default as MiniSchedule } from '../../assets/mini-schedule.svg';
7
+ export { default as Promotions } from '../../assets/promotions.svg';
8
+ export { default as Restore } from '../../assets/restore.svg';
9
+ export { default as ScheduleBox } from '../../assets/schedule-box.svg';
10
+ export { default as ScheduleClock } from '../../assets/schedule.svg';
11
+ export { default as RenewSubscription } from '../../assets/subscription-renews-icon.svg';
12
+ export { default as Trash } from '../../assets/trash.svg';
13
+ export { default as PaymentMethod } from '../../assets/payment-method.svg';
14
+ export { default as OutlinedCircle } from '../../assets/outlined-circle.svg';
15
+ export { default as OutlinedCheckedCircle } from '../../assets/outlined-checked-circle.svg';
16
+ export { default as OutlinedCheckedCircleDisabled } from '../../assets/outlined-checked-circle-disabled.svg';
17
+ export { default as ArrowForward } from '../../assets/arrow-forward.svg';
18
+ export { default as Close } from '../../assets/close.svg';
19
+ export { default as Check } from '../../assets/check.svg';
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  Alignment,
3
+ CheckoutConfiguration,
3
4
  CustomerPortalConfiguration,
4
5
  FontWeight as JSFontWeight,
5
6
  PaywallConfiguration,
7
+ TypographyConfiguration,
6
8
  } from '@stigg/js-client-sdk';
7
9
  import { CustomizedTheme } from '../../theme/Theme';
8
10
  import { HorizontalAlignment, FontWeight } from '../../theme/types';
9
11
 
10
- function addCssUnits(value?: number | null, unit: string = 'px') {
12
+ function addCssUnits(value?: number | null, unit = 'px') {
11
13
  if (!value) {
12
14
  return undefined;
13
15
  }
@@ -29,10 +31,7 @@ function mapFontWeight(defaultValue: FontWeight, fontWeight?: JSFontWeight | nul
29
31
  }
30
32
  }
31
33
 
32
- function mapTypography(
33
- configuration: CustomerPortalConfiguration | PaywallConfiguration,
34
- ): CustomizedTheme['typography'] {
35
- const { typography } = configuration;
34
+ function mapTypography(typography?: TypographyConfiguration | null): CustomizedTheme['typography'] {
36
35
  return {
37
36
  fontFamilyUrl: typography?.fontFamily || undefined,
38
37
  h1: {
@@ -58,6 +57,7 @@ function mapAlignment(alignment?: Alignment | null): HorizontalAlignment | undef
58
57
  if (!alignment) {
59
58
  return undefined;
60
59
  }
60
+
61
61
  switch (alignment) {
62
62
  case Alignment.Left:
63
63
  return 'left';
@@ -65,11 +65,14 @@ function mapAlignment(alignment?: Alignment | null): HorizontalAlignment | undef
65
65
  return 'center';
66
66
  case Alignment.Right:
67
67
  return 'right';
68
+ default: {
69
+ return undefined;
70
+ }
68
71
  }
69
72
  }
70
73
 
71
74
  export function mapCustomerPortalConfiguration(configuration: CustomerPortalConfiguration): CustomizedTheme {
72
- const { palette } = configuration;
75
+ const { palette, typography } = configuration;
73
76
  return {
74
77
  palette: {
75
78
  primary: palette?.primary || undefined,
@@ -80,12 +83,12 @@ export function mapCustomerPortalConfiguration(configuration: CustomerPortalConf
80
83
  primary: palette?.textColor || undefined,
81
84
  },
82
85
  },
83
- typography: mapTypography(configuration),
86
+ typography: mapTypography(typography),
84
87
  };
85
88
  }
86
89
 
87
90
  export function mapPaywallConfiguration(paywallConfiguration: PaywallConfiguration): CustomizedTheme {
88
- const { palette, layout, customCss } = paywallConfiguration;
91
+ const { palette, layout, customCss, typography } = paywallConfiguration;
89
92
  return {
90
93
  customCss: customCss || undefined,
91
94
  palette: {
@@ -97,7 +100,7 @@ export function mapPaywallConfiguration(paywallConfiguration: PaywallConfigurati
97
100
  primary: palette?.textColor || undefined,
98
101
  },
99
102
  },
100
- typography: mapTypography(paywallConfiguration),
103
+ typography: mapTypography(typography),
101
104
  layout: {
102
105
  ctaAlignment: mapAlignment(layout?.alignment),
103
106
  headerAlignment: mapAlignment(layout?.alignment),
@@ -109,3 +112,20 @@ export function mapPaywallConfiguration(paywallConfiguration: PaywallConfigurati
109
112
  },
110
113
  };
111
114
  }
115
+
116
+ export function mapCheckoutConfiguration(configuration: CheckoutConfiguration): CustomizedTheme {
117
+ const { palette, typography } = configuration;
118
+ return {
119
+ palette: {
120
+ primary: palette?.primary || undefined,
121
+ backgroundPaper: palette?.backgroundColor || undefined,
122
+ outlinedBorder: palette?.borderColor || undefined,
123
+ text: {
124
+ primary: palette?.textColor || undefined,
125
+ },
126
+ backgroundHighlight: palette?.selectionColor || undefined,
127
+ backgroundSection: palette?.summaryBackgroundColor || undefined,
128
+ },
129
+ typography: mapTypography(typography),
130
+ };
131
+ }
@@ -10,8 +10,7 @@ import { CustomerPortalSection } from '../../CustomerPortal';
10
10
  import { CustomerPortalLocalization } from '../../customerPortalTextOverrides';
11
11
  import { StyledTabs, TabContent, TabsLayout } from './SubscriptionTabs.style';
12
12
  import { CustomerPortalTheme } from '../../customerPortalTheme';
13
- import { Icon } from '../../../common/Icon';
14
- import { Icons } from '../../../common/customIcons';
13
+ import { Icon, Icons } from '../../../common/Icon';
15
14
  import { FontWeight } from 'styled-typography';
16
15
 
17
16
  type TabPanelProps = {
@@ -41,21 +40,16 @@ export type SubscriptionTabsProps = {
41
40
  function TabTitle({ isSelected, label, icon }: { isSelected: boolean; label: string; icon: Icons }) {
42
41
  const color = isSelected ? 'primary' : 'secondary';
43
42
  return (
44
- <div style={{display: 'flex', gap: 8, alignItems: 'center' }}>
43
+ <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
45
44
  <Icon icon={icon} svgStrokeColor={color} />
46
- <Typography variant="h6" bold={isSelected} fontWeight={FontWeight.Medium} color={color}>
45
+ <Typography variant="h6" bold={isSelected} fontWeight={FontWeight.Medium} color={color}>
47
46
  {label}
48
47
  </Typography>
49
48
  </div>
50
49
  );
51
50
  }
52
51
 
53
- export function SubscriptionTabs({
54
- customerPortal,
55
- hiddenSections,
56
- textOverrides,
57
- theme,
58
- }: SubscriptionTabsProps) {
52
+ export function SubscriptionTabs({ customerPortal, hiddenSections, textOverrides, theme }: SubscriptionTabsProps) {
59
53
  const allAddons = flatMap(customerPortal.subscriptions, subscription => subscription.addons);
60
54
  const isSectionHidden = (sectionName: CustomerPortalSection) =>
61
55
  hiddenSections?.some(section => section === sectionName);
@@ -81,14 +75,14 @@ export function SubscriptionTabs({
81
75
  <Tab
82
76
  sx={{ textTransform: 'none' }}
83
77
  value={1}
84
- label={<TabTitle isSelected={value === 1} label={textOverrides.addonsTabTitle} icon='Addons' />}
78
+ label={<TabTitle isSelected={value === 1} label={textOverrides.addonsTabTitle} icon="Addons" />}
85
79
  />
86
80
  ) : null}
87
81
  {showPromotions ? (
88
82
  <Tab
89
83
  sx={{ textTransform: 'none' }}
90
84
  value={2}
91
- label={<TabTitle isSelected={value === 2} label={textOverrides.promotionsTabTitle} icon='Promotions' />}
85
+ label={<TabTitle isSelected={value === 2} label={textOverrides.promotionsTabTitle} icon="Promotions" />}
92
86
  />
93
87
  ) : null}
94
88
  </StyledTabs>
@@ -0,0 +1,17 @@
1
+ import sortBy from 'lodash/sortBy';
2
+ import { useMemo } from 'react';
3
+
4
+ import { BillingModel, Price } from '@stigg/js-client-sdk';
5
+
6
+ const CHARGES_BILLING_MODEL_ORDER = [BillingModel.FlatFee, BillingModel.PerUnit, BillingModel.UsageBased];
7
+
8
+ export const sortCharges = (charges: Price[]) => {
9
+ return sortBy(charges, [
10
+ charge => CHARGES_BILLING_MODEL_ORDER.indexOf(charge.pricingModel),
11
+ charge => charge.feature?.displayName,
12
+ ]);
13
+ };
14
+
15
+ export const useChargesSort = (charges: Price[]) => {
16
+ return useMemo(() => sortCharges(charges), [charges]);
17
+ };
@@ -11,7 +11,7 @@ import { useStiggContext } from '../..';
11
11
  import { hasPricePointsForPlans } from './utils/hasPricePoints';
12
12
  import { getPlansToDisplay } from './utils/getPlansToDisplay';
13
13
  import { getPlanPrice } from '../utils/getPlanPrice';
14
- import { getSelectedTier } from './planPriceTier';
14
+ import { getSelectedTier } from '../utils/priceTierUtils';
15
15
 
16
16
  const PaywallPlansContainer = styled.div`
17
17
  color: ${({ theme }) => theme.stigg.palette.text.primary};
@@ -11,7 +11,7 @@ import classNames from 'classnames';
11
11
  import { Grid } from '@mui/material';
12
12
  import MiniSchedule from '../../assets/mini-schedule.svg';
13
13
  import { PlanPrice } from './PlanPrice';
14
- import { getSelectedTier } from './planPriceTier';
14
+ import { getSelectedTier } from '../utils/priceTierUtils';
15
15
 
16
16
  const PlanOfferingContainer = styled.div<{ $isHighlighted: boolean; $isCurrentPlan: boolean }>`
17
17
  position: relative;
@@ -9,7 +9,7 @@ import ClipLoader from 'react-spinners/ClipLoader';
9
9
  import { Typography } from '../common/Typography';
10
10
  import { getSubscriptionScheduleUpdateTexts } from '../utils/getSubscriptionScheduleUpdateTexts';
11
11
  import { isFunction } from 'lodash';
12
- import { compareSelectedTierToCurrentTier, PriceTierComparison } from './planPriceTier';
12
+ import { compareSelectedTierToCurrentTier, PriceTierComparison } from '../utils/priceTierUtils';
13
13
 
14
14
  const LoadingIndicator = styled(ClipLoader)`
15
15
  margin-left: 10px;
@@ -5,7 +5,7 @@ import { Typography } from '../common/Typography';
5
5
  import React, { useEffect, useState } from 'react';
6
6
  import styled from '@emotion/styled/macro';
7
7
  import { BillingPeriod, PriceTierFragment } from '@stigg/js-client-sdk';
8
- import { TiersLayout } from './TiersLayout';
8
+ import { TiersSelectContainer } from '../common/TiersSelectContainer';
9
9
 
10
10
  const EMPTY_CHAR = '‎';
11
11
 
@@ -28,21 +28,14 @@ type PriceBillingPeriodProps = {
28
28
  billingPeriod: BillingPeriod;
29
29
  hasMonthlyPrice: boolean;
30
30
  hasAnnuallyPrice: boolean;
31
- paywallLocale: PaywallLocalization;
32
31
  };
33
32
 
34
- function PriceBillingPeriod({
35
- plan,
36
- billingPeriod,
37
- hasMonthlyPrice,
38
- hasAnnuallyPrice,
39
- paywallLocale,
40
- }: PriceBillingPeriodProps) {
33
+ function PriceBillingPeriod({ plan, billingPeriod, hasMonthlyPrice, hasAnnuallyPrice }: PriceBillingPeriodProps) {
41
34
  const hasPrice = plan.pricePoints.find(pricePoint => pricePoint.billingPeriod === billingPeriod);
42
35
 
43
36
  let content = EMPTY_CHAR;
44
37
  if (hasPrice && hasMonthlyPrice && hasAnnuallyPrice) {
45
- content = paywallLocale.price.billingPeriod?.(billingPeriod) || `, billed ${billingPeriod.toLowerCase()}`;
38
+ content = `, billed ${billingPeriod.toLowerCase()}`;
46
39
  }
47
40
 
48
41
  return (
@@ -140,14 +133,13 @@ export const PlanPrice = ({
140
133
  billingPeriod={billingPeriod}
141
134
  hasAnnuallyPrice={hasAnnuallyPrice}
142
135
  hasMonthlyPrice={hasMonthlyPrice}
143
- paywallLocale={paywallLocale}
144
136
  />
145
137
  </Typography>
146
138
  )}
147
139
 
148
140
  {withTiersRow && (
149
- <TiersLayout
150
- plan={plan}
141
+ <TiersSelectContainer
142
+ componentId={`${plan.id}_${featureId}_tier`}
151
143
  tiers={tiers}
152
144
  tierUnits={tierUnits}
153
145
  selectedTier={selectedTier}
@@ -26,8 +26,6 @@ export type PaywallLocalization = {
26
26
  };
27
27
  price: {
28
28
  startingAtCaption: string;
29
- billingPeriod?: (billingPeriod: BillingPeriod) => string;
30
- pricePeriod: (billingPeriod: BillingPeriod) => string;
31
29
  custom: string;
32
30
  priceNotSet: string;
33
31
  free: PlanPriceText | ((currency?: PaywallCurrency) => PlanPriceText);
@@ -58,7 +56,6 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
58
56
  },
59
57
  price: {
60
58
  startingAtCaption: 'Starts at',
61
- pricePeriod: (billingPeriod: BillingPeriod) => (billingPeriod === BillingPeriod.Monthly ? '/ month' : '/ year'),
62
59
  free: currency => ({
63
60
  price: `${currency?.symbol}0`,
64
61
  }),
@@ -3,16 +3,21 @@ export function calculateUnitQuantityText(
3
3
  maxUnitQuantity?: number | null,
4
4
  unitsPlural?: string | null,
5
5
  ) {
6
+ const unitsText = unitsPlural ? ` ${unitsPlural}` : '';
7
+
6
8
  // copy for only maxunit
7
9
  if ((!minUnitQuantity || minUnitQuantity === 1) && maxUnitQuantity) {
8
- return `Up to ${maxUnitQuantity} ${unitsPlural}`;
10
+ return `Up to ${maxUnitQuantity}${unitsText}`;
9
11
  }
12
+
10
13
  // both limits
11
14
  if (minUnitQuantity && minUnitQuantity > 1 && maxUnitQuantity) {
12
- return `${minUnitQuantity}-${maxUnitQuantity} ${unitsPlural}`;
15
+ return `${minUnitQuantity}-${maxUnitQuantity}${unitsText}`;
13
16
  }
17
+
14
18
  if (minUnitQuantity && minUnitQuantity > 1) {
15
- return `Minimum ${minUnitQuantity} ${unitsPlural}`;
19
+ return `Minimum ${minUnitQuantity}${unitsText}`;
16
20
  }
21
+
17
22
  return '';
18
- }
23
+ }
@@ -2,7 +2,7 @@ import { BillingPeriod, PaywallCalculatedPricePoint, Price } from '@stigg/js-cli
2
2
  import isNil from 'lodash/isNil';
3
3
  import { PaywallPlan } from '../paywall';
4
4
 
5
- function calculateDiscountRate(monthlyPrice?: number | null, annuallyPrice?: number | null) {
5
+ export function calculateDiscountRate(monthlyPrice?: number | null, annuallyPrice?: number | null) {
6
6
  if (!isNil(monthlyPrice) && !isNil(annuallyPrice)) {
7
7
  const annuallyPerMonthPrice = annuallyPrice / 12;
8
8
  return Math.round(((monthlyPrice - annuallyPerMonthPrice) / monthlyPrice) * 100);
@@ -8,7 +8,7 @@ export const currencyPriceFormatter = ({
8
8
  maximumFractionDigits = 5,
9
9
  }: {
10
10
  amount: number;
11
- currency?: Currency;
11
+ currency?: Currency | string;
12
12
  locale?: string;
13
13
  maximumFractionDigits?: number;
14
14
  }) => {