@stigg/react-sdk 4.2.2 → 4.3.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 (165) 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 +29 -0
  5. package/dist/components/checkout/CheckoutProvider.d.ts +33 -0
  6. package/dist/components/checkout/CheckoutSummary.d.ts +9 -0
  7. package/dist/components/checkout/components/Button.d.ts +6 -0
  8. package/dist/components/checkout/components/InputField.d.ts +8 -0
  9. package/dist/components/checkout/components/index.d.ts +2 -0
  10. package/dist/components/checkout/formatting.d.ts +2 -0
  11. package/dist/components/checkout/hooks/index.d.ts +8 -0
  12. package/dist/components/checkout/hooks/useAddonsStepModel.d.ts +21 -0
  13. package/dist/components/checkout/hooks/useCheckoutModel.d.ts +9 -0
  14. package/dist/components/checkout/hooks/useCouponModel.d.ts +7 -0
  15. package/dist/components/checkout/hooks/useLoadCheckout.d.ts +13 -0
  16. package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +16 -0
  17. package/dist/components/checkout/hooks/usePlanStepModel.d.ts +23 -0
  18. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +13 -0
  19. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +26 -0
  20. package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +5 -0
  21. package/dist/components/checkout/hooks/useSubscriptionState.d.ts +2 -0
  22. package/dist/components/checkout/index.d.ts +3 -0
  23. package/dist/components/checkout/planHeader/PlanHeader.d.ts +7 -0
  24. package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +25 -0
  25. package/dist/components/checkout/planHeader/index.d.ts +1 -0
  26. package/dist/components/checkout/progressBar/CheckoutProgressBar.d.ts +2 -0
  27. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +45 -0
  28. package/dist/components/checkout/promotionCode/AddPromotionCode.d.ts +5 -0
  29. package/dist/components/checkout/promotionCode/AddPromotionCodeButton.d.ts +7 -0
  30. package/dist/components/checkout/promotionCode/AppliedPromotionCode.d.ts +6 -0
  31. package/dist/components/checkout/promotionCode/PromotionCodeSection.d.ts +5 -0
  32. package/dist/components/checkout/promotionCode/index.d.ts +1 -0
  33. package/dist/components/checkout/steps/addons/CheckoutAddonsStep.d.ts +2 -0
  34. package/dist/components/checkout/steps/addons/CheckoutAddonsStep.style.d.ts +93 -0
  35. package/dist/components/checkout/steps/addons/addon.utils.d.ts +15 -0
  36. package/dist/components/checkout/steps/addons/index.d.ts +1 -0
  37. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +19 -0
  38. package/dist/components/checkout/steps/payment/PaymentMethods.style.d.ts +113 -0
  39. package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -0
  40. package/dist/components/checkout/steps/payment/index.d.ts +1 -0
  41. package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -0
  42. package/dist/components/checkout/steps/payment/stripe/index.d.ts +3 -0
  43. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +33 -0
  44. package/dist/components/checkout/steps/payment/stripe/useStripeIntegration.d.ts +5 -0
  45. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +10 -0
  46. package/dist/components/checkout/steps/plan/BillingPeriodPicker.d.ts +9 -0
  47. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +52 -0
  48. package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +16 -0
  49. package/dist/components/checkout/steps/plan/CheckoutPlanStep.d.ts +4 -0
  50. package/dist/components/checkout/steps/plan/CheckoutPlanStep.style.d.ts +12 -0
  51. package/dist/components/checkout/steps/plan/index.d.ts +1 -0
  52. package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +2 -0
  53. package/dist/components/checkout/textOverrides.d.ts +28 -0
  54. package/dist/components/checkout/theme.d.ts +8 -0
  55. package/dist/components/checkout/types.d.ts +7 -0
  56. package/dist/components/common/Icon.d.ts +3 -2
  57. package/dist/components/common/PoweredByStigg.d.ts +1 -1
  58. package/dist/components/{paywall/TiersLayout.d.ts → common/TiersSelectContainer.d.ts} +2 -3
  59. package/dist/components/common/customIcons.d.ts +17 -5
  60. package/dist/components/common/mapExternalTheme.d.ts +2 -0
  61. package/dist/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.d.ts +1 -1
  62. package/dist/components/hooks/useChargeSort.d.ts +3 -0
  63. package/dist/components/utils/calculateDiscountRate.d.ts +1 -0
  64. package/dist/components/utils/currencyUtils.d.ts +1 -1
  65. package/dist/components/{paywall/planPriceTier.d.ts → utils/priceTierUtils.d.ts} +3 -1
  66. package/dist/components/utils/priceUtils.d.ts +2 -0
  67. package/dist/index.d.ts +1 -0
  68. package/dist/react-sdk.cjs.development.js +3472 -219
  69. package/dist/react-sdk.cjs.development.js.map +1 -1
  70. package/dist/react-sdk.cjs.production.min.js +1 -1
  71. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  72. package/dist/react-sdk.esm.js +3615 -225
  73. package/dist/react-sdk.esm.js.map +1 -1
  74. package/dist/stories/Checkout.stories.d.ts +3 -0
  75. package/dist/theme/getResolvedTheme.d.ts +1 -0
  76. package/dist/theme/types.d.ts +1 -0
  77. package/package.json +7 -4
  78. package/src/assets/arrow-forward.svg +3 -0
  79. package/src/assets/arrow-right.svg +6 -0
  80. package/src/assets/close.svg +3 -0
  81. package/src/assets/nyancat.svg +634 -0
  82. package/src/assets/outlined-checked-circle.svg +6 -0
  83. package/src/assets/outlined-circle.svg +3 -0
  84. package/src/assets/payment-method.svg +11 -0
  85. package/src/assets/plus-icon.svg +6 -0
  86. package/src/assets/trash.svg +8 -0
  87. package/src/components/StiggProvider.tsx +5 -5
  88. package/src/components/checkout/Checkout.tsx +30 -0
  89. package/src/components/checkout/CheckoutContainer.style.ts +34 -0
  90. package/src/components/checkout/CheckoutContainer.tsx +92 -0
  91. package/src/components/checkout/CheckoutProvider.tsx +135 -0
  92. package/src/components/checkout/CheckoutSummary.tsx +361 -0
  93. package/src/components/checkout/components/Button.tsx +30 -0
  94. package/src/components/checkout/components/InputField.tsx +23 -0
  95. package/src/components/checkout/components/index.ts +2 -0
  96. package/src/components/checkout/formatting.ts +12 -0
  97. package/src/components/checkout/hooks/index.ts +8 -0
  98. package/src/components/checkout/hooks/useAddonsStepModel.ts +96 -0
  99. package/src/components/checkout/hooks/useCheckoutModel.ts +31 -0
  100. package/src/components/checkout/hooks/useCouponModel.ts +28 -0
  101. package/src/components/checkout/hooks/useLoadCheckout.ts +40 -0
  102. package/src/components/checkout/hooks/usePaymentStepModel.ts +49 -0
  103. package/src/components/checkout/hooks/usePlanStepModel.ts +170 -0
  104. package/src/components/checkout/hooks/usePreviewSubscription.ts +82 -0
  105. package/src/components/checkout/hooks/useProgressBarModel.ts +89 -0
  106. package/src/components/checkout/hooks/useSubscriptionModel.ts +16 -0
  107. package/src/components/checkout/hooks/useSubscriptionState.ts +26 -0
  108. package/src/components/checkout/index.ts +3 -0
  109. package/src/components/checkout/planHeader/PlanHeader.style.tsx +23 -0
  110. package/src/components/checkout/planHeader/PlanHeader.tsx +61 -0
  111. package/src/components/checkout/planHeader/index.ts +1 -0
  112. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +29 -0
  113. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +48 -0
  114. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +85 -0
  115. package/src/components/checkout/promotionCode/AddPromotionCodeButton.tsx +39 -0
  116. package/src/components/checkout/promotionCode/AppliedPromotionCode.tsx +37 -0
  117. package/src/components/checkout/promotionCode/PromotionCodeSection.tsx +27 -0
  118. package/src/components/checkout/promotionCode/index.ts +1 -0
  119. package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +24 -0
  120. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +125 -0
  121. package/src/components/checkout/steps/addons/addon.utils.ts +68 -0
  122. package/src/components/checkout/steps/addons/index.ts +1 -0
  123. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +26 -0
  124. package/src/components/checkout/steps/payment/PaymentMethods.tsx +83 -0
  125. package/src/components/checkout/steps/payment/PaymentStep.tsx +41 -0
  126. package/src/components/checkout/steps/payment/index.ts +1 -0
  127. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +43 -0
  128. package/src/components/checkout/steps/payment/stripe/index.ts +3 -0
  129. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +109 -0
  130. package/src/components/checkout/steps/payment/stripe/useStripeIntegration.ts +27 -0
  131. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +100 -0
  132. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +46 -0
  133. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +63 -0
  134. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +138 -0
  135. package/src/components/checkout/steps/plan/CheckoutPlanStep.style.tsx +6 -0
  136. package/src/components/checkout/steps/plan/CheckoutPlanStep.tsx +22 -0
  137. package/src/components/checkout/steps/plan/index.ts +1 -0
  138. package/src/components/checkout/steps/surprise/SurpriseStep.tsx +27 -0
  139. package/src/components/checkout/textOverrides.ts +58 -0
  140. package/src/components/checkout/theme.ts +26 -0
  141. package/src/components/checkout/types.ts +7 -0
  142. package/src/components/common/Icon.tsx +17 -22
  143. package/src/components/common/PoweredByStigg.tsx +1 -1
  144. package/src/components/{paywall/TiersLayout.tsx → common/TiersSelectContainer.tsx} +8 -7
  145. package/src/components/common/Typography.tsx +11 -1
  146. package/src/components/common/customIcons.ts +17 -28
  147. package/src/components/common/mapExternalTheme.ts +6 -0
  148. package/src/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.tsx +6 -12
  149. package/src/components/hooks/useChargeSort.ts +17 -0
  150. package/src/components/paywall/BillingPeriodPicker.tsx +1 -1
  151. package/src/components/paywall/Paywall.tsx +1 -1
  152. package/src/components/paywall/PlanOffering.tsx +1 -1
  153. package/src/components/paywall/PlanOfferingButton.tsx +1 -1
  154. package/src/components/paywall/PlanPrice.tsx +3 -3
  155. package/src/components/paywall/utils/calculateUnitQuantityText.ts +9 -4
  156. package/src/components/utils/calculateDiscountRate.ts +26 -14
  157. package/src/components/utils/currencyUtils.ts +1 -1
  158. package/src/components/utils/getPaidPriceText.ts +2 -2
  159. package/src/components/{paywall/planPriceTier.ts → utils/priceTierUtils.ts} +25 -3
  160. package/src/components/utils/priceUtils.ts +10 -0
  161. package/src/index.ts +1 -0
  162. package/src/stories/Checkout.stories.tsx +59 -0
  163. package/src/theme/Theme.tsx +9 -8
  164. package/src/theme/getResolvedTheme.ts +1 -0
  165. package/src/theme/types.ts +1 -0
