@stigg/react-sdk 5.36.0 → 6.0.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/dist/components/common/customIcons.d.ts +3 -0
- package/dist/components/paywall/Paywall.d.ts +2 -1
- package/dist/components/paywall/PaywallContainer.d.ts +2 -1
- package/dist/components/paywall/PlanCompatibleAddons.d.ts +15 -0
- package/dist/components/paywall/PlanOffering.d.ts +2 -1
- package/dist/components/paywall/index.d.ts +1 -0
- package/dist/components/paywall/paywallTextOverrides.d.ts +2 -0
- package/dist/react-sdk.cjs.development.js +1633 -1416
- 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 +4593 -4329
- package/dist/react-sdk.esm.js.map +1 -1
- package/dist/stories/Paywall.stories.d.ts +1 -0
- package/package.json +1 -1
- package/src/assets/add.svg +3 -0
- package/src/assets/check.svg +1 -1
- package/src/assets/entitlement-check.svg +3 -0
- package/src/assets/remove.svg +3 -0
- package/src/components/common/customIcons.ts +3 -0
- package/src/components/paywall/EntitlementRow.tsx +8 -10
- package/src/components/paywall/Paywall.tsx +3 -0
- package/src/components/paywall/PaywallContainer.tsx +3 -0
- package/src/components/paywall/PlanCompatibleAddons.tsx +125 -0
- package/src/components/paywall/PlanEntitlements.tsx +1 -1
- package/src/components/paywall/PlanOffering.tsx +13 -0
- package/src/components/paywall/index.ts +1 -0
- package/src/components/paywall/paywallTextOverrides.ts +2 -0
- package/src/stories/Paywall.stories.tsx +16 -0
|
@@ -6,3 +6,4 @@ export declare const CustomerPaywall: import("@storybook/csf").AnnotatedStoryFn<
|
|
|
6
6
|
export declare const CustomerUpgradePaywall: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, any>;
|
|
7
7
|
export declare const CustomerAsyncCTA: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, any>;
|
|
8
8
|
export declare const CustomerResourcePaywall: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, any>;
|
|
9
|
+
export declare const PaywallWithAddons: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, any>;
|
package/package.json
CHANGED
package/src/assets/check.svg
CHANGED
|
@@ -19,3 +19,6 @@ export { default as Close } from '../../assets/close.svg';
|
|
|
19
19
|
export { default as Check } from '../../assets/check.svg';
|
|
20
20
|
export { default as PayAsYouGoCharge } from '../../assets/pay-as-you-go-charge.svg';
|
|
21
21
|
export { default as Coupon } from '../../assets/coupon.svg';
|
|
22
|
+
export { default as Add } from '../../assets/add.svg';
|
|
23
|
+
export { default as Remove } from '../../assets/remove.svg';
|
|
24
|
+
export { default as EntitlementCheck } from '../../assets/entitlement-check.svg';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from '@emotion/styled/macro';
|
|
3
3
|
import { EntitlementResetPeriod } from '@stigg/js-client-sdk';
|
|
4
|
-
import CheckUrl from '../../assets/check-stigg.svg';
|
|
5
4
|
import { calculateUnitQuantityText } from './utils/calculateUnitQuantityText';
|
|
6
5
|
import { formatNumber } from '../utils/formatNumber';
|
|
7
6
|
import { Typography } from '../common/Typography';
|
|
7
|
+
import { Icon } from '../common/Icon';
|
|
8
8
|
|
|
9
9
|
const EntitlementName = styled(Typography)`
|
|
10
10
|
margin: 0;
|
|
@@ -12,22 +12,20 @@ const EntitlementName = styled(Typography)`
|
|
|
12
12
|
|
|
13
13
|
const EntitlementRowContainer = styled.div`
|
|
14
14
|
display: flex;
|
|
15
|
-
align-items:
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: 16px;
|
|
16
17
|
`;
|
|
17
18
|
|
|
18
19
|
const EntitlementIconContainer = styled.div`
|
|
19
20
|
display: flex;
|
|
20
21
|
align-items: center;
|
|
21
|
-
margin-right: 16px;
|
|
22
|
-
height: ${({ theme }) => theme.stigg.typography.h3.fontSize};
|
|
23
22
|
flex-shrink: 0;
|
|
24
23
|
`;
|
|
25
24
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
25
|
+
const EntitlementIcon = styled(Icon)`
|
|
26
|
+
width: 24px;
|
|
27
|
+
height: 24px;
|
|
28
|
+
color: ${({ theme }) => theme.stigg.palette.primary};
|
|
31
29
|
`;
|
|
32
30
|
|
|
33
31
|
type EntitlementRowProps = {
|
|
@@ -113,7 +111,7 @@ export function EntitlementRow(props: EntitlementRowProps) {
|
|
|
113
111
|
return (
|
|
114
112
|
<EntitlementRowContainer className={`stigg-entitlement-row-container stigg-entitlement-${restProps.feature?.id}`}>
|
|
115
113
|
<EntitlementIconContainer>
|
|
116
|
-
<
|
|
114
|
+
<EntitlementIcon icon="EntitlementCheck" className="stigg-entitlement-row-icon" />
|
|
117
115
|
</EntitlementIconContainer>
|
|
118
116
|
<EntitlementName className="stigg-entitlement-name" variant="h6" color="secondary">
|
|
119
117
|
{displayNameOverride || displayName}
|
|
@@ -61,6 +61,7 @@ type PaywallProps = {
|
|
|
61
61
|
locale: string;
|
|
62
62
|
shouldHidePlan?: ShouldHidePlanFn;
|
|
63
63
|
selectDefaultTierIndex?: SelectDefaultTierIndexFn;
|
|
64
|
+
hideCompatibleAddons?: boolean;
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
export const Paywall = ({
|
|
@@ -78,6 +79,7 @@ export const Paywall = ({
|
|
|
78
79
|
shouldHidePlan,
|
|
79
80
|
selectDefaultTierIndex,
|
|
80
81
|
currentSubscriptionOverride,
|
|
82
|
+
hideCompatibleAddons,
|
|
81
83
|
}: PaywallProps) => {
|
|
82
84
|
const { stigg } = useStiggContext();
|
|
83
85
|
const discountRate = calculatePaywallDiscountRate(plans);
|
|
@@ -176,6 +178,7 @@ export const Paywall = ({
|
|
|
176
178
|
customer={customer}
|
|
177
179
|
isCustomerInCustomPlan={isCustomerInCustomPlan}
|
|
178
180
|
selectDefaultTierIndex={selectDefaultTierIndex}
|
|
181
|
+
hideCompatibleAddons={hideCompatibleAddons}
|
|
179
182
|
/>
|
|
180
183
|
))}
|
|
181
184
|
</PaywallPlansContainer>
|
|
@@ -30,6 +30,7 @@ export type PaywallContainerProps = {
|
|
|
30
30
|
billingCountryCode?: string;
|
|
31
31
|
shouldHidePlan?: ShouldHidePlanFn;
|
|
32
32
|
selectDefaultTierIndex?: SelectDefaultTierIndexFn;
|
|
33
|
+
hideCompatibleAddons?: boolean;
|
|
33
34
|
// This is used to override the current subscription in case a many to one plan mapping is needed
|
|
34
35
|
// Many plans mapped to one (fictive) plan
|
|
35
36
|
currentSubscriptionOverride?: CurrentSubscriptionOverrideFn;
|
|
@@ -48,6 +49,7 @@ export const PaywallContainer = ({
|
|
|
48
49
|
shouldHidePlan,
|
|
49
50
|
selectDefaultTierIndex,
|
|
50
51
|
currentSubscriptionOverride: currentSubscriptionOverrideFn,
|
|
52
|
+
hideCompatibleAddons,
|
|
51
53
|
}: PaywallContainerProps) => {
|
|
52
54
|
const hasCustomerPortalContext = useCheckContextExists(CustomerPortalContext);
|
|
53
55
|
let isCustomerPortalLoading = false;
|
|
@@ -104,6 +106,7 @@ export const PaywallContainer = ({
|
|
|
104
106
|
locale={locale}
|
|
105
107
|
shouldHidePlan={shouldHidePlan}
|
|
106
108
|
selectDefaultTierIndex={selectDefaultTierIndex}
|
|
109
|
+
hideCompatibleAddons={hideCompatibleAddons}
|
|
107
110
|
/>
|
|
108
111
|
);
|
|
109
112
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Addon, WidgetType } from '@stigg/js-client-sdk';
|
|
3
|
+
import MuiButton from '@mui/material/Button';
|
|
4
|
+
import styled from '@emotion/styled/macro';
|
|
5
|
+
import classNames from 'classnames';
|
|
6
|
+
import { Typography } from '../common/Typography';
|
|
7
|
+
import { PaywallLocalization } from './paywallTextOverrides';
|
|
8
|
+
import { Icon } from '../common/Icon';
|
|
9
|
+
|
|
10
|
+
export const StyledButton = styled(MuiButton)`
|
|
11
|
+
padding: 0px;
|
|
12
|
+
text-transform: none;
|
|
13
|
+
margin-left: 0px;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const ButtonText = styled(Typography)`
|
|
17
|
+
font-size: 14px;
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const AddonsBox = styled.div`
|
|
22
|
+
width: 100%;
|
|
23
|
+
gap: 10px;
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const AddonsList = styled.div`
|
|
27
|
+
margin-top: 10px;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
gap: 4px;
|
|
32
|
+
width: 100%;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const AddonRow = styled.div`
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: row;
|
|
38
|
+
flex-wrap: nowrap;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
padding: 8px 0px;
|
|
42
|
+
max-height: 44px;
|
|
43
|
+
gap: 16px;
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
const AddonName = styled(Typography)`
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
font-feature-settings: 'liga' off, 'clig' off;
|
|
49
|
+
text-overflow: ellipsis;
|
|
50
|
+
font-family: 'DM Sans';
|
|
51
|
+
letter-spacing: 0.15px;
|
|
52
|
+
white-space: nowrap;
|
|
53
|
+
min-width: 0;
|
|
54
|
+
flex-shrink: 1;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const AddonIcon = styled(Icon)`
|
|
58
|
+
width: 24px;
|
|
59
|
+
height: 24px;
|
|
60
|
+
color: ${({ theme }) => theme.stigg.palette.primary};
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const AddonContent = styled.div`
|
|
64
|
+
flex: 1;
|
|
65
|
+
min-width: 0;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const Footer = styled.div`
|
|
69
|
+
margin-top: 16px;
|
|
70
|
+
display: flex;
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const MAX_ADDONS = 4;
|
|
74
|
+
|
|
75
|
+
type PlanCompatibleAddonsProps = {
|
|
76
|
+
addons: Addon[];
|
|
77
|
+
paywallLocale: PaywallLocalization;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export function PlanCompatibleAddons({ addons, paywallLocale }: PlanCompatibleAddonsProps) {
|
|
81
|
+
const [showAllAddons, setShowAllAddons] = useState(false);
|
|
82
|
+
|
|
83
|
+
if (!addons || addons.length === 0) return null;
|
|
84
|
+
|
|
85
|
+
const visibleAddons = addons.filter((addon) => !addon.hiddenFromWidgets?.includes(WidgetType.Paywall));
|
|
86
|
+
|
|
87
|
+
const toggleShowAllAddons = () => {
|
|
88
|
+
setShowAllAddons(!showAllAddons);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const displayedAddons = showAllAddons ? visibleAddons : visibleAddons.slice(0, MAX_ADDONS);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<AddonsBox className="stigg-compatible-addons-container">
|
|
95
|
+
<Typography className="stigg-compatible-addons-header" color="secondary" variant="body1" bold>
|
|
96
|
+
{paywallLocale.addonsTitle}
|
|
97
|
+
</Typography>
|
|
98
|
+
<AddonsList className="stigg-compatible-addons-list">
|
|
99
|
+
{displayedAddons.map((addon) => {
|
|
100
|
+
return (
|
|
101
|
+
<AddonRow
|
|
102
|
+
key={addon.id}
|
|
103
|
+
className={classNames(`stigg-compatible-addon--${addon.id}`, 'stigg-compatible-addon-item')}>
|
|
104
|
+
<AddonIcon icon="Add" className="stigg-compatible-addon-icon" />
|
|
105
|
+
<AddonContent className="stigg-compatible-addon-content">
|
|
106
|
+
<AddonName variant="body1" color="primary" className="stigg-compatible-addon-name">
|
|
107
|
+
{addon.displayName}
|
|
108
|
+
</AddonName>
|
|
109
|
+
</AddonContent>
|
|
110
|
+
</AddonRow>
|
|
111
|
+
);
|
|
112
|
+
})}
|
|
113
|
+
</AddonsList>
|
|
114
|
+
{visibleAddons.length > MAX_ADDONS && (
|
|
115
|
+
<Footer>
|
|
116
|
+
<StyledButton variant="text" onClick={toggleShowAllAddons}>
|
|
117
|
+
<ButtonText color="primary.main">
|
|
118
|
+
{showAllAddons ? 'Show less' : `Show ${visibleAddons.length - MAX_ADDONS} more`}
|
|
119
|
+
</ButtonText>
|
|
120
|
+
</StyledButton>
|
|
121
|
+
</Footer>
|
|
122
|
+
)}
|
|
123
|
+
</AddonsBox>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -16,7 +16,7 @@ function getTitle(plan: PaywallPlan, paywallLocale: PaywallLocalization, hasFeat
|
|
|
16
16
|
if (paywallLocale.entitlementsTitle) {
|
|
17
17
|
return paywallLocale.entitlementsTitle(plan);
|
|
18
18
|
}
|
|
19
|
-
let title = hasFeatures ?
|
|
19
|
+
let title = hasFeatures ? `Includes:` : '';
|
|
20
20
|
if (plan.basePlan) {
|
|
21
21
|
title = `Everything in ${plan.basePlan.displayName}${hasFeatures ? ', plus:' : ''}`;
|
|
22
22
|
}
|
|
@@ -12,6 +12,7 @@ import { Typography } from '../common/Typography';
|
|
|
12
12
|
import MiniSchedule from '../../assets/mini-schedule.svg';
|
|
13
13
|
import { PlanPrice } from './PlanPrice';
|
|
14
14
|
import { getTiersPerUnitQuantities } from '../utils/priceTierUtils';
|
|
15
|
+
import { PlanCompatibleAddons } from './PlanCompatibleAddons';
|
|
15
16
|
|
|
16
17
|
const PlanOfferingButtonHeight = '66px';
|
|
17
18
|
|
|
@@ -32,6 +33,10 @@ const PlanOfferingContainer = styled.div<{ $isHighlighted: boolean; $isCurrentPl
|
|
|
32
33
|
position: relative;
|
|
33
34
|
`;
|
|
34
35
|
|
|
36
|
+
const AddonsContainer = styled.div<{ $planHasEntitlements: boolean }>`
|
|
37
|
+
margin-top: ${({ $planHasEntitlements }) => ($planHasEntitlements ? '32px' : '0px')};
|
|
38
|
+
`;
|
|
39
|
+
|
|
35
40
|
const PlanHeader = styled(Typography)`
|
|
36
41
|
padding-bottom: 8px;
|
|
37
42
|
`;
|
|
@@ -87,6 +92,7 @@ type PlanOfferingProps = {
|
|
|
87
92
|
withStartingAtRow: boolean;
|
|
88
93
|
isCustomerInCustomPlan: boolean;
|
|
89
94
|
selectDefaultTierIndex?: SelectDefaultTierIndexFn;
|
|
95
|
+
hideCompatibleAddons?: boolean;
|
|
90
96
|
};
|
|
91
97
|
|
|
92
98
|
const NextPlanTagContainer = styled.div`
|
|
@@ -140,6 +146,7 @@ export function PlanOffering({
|
|
|
140
146
|
withStartingAtRow,
|
|
141
147
|
isCustomerInCustomPlan,
|
|
142
148
|
selectDefaultTierIndex,
|
|
149
|
+
hideCompatibleAddons,
|
|
143
150
|
}: PlanOfferingProps) {
|
|
144
151
|
const isNextPlan = plan.isNextPlan && plan.isNextPlan(billingPeriod);
|
|
145
152
|
const planPrices = plan.pricePoints.filter((pricePoint) => pricePoint.billingPeriod === billingPeriod);
|
|
@@ -238,6 +245,12 @@ export function PlanOffering({
|
|
|
238
245
|
</HeaderWrapper>
|
|
239
246
|
|
|
240
247
|
<PlanEntitlements plan={plan} billingPeriod={billingPeriod} paywallLocale={paywallLocale} />
|
|
248
|
+
|
|
249
|
+
<AddonsContainer $planHasEntitlements={plan.entitlements.length > 0} className="stigg-addons-container">
|
|
250
|
+
{!hideCompatibleAddons && plan.compatibleAddons && plan.compatibleAddons.length > 0 && (
|
|
251
|
+
<PlanCompatibleAddons addons={plan.compatibleAddons} paywallLocale={paywallLocale} />
|
|
252
|
+
)}
|
|
253
|
+
</AddonsContainer>
|
|
241
254
|
</PlanOfferingContainer>
|
|
242
255
|
);
|
|
243
256
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { PaywallContainer as Paywall, PaywallContainerProps as PaywallProps } from './PaywallContainer';
|
|
2
2
|
export * from './types';
|
|
3
3
|
export { PaywallLocalization, PlanPriceText, CurrentPlanParams } from './paywallTextOverrides';
|
|
4
|
+
export { PlanCompatibleAddons } from './PlanCompatibleAddons';
|
|
@@ -21,6 +21,7 @@ export type CurrentPlanParams = {
|
|
|
21
21
|
export type PaywallLocalization = {
|
|
22
22
|
highlightChip: string;
|
|
23
23
|
entitlementsTitle?: (plan: PaywallPlan) => string;
|
|
24
|
+
addonsTitle?: string;
|
|
24
25
|
planCTAButton: {
|
|
25
26
|
upgrade: string | ((plan: PaywallPlan) => string);
|
|
26
27
|
downgrade: string | ((plan: PaywallPlan) => string);
|
|
@@ -51,6 +52,7 @@ export type PaywallLocalization = {
|
|
|
51
52
|
export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<PaywallLocalization>) {
|
|
52
53
|
const paywallDefaultLocalization: PaywallLocalization = {
|
|
53
54
|
highlightChip: 'Recommended',
|
|
55
|
+
addonsTitle: 'Available add-ons:',
|
|
54
56
|
planCTAButton: {
|
|
55
57
|
upgrade: 'Upgrade',
|
|
56
58
|
downgrade: 'Downgrade',
|
|
@@ -40,6 +40,7 @@ const Template: ComponentStory<any> = (args) => (
|
|
|
40
40
|
billingCountryCode={args.billingCountryCode}
|
|
41
41
|
preferredBillingPeriod={args.preferredBillingPeriod}
|
|
42
42
|
shouldHidePlan={args.shouldHidePlan}
|
|
43
|
+
hideCompatibleAddons={args.hideCompatibleAddons}
|
|
43
44
|
/>
|
|
44
45
|
);
|
|
45
46
|
|
|
@@ -121,3 +122,18 @@ CustomerResourcePaywall.args = {
|
|
|
121
122
|
productId: 'product-site',
|
|
122
123
|
resourceId: 'example.com',
|
|
123
124
|
};
|
|
125
|
+
|
|
126
|
+
export const PaywallWithAddons = Template.bind({});
|
|
127
|
+
PaywallWithAddons.args = {
|
|
128
|
+
...defaultArgs,
|
|
129
|
+
highlightedPlanId: 'plan-revvenu-essentials',
|
|
130
|
+
hideCompatibleAddons: false,
|
|
131
|
+
textOverrides: {
|
|
132
|
+
highlightChip: 'Best value',
|
|
133
|
+
planCTAButton: {
|
|
134
|
+
startTrial: () => 'Start trial',
|
|
135
|
+
upgrade: 'Start now',
|
|
136
|
+
custom: 'Contact us',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
};
|