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