@@ -1,28 +1,17 @@
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 ArrowForward } from '../../assets/arrow-forward.svg';
17
+ export { default as Close } from '../../assets/close.svg';
@@ -6,6 +6,7 @@ import {
6
6
  } from '@stigg/js-client-sdk';
7
7
  import { CustomizedTheme } from '../../theme/Theme';
8
8
  import { HorizontalAlignment, FontWeight } from '../../theme/types';
9
+ import { CheckoutConfiguration } from '../checkout/types';
9
10
 
10
11
  function addCssUnits(value?: number | null, unit: string = 'px') {
11
12
  if (!value) {
@@ -109,3 +110,8 @@ export function mapPaywallConfiguration(paywallConfiguration: PaywallConfigurati
109
110
  },
110
111
  };
111
112
  }
113
+
114
+ export function mapCheckoutConfiguration(_configuration: CheckoutConfiguration): CustomizedTheme {
115
+ // TODO: configuration should be of type CustomerPortalConfiguration
116
+ return {};
117
+ }
@@ -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
+ };
@@ -87,7 +87,7 @@ export function BillingPeriodPicker({
87
87
  >
88
88
  Annual
89
89
  </PeriodText>
90
- <DiscountRate discount={discountRate} disabled={isMonthlyBillingPeriod} />
90
+ {discountRate !== 0 && <DiscountRate discount={discountRate} disabled={isMonthlyBillingPeriod} />}
91
91
  </PickerContainer>
92
92
  );
93
93
  }
