@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.
- package/README.md +1 -1
- package/dist/components/checkout/Checkout.d.ts +5 -0
- package/dist/components/checkout/CheckoutContainer.d.ts +22 -0
- package/dist/components/checkout/CheckoutContainer.style.d.ts +29 -0
- package/dist/components/checkout/CheckoutProvider.d.ts +33 -0
- package/dist/components/checkout/CheckoutSummary.d.ts +9 -0
- package/dist/components/checkout/components/Button.d.ts +6 -0
- package/dist/components/checkout/components/InputField.d.ts +8 -0
- package/dist/components/checkout/components/index.d.ts +2 -0
- package/dist/components/checkout/formatting.d.ts +2 -0
- package/dist/components/checkout/hooks/index.d.ts +8 -0
- package/dist/components/checkout/hooks/useAddonsStepModel.d.ts +21 -0
- package/dist/components/checkout/hooks/useCheckoutModel.d.ts +9 -0
- package/dist/components/checkout/hooks/useCouponModel.d.ts +7 -0
- package/dist/components/checkout/hooks/useLoadCheckout.d.ts +13 -0
- package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +16 -0
- package/dist/components/checkout/hooks/usePlanStepModel.d.ts +23 -0
- package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +13 -0
- package/dist/components/checkout/hooks/useProgressBarModel.d.ts +26 -0
- package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +5 -0
- package/dist/components/checkout/hooks/useSubscriptionState.d.ts +2 -0
- package/dist/components/checkout/index.d.ts +3 -0
- package/dist/components/checkout/planHeader/PlanHeader.d.ts +7 -0
- package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +25 -0
- package/dist/components/checkout/planHeader/index.d.ts +1 -0
- package/dist/components/checkout/progressBar/CheckoutProgressBar.d.ts +2 -0
- package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +45 -0
- package/dist/components/checkout/promotionCode/AddPromotionCode.d.ts +5 -0
- package/dist/components/checkout/promotionCode/AddPromotionCodeButton.d.ts +7 -0
- package/dist/components/checkout/promotionCode/AppliedPromotionCode.d.ts +6 -0
- package/dist/components/checkout/promotionCode/PromotionCodeSection.d.ts +5 -0
- package/dist/components/checkout/promotionCode/index.d.ts +1 -0
- package/dist/components/checkout/steps/addons/CheckoutAddonsStep.d.ts +2 -0
- package/dist/components/checkout/steps/addons/CheckoutAddonsStep.style.d.ts +93 -0
- package/dist/components/checkout/steps/addons/addon.utils.d.ts +15 -0
- package/dist/components/checkout/steps/addons/index.d.ts +1 -0
- package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +19 -0
- package/dist/components/checkout/steps/payment/PaymentMethods.style.d.ts +113 -0
- package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -0
- package/dist/components/checkout/steps/payment/index.d.ts +1 -0
- package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -0
- package/dist/components/checkout/steps/payment/stripe/index.d.ts +3 -0
- package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +33 -0
- package/dist/components/checkout/steps/payment/stripe/useStripeIntegration.d.ts +5 -0
- package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +10 -0
- package/dist/components/checkout/steps/plan/BillingPeriodPicker.d.ts +9 -0
- package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +52 -0
- package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +16 -0
- package/dist/components/checkout/steps/plan/CheckoutPlanStep.d.ts +4 -0
- package/dist/components/checkout/steps/plan/CheckoutPlanStep.style.d.ts +12 -0
- package/dist/components/checkout/steps/plan/index.d.ts +1 -0
- package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +2 -0
- package/dist/components/checkout/textOverrides.d.ts +28 -0
- package/dist/components/checkout/theme.d.ts +8 -0
- package/dist/components/checkout/types.d.ts +7 -0
- package/dist/components/common/Icon.d.ts +3 -2
- package/dist/components/common/PoweredByStigg.d.ts +1 -1
- package/dist/components/{paywall/TiersLayout.d.ts → common/TiersSelectContainer.d.ts} +2 -3
- package/dist/components/common/customIcons.d.ts +17 -5
- package/dist/components/common/mapExternalTheme.d.ts +2 -0
- package/dist/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.d.ts +1 -1
- package/dist/components/hooks/useChargeSort.d.ts +3 -0
- package/dist/components/utils/calculateDiscountRate.d.ts +1 -0
- package/dist/components/utils/currencyUtils.d.ts +1 -1
- package/dist/components/{paywall/planPriceTier.d.ts → utils/priceTierUtils.d.ts} +3 -1
- package/dist/components/utils/priceUtils.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/react-sdk.cjs.development.js +3472 -219
- package/dist/react-sdk.cjs.development.js.map +1 -1
- package/dist/react-sdk.cjs.production.min.js +1 -1
- package/dist/react-sdk.cjs.production.min.js.map +1 -1
- package/dist/react-sdk.esm.js +3615 -225
- package/dist/react-sdk.esm.js.map +1 -1
- package/dist/stories/Checkout.stories.d.ts +3 -0
- package/dist/theme/getResolvedTheme.d.ts +1 -0
- package/dist/theme/types.d.ts +1 -0
- package/package.json +7 -4
- package/src/assets/arrow-forward.svg +3 -0
- package/src/assets/arrow-right.svg +6 -0
- package/src/assets/close.svg +3 -0
- package/src/assets/nyancat.svg +634 -0
- package/src/assets/outlined-checked-circle.svg +6 -0
- package/src/assets/outlined-circle.svg +3 -0
- package/src/assets/payment-method.svg +11 -0
- package/src/assets/plus-icon.svg +6 -0
- package/src/assets/trash.svg +8 -0
- package/src/components/StiggProvider.tsx +5 -5
- package/src/components/checkout/Checkout.tsx +30 -0
- package/src/components/checkout/CheckoutContainer.style.ts +34 -0
- package/src/components/checkout/CheckoutContainer.tsx +92 -0
- package/src/components/checkout/CheckoutProvider.tsx +135 -0
- package/src/components/checkout/CheckoutSummary.tsx +361 -0
- package/src/components/checkout/components/Button.tsx +30 -0
- package/src/components/checkout/components/InputField.tsx +23 -0
- package/src/components/checkout/components/index.ts +2 -0
- package/src/components/checkout/formatting.ts +12 -0
- package/src/components/checkout/hooks/index.ts +8 -0
- package/src/components/checkout/hooks/useAddonsStepModel.ts +96 -0
- package/src/components/checkout/hooks/useCheckoutModel.ts +31 -0
- package/src/components/checkout/hooks/useCouponModel.ts +28 -0
- package/src/components/checkout/hooks/useLoadCheckout.ts +40 -0
- package/src/components/checkout/hooks/usePaymentStepModel.ts +49 -0
- package/src/components/checkout/hooks/usePlanStepModel.ts +170 -0
- package/src/components/checkout/hooks/usePreviewSubscription.ts +82 -0
- package/src/components/checkout/hooks/useProgressBarModel.ts +89 -0
- package/src/components/checkout/hooks/useSubscriptionModel.ts +16 -0
- package/src/components/checkout/hooks/useSubscriptionState.ts +26 -0
- package/src/components/checkout/index.ts +3 -0
- package/src/components/checkout/planHeader/PlanHeader.style.tsx +23 -0
- package/src/components/checkout/planHeader/PlanHeader.tsx +61 -0
- package/src/components/checkout/planHeader/index.ts +1 -0
- package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +29 -0
- package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +48 -0
- package/src/components/checkout/promotionCode/AddPromotionCode.tsx +85 -0
- package/src/components/checkout/promotionCode/AddPromotionCodeButton.tsx +39 -0
- package/src/components/checkout/promotionCode/AppliedPromotionCode.tsx +37 -0
- package/src/components/checkout/promotionCode/PromotionCodeSection.tsx +27 -0
- package/src/components/checkout/promotionCode/index.ts +1 -0
- package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +24 -0
- package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +125 -0
- package/src/components/checkout/steps/addons/addon.utils.ts +68 -0
- package/src/components/checkout/steps/addons/index.ts +1 -0
- package/src/components/checkout/steps/payment/PaymentMethods.style.ts +26 -0
- package/src/components/checkout/steps/payment/PaymentMethods.tsx +83 -0
- package/src/components/checkout/steps/payment/PaymentStep.tsx +41 -0
- package/src/components/checkout/steps/payment/index.ts +1 -0
- package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +43 -0
- package/src/components/checkout/steps/payment/stripe/index.ts +3 -0
- package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +109 -0
- package/src/components/checkout/steps/payment/stripe/useStripeIntegration.ts +27 -0
- package/src/components/checkout/steps/payment/stripe/useSubmit.ts +100 -0
- package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +46 -0
- package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +63 -0
- package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +138 -0
- package/src/components/checkout/steps/plan/CheckoutPlanStep.style.tsx +6 -0
- package/src/components/checkout/steps/plan/CheckoutPlanStep.tsx +22 -0
- package/src/components/checkout/steps/plan/index.ts +1 -0
- package/src/components/checkout/steps/surprise/SurpriseStep.tsx +27 -0
- package/src/components/checkout/textOverrides.ts +58 -0
- package/src/components/checkout/theme.ts +26 -0
- package/src/components/checkout/types.ts +7 -0
- package/src/components/common/Icon.tsx +17 -22
- package/src/components/common/PoweredByStigg.tsx +1 -1
- package/src/components/{paywall/TiersLayout.tsx → common/TiersSelectContainer.tsx} +8 -7
- package/src/components/common/Typography.tsx +11 -1
- package/src/components/common/customIcons.ts +17 -28
- package/src/components/common/mapExternalTheme.ts +6 -0
- package/src/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.tsx +6 -12
- package/src/components/hooks/useChargeSort.ts +17 -0
- package/src/components/paywall/BillingPeriodPicker.tsx +1 -1
- package/src/components/paywall/Paywall.tsx +1 -1
- package/src/components/paywall/PlanOffering.tsx +1 -1
- package/src/components/paywall/PlanOfferingButton.tsx +1 -1
- package/src/components/paywall/PlanPrice.tsx +3 -3
- package/src/components/paywall/utils/calculateUnitQuantityText.ts +9 -4
- package/src/components/utils/calculateDiscountRate.ts +26 -14
- package/src/components/utils/currencyUtils.ts +1 -1
- package/src/components/utils/getPaidPriceText.ts +2 -2
- package/src/components/{paywall/planPriceTier.ts → utils/priceTierUtils.ts} +25 -3
- package/src/components/utils/priceUtils.ts +10 -0
- package/src/index.ts +1 -0
- package/src/stories/Checkout.stories.tsx +59 -0
- package/src/theme/Theme.tsx +9 -8
- package/src/theme/getResolvedTheme.ts +1 -0
- package/src/theme/types.ts +1 -0
|
@@ -1,28 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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}
|
|
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=
|
|
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=
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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 {
|
|
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
|
-
<
|
|
142
|
-
|
|
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}
|
|
10
|
+
return `Up to ${maxUnitQuantity}${unitsText}`;
|
|
9
11
|
}
|
|
12
|
+
|
|
10
13
|
// both limits
|
|
11
14
|
if (minUnitQuantity && minUnitQuantity > 1 && maxUnitQuantity) {
|
|
12
|
-
return `${minUnitQuantity}-${maxUnitQuantity}
|
|
15
|
+
return `${minUnitQuantity}-${maxUnitQuantity}${unitsText}`;
|
|
13
16
|
}
|
|
17
|
+
|
|
14
18
|
if (minUnitQuantity && minUnitQuantity > 1) {
|
|
15
|
-
return `Minimum ${minUnitQuantity}
|
|
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
|
-
|
|
17
|
-
|
|
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) {
|
|
@@ -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 '
|
|
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
|
|
47
|
+
tierUnits = getPriceFeatureUnit(price);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
priceNumber += calculateTierPrice(price, currentTier, selectedBillingPeriod, shouldShowMonthlyPriceAmount);
|
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
import { PaywallPlan } from '
|
|
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
|
-
|
|
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
|
+
};
|
package/src/theme/Theme.tsx
CHANGED
|
@@ -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
|
-
|
|
5
|
+
|
|
6
|
+
import { css, ThemeProvider } from '@emotion/react';
|
|
4
7
|
import styled from '@emotion/styled/macro';
|
|
5
|
-
import { ThemeProvider } from '@
|
|
6
|
-
|
|
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 {
|
|
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(),
|