@@ -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
 
@@ -138,8 +138,8 @@ export const PlanPrice = ({
138
138
  )}
139
139
 
140
140
  {withTiersRow && (
141
- <TiersLayout
142
- plan={plan}
141
+ <TiersSelectContainer
142
+ componentId={`${plan.id}_${featureId}_tier`}
143
143
  tiers={tiers}
144
144
  tierUnits={tierUnits}
145
145
  selectedTier={selectedTier}
@@ -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
+ }
@@ -1,8 +1,8 @@
1
- import { BillingPeriod } from '@stigg/js-client-sdk';
1
+ import { BillingPeriod, PaywallCalculatedPricePoint, Price } from '@stigg/js-client-sdk';
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);
@@ -11,20 +11,32 @@ function calculateDiscountRate(monthlyPrice?: number | null, annuallyPrice?: num
11
11
  return null;
12
12
  }
13
13
 
14
+ function getPlanBillingPeriodAmount(plan: PaywallPlan, billingPeriod: BillingPeriod) {
15
+ let pricePoint: PaywallCalculatedPricePoint | Price | undefined;
16
+
17
+ pricePoint = plan.paywallCalculatedPricePoints?.find(price => price.billingPeriod === billingPeriod);
18
+
19
+ if (!pricePoint) {
20
+ pricePoint = plan.pricePoints.find(price => price.billingPeriod === billingPeriod);
21
+ }
22
+
23
+ if (!pricePoint?.amount) {
24
+ const tieredPrice = plan.pricePoints.find(price => {
25
+ return price.isTieredPrice && price.billingPeriod === billingPeriod;
26
+ });
27
+
28
+ if (tieredPrice) {
29
+ return tieredPrice.tiers![0].unitPrice.amount;
30
+ }
31
+ }
32
+
33
+ return pricePoint?.amount;
34
+ }
35
+
14
36
  export function calculatePaywallDiscountRate(plans: PaywallPlan[]) {
15
37
  return plans.reduce((maxDiscount, plan) => {
16
- let monthlyAmount;
17
- let annuallyAmount;
18
-
19
- if (plan.paywallCalculatedPricePoints?.length) {
20
- monthlyAmount = plan.paywallCalculatedPricePoints?.find(price => price.billingPeriod === BillingPeriod.Monthly)
21
- ?.amount;
22
- annuallyAmount = plan.paywallCalculatedPricePoints?.find(price => price.billingPeriod === BillingPeriod.Annually)
23
- ?.amount;
24
- } else {
25
- monthlyAmount = plan.pricePoints.find(price => price.billingPeriod === BillingPeriod.Monthly)?.amount;
26
- annuallyAmount = plan.pricePoints.find(price => price.billingPeriod === BillingPeriod.Annually)?.amount;
27
- }
38
+ const monthlyAmount = getPlanBillingPeriodAmount(plan, BillingPeriod.Monthly);
39
+ const annuallyAmount = getPlanBillingPeriodAmount(plan, BillingPeriod.Annually);
28
40
 
29
41
  const discountRate = calculateDiscountRate(monthlyAmount, annuallyAmount);
30
42
  if (discountRate) {
@@ -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
  }) => {
@@ -7,7 +7,7 @@ import {
7
7
  } from '@stigg/js-client-sdk';
8
8
  import { currencyPriceFormatter } from './currencyUtils';
9
9
  import { PlanPriceText } from './getPlanPrice';
10
- import { calculateTierPrice } from '../paywall/planPriceTier';
10
+ import { calculateTierPrice, getPriceFeatureUnit } from './priceTierUtils';
11
11
 
12
12
  type GetPaidPriceTextParams = {
13
13
  planPrices: Price[];
@@ -44,7 +44,7 @@ export function getPaidPriceText({
44
44
  currentTier = selectedTierByFeature[price.feature!.featureId] || currentTier;
45
45
 
46
46
  tiers = price.tiers;
47
- tierUnits = price.feature!.unitsPlural || '';
47
+ tierUnits = getPriceFeatureUnit(price);
48
48
  }
49
49
 
50
50
  priceNumber += calculateTierPrice(price, currentTier, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
@@ -1,7 +1,30 @@
1
- import { PaywallPlan } from './types';
1
+ import { PaywallPlan } from '../paywall/types';
2
2
 
3
3
  import { BillingModel, TiersMode, BillingPeriod, Price, PriceTierFragment, Subscription } from '@stigg/js-client-sdk';
4
4
 
5
+ export function getPriceFeatureUnit(price: Price) {
6
+ if (!price.feature) {
7
+ return '';
8
+ }
9
+
10
+ return (price.feature!.unitQuantity != 1 ? price.feature!.unitsPlural : price.feature!.units) || '';
11
+ }
12
+
13
+ export function getTierByQuantity(tiers: PriceTierFragment[], quantity: number) {
14
+ if (!tiers) return;
15
+
16
+ const ascendingTiers = [...tiers];
17
+ ascendingTiers.sort((a, b) => a.upTo - b.upTo);
18
+
19
+ for (const tier of ascendingTiers) {
20
+ if (quantity <= tier.upTo) {
21
+ return tier;
22
+ }
23
+ }
24
+
25
+ return ascendingTiers[ascendingTiers.length - 1];
26
+ }
27
+
5
28
  export function calculateTierPrice(
6
29
  price: Price,
7
30
  currentTier: PriceTierFragment,
@@ -46,8 +69,7 @@ export function getSelectedTier(
46
69
  );
47
70
 
48
71
  if (tieredPrice) {
49
- const customerTier = price.tiers!.find(tier => tier.upTo === tieredPrice.feature!.unitQuantity);
50
- currentTier = customerTier || price.tiers![0];
72
+ currentTier = getTierByQuantity(price.tiers!, tieredPrice.feature!.unitQuantity || 1)!;
51
73
  }
52
74
  }
53
75
 
@@ -0,0 +1,10 @@
1
+ import { Price } from '@stigg/js-client-sdk';
2
+
3
+ export const getValidPriceQuantity = (price: Price, quantity: number) => {
4
+ if (price.minUnitQuantity && quantity < price.minUnitQuantity) {
5
+ return price.minUnitQuantity;
6
+ } else if (price.maxUnitQuantity && quantity > price.maxUnitQuantity) {
7
+ return price.maxUnitQuantity;
8
+ }
9
+ return quantity;
10
+ };
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export {
29
29
  StiggContextValue,
30
30
  StiggContext,
31
31
  } from './components/StiggProvider';
32
+ export { Checkout, CheckoutProps, CheckoutConfiguration } from './components/checkout';
32
33
  export { useWaitForCheckoutCompleted, ProvisionStatus } from './components/hooks';
33
34
  export { HorizontalAlignment, TextAlignment } from './theme/types';
34
35
  export { CustomizedTheme as Theme } from './theme/Theme';
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled/macro';
3
+ import { ComponentMeta, ComponentStory } from '@storybook/react';
4
+ import { Checkout } from '../components/checkout';
5
+ import { StiggProvider } from '../components/StiggProvider';
6
+ import { defaultArgsWithCustomer } from './baseArgs';
7
+
8
+ export default {
9
+ title: 'Stigg React SDK/Checkout',
10
+ component: Checkout,
11
+ decorators: [
12
+ (Story, { args }) => (
13
+ <StiggProvider
14
+ apiKey={args.apiKey}
15
+ customerId={args.customerId}
16
+ theme={args.theme}
17
+ locale={args.locale}
18
+ baseUri={args.baseUri}
19
+ enableEdge={args.disableEdge}
20
+ >
21
+ <Story />
22
+ </StiggProvider>
23
+ ),
24
+ ],
25
+ } as ComponentMeta<typeof Checkout>;
26
+
27
+ const Wrapper = styled.div`
28
+ width: 1000px;
29
+ `;
30
+
31
+ const Template: ComponentStory<any> = args => (
32
+ <Wrapper>
33
+ <Checkout
34
+ planId={args.planId}
35
+ preferredBillingPeriod={args.preferredBillingPeriod}
36
+ billingCountryCode={args.billingCountryCode}
37
+ resourceId={args.resourceId}
38
+ onCheckoutCompleted={results => {
39
+ console.log('checkout finished!', results);
40
+ return Promise.resolve();
41
+ }}
42
+ onCheckout={async ({ checkoutParams, checkoutAction }) => {
43
+ console.log('checkout started!', checkoutParams);
44
+ const { success, errorMessage } = await checkoutAction();
45
+ return { success, errorMessage };
46
+ }}
47
+ billableFeatures={[{ featureId: 'feature-seat', quantity: 30 }]}
48
+ onChangePlan={({ currentPlan }) => {
49
+ console.log('plan changed clicked!', { currentPlan });
50
+ }}
51
+ />
52
+ </Wrapper>
53
+ );
54
+
55
+ export const DefaultCheckout = Template.bind({});
56
+ DefaultCheckout.args = {
57
+ ...defaultArgsWithCustomer,
58
+ planId: 'plan-revvenu-essentials',
59
+ };
@@ -1,16 +1,17 @@
1
+ import { merge } from 'lodash';
1
2
  import React, { PropsWithChildren } from 'react';
3
+ import { ThemeProvider as StyledThemeProvider } from 'styled-components';
2
4
  import { TypographyProps } from 'styled-typography';
3
- import { css } from '@emotion/react';
5
+
6
+ import { css, ThemeProvider } from '@emotion/react';
4
7
  import styled from '@emotion/styled/macro';
5
- import { ThemeProvider } from '@emotion/react';
6
- import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles';
7
- import { ThemeProvider as StyledThemeProvider } from 'styled-components';
8
- import { Fonts } from './Fonts';
9
- import { DeepPartial } from '../types';
10
- import { StiggTheme } from './types';
8
+ import { createTheme, ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
9
+
11
10
  import { useStiggContext } from '../components/StiggProvider';
12
- import { merge } from 'lodash';
11
+ import { DeepPartial } from '../types';
12
+ import { Fonts } from './Fonts';
13
13
  import { getResolvedTheme } from './getResolvedTheme';
14
+ import { StiggTheme } from './types';
14
15
 
15
16
  export type CustomizedTheme = DeepPartial<StiggTheme>;
16
17
 
@@ -18,6 +18,7 @@ export const getResolvedTheme = (customizedTheme?: CustomizedTheme): StiggTheme
18
18
  const baseTheme: StiggTheme = {
19
19
  palette: {
20
20
  primary: primaryColor.hex(),
21
+ primaryDark: primaryColor.darken(0.3).hex(),
21
22
  backgroundPaper: '#FFFFFF',
22
23
  backgroundHighlight: '#F5F6F9',
23
24
  backgroundSection: primaryColor.alpha(0.1).toString(),
@@ -8,6 +8,7 @@ export type FontVariant = {
8
8
  export type StiggTheme = {
9
9
  palette: {
10
10
  primary: string;
11
+ primaryDark: string;
11
12
  backgroundPaper: string;
12
13
  backgroundHighlight: string;
13
14
  backgroundSection: string;