@stigg/react-sdk 4.9.0 → 4.10.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/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.d.ts +1 -1
- package/dist/components/customerPortal/usage/featureUsage/EntitlementCTAButton.d.ts +1 -1
- package/dist/react-sdk.cjs.development.js +15 -15
- package/dist/react-sdk.cjs.development.js.map +1 -1
- package/dist/react-sdk.cjs.production.min.js.map +1 -1
- package/dist/react-sdk.esm.js +15 -15
- package/dist/react-sdk.esm.js.map +1 -1
- package/package.json +7 -5
- package/src/components/checkout/hooks/useCouponModel.ts +1 -1
- package/src/components/checkout/steps/addons/addon.utils.ts +6 -6
- package/src/components/common/PoweredByStigg.tsx +1 -2
- package/src/components/common/iconColor.ts +2 -4
- package/src/components/customerPortal/CustomerPortal.style.ts +2 -2
- package/src/components/customerPortal/CustomerPortalProvider.tsx +1 -2
- package/src/components/customerPortal/billing/InformationGrid.tsx +1 -2
- package/src/components/customerPortal/billing/InvoicesSection.tsx +9 -4
- package/src/components/customerPortal/common/ExternalLinkButton.tsx +2 -3
- package/src/components/customerPortal/common/SectionContainer.tsx +1 -1
- package/src/components/customerPortal/common/SectionHeader.ts +4 -2
- package/src/components/customerPortal/common/SkeletonButton.tsx +1 -1
- package/src/components/customerPortal/subscriptionOverview/ContactCustomerSupport.tsx +1 -2
- package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverview.tsx +1 -2
- package/src/components/customerPortal/subscriptionOverview/SubscriptionsOverviewHeader.tsx +3 -8
- package/src/components/customerPortal/subscriptionOverview/charges/ChargeItem.tsx +1 -1
- package/src/components/customerPortal/subscriptionOverview/charges/ChargeList.tsx +1 -1
- package/src/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.tsx +8 -4
- package/src/components/customerPortal/subscriptionOverview/tabs/AddonsList.tsx +1 -1
- package/src/components/customerPortal/subscriptionOverview/tabs/Promotions.tsx +1 -1
- package/src/components/customerPortal/subscriptionOverview/tabs/SubscriptionTabs.tsx +2 -2
- package/src/components/customerPortal/subscriptionOverview/upcomingBilling/NoUpcomingBilling.tsx +4 -2
- package/src/components/customerPortal/subscriptionOverview/upcomingBilling/UpcomingBilling.tsx +1 -1
- package/src/components/customerPortal/types.ts +2 -2
- package/src/components/customerPortal/usage/featureUsage/EntitlementCTAButton.tsx +10 -3
- package/src/components/customerPortal/usage/featureUsage/FeatureUsage.style.ts +1 -1
- package/src/components/customerPortal/usage/featureUsage/FeatureUsage.tsx +2 -4
- package/src/components/hooks/useChargeSort.ts +2 -2
- package/src/components/paywall/PlanEntitlements.tsx +4 -4
- package/src/components/paywall/paywallTextOverrides.ts +2 -2
- package/src/components/paywall/utils/computeDefaultBillingPeriod.ts +2 -2
- package/src/components/paywall/utils/hasPricePoints.ts +3 -3
- package/src/components/utils/calculateDiscountRate.ts +3 -3
- package/src/components/utils/getFeatureName.ts +7 -3
- package/src/components/utils/getPlanPrice.ts +2 -2
- package/src/components/utils/priceTierUtils.ts +6 -4
- package/src/types.ts +1 -1
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.10.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"lint-fix": "yarn run lint --fix",
|
|
19
19
|
"size": "size-limit",
|
|
20
20
|
"analyze": "size-limit --why",
|
|
21
|
-
"fix:prettier": "prettier \"src/**/*.ts\" --write",
|
|
21
|
+
"fix:prettier": "prettier \"src/**/*.(js|jsx|ts|tsx)\" --write",
|
|
22
|
+
"pretty-quick": "pretty-quick --staged --pattern 'src/**/*.*(js|jsx|ts|tsx)'",
|
|
22
23
|
"storybook": "export NODE_OPTIONS=--openssl-legacy-provider && start-storybook -p 6006",
|
|
23
24
|
"build-storybook": "build-storybook",
|
|
24
25
|
"prepare": "husky install",
|
|
@@ -88,14 +89,15 @@
|
|
|
88
89
|
"eslint-plugin-import": "^2.28.1",
|
|
89
90
|
"eslint-plugin-jest": "^25.3.2",
|
|
90
91
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
|
91
|
-
"eslint-plugin-prettier": "^
|
|
92
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
92
93
|
"eslint-plugin-react": "^7.28.0",
|
|
93
94
|
"eslint-plugin-react-hooks": "^4.2.0",
|
|
94
95
|
"eslint-plugin-unused-imports": "^2.0.0",
|
|
95
96
|
"husky": "^7.0.4",
|
|
96
97
|
"lint-staged": "^14.0.1",
|
|
97
98
|
"postcss": "^8.4.24",
|
|
98
|
-
"prettier": "^
|
|
99
|
+
"prettier": "^2.4.1",
|
|
100
|
+
"pretty-quick": "^3.1.3",
|
|
99
101
|
"react": "^18.0.0",
|
|
100
102
|
"react-dom": "^18.0.0",
|
|
101
103
|
"rollup-plugin-postcss": "^4.0.2",
|
|
@@ -120,10 +122,10 @@
|
|
|
120
122
|
"immer": "^10.0.2",
|
|
121
123
|
"lodash": "^4.17.21",
|
|
122
124
|
"lodash-es": "^4.17.21",
|
|
125
|
+
"lottie-react": "^2.4.0",
|
|
123
126
|
"moment": "^2.29.4",
|
|
124
127
|
"react-feather": "^2.0.10",
|
|
125
128
|
"react-loading-skeleton": "^3.1.0",
|
|
126
|
-
"lottie-react": "^2.4.0",
|
|
127
129
|
"react-spinners": "^0.13.3",
|
|
128
130
|
"react-switch": "^7.0.0",
|
|
129
131
|
"styled-components": "^5.3.6",
|
|
@@ -23,8 +23,8 @@ export function filterAddons({
|
|
|
23
23
|
}: { addons?: Addon[] } & filterAddonsBaseProps): Addon[] {
|
|
24
24
|
return (
|
|
25
25
|
addons
|
|
26
|
-
?.filter(addon => filterAddonPricePointsByBillingPeriod(addon, billingPeriod))
|
|
27
|
-
?.map(addon => mapAddonPricePointsByBillingCountryCode({ addon, currency, billingCountryCode })) || []
|
|
26
|
+
?.filter((addon) => filterAddonPricePointsByBillingPeriod(addon, billingPeriod))
|
|
27
|
+
?.map((addon) => mapAddonPricePointsByBillingCountryCode({ addon, currency, billingCountryCode })) || []
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -36,8 +36,8 @@ export function filterSubscriptionAddons({
|
|
|
36
36
|
}: { addons?: SubscriptionAddon[] } & filterAddonsBaseProps): SubscriptionAddon[] {
|
|
37
37
|
return (
|
|
38
38
|
addons
|
|
39
|
-
?.filter(addon => filterAddonPricePointsByBillingPeriod(addon.addon, billingPeriod))
|
|
40
|
-
?.map(addon => ({
|
|
39
|
+
?.filter((addon) => filterAddonPricePointsByBillingPeriod(addon.addon, billingPeriod))
|
|
40
|
+
?.map((addon) => ({
|
|
41
41
|
...addon,
|
|
42
42
|
addon: mapAddonPricePointsByBillingCountryCode({ addon: addon.addon, currency, billingCountryCode }),
|
|
43
43
|
})) || []
|
|
@@ -45,7 +45,7 @@ export function filterSubscriptionAddons({
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function filterAddonPricePointsByBillingPeriod(addon: Addon, billingPeriod: BillingPeriod) {
|
|
48
|
-
return addon.pricePoints.some(pricePoint => pricePoint.billingPeriod === billingPeriod);
|
|
48
|
+
return addon.pricePoints.some((pricePoint) => pricePoint.billingPeriod === billingPeriod);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function mapAddonPricePointsByBillingCountryCode({
|
|
@@ -60,7 +60,7 @@ function mapAddonPricePointsByBillingCountryCode({
|
|
|
60
60
|
return {
|
|
61
61
|
...addon,
|
|
62
62
|
pricePoints: addon.pricePoints.filter(
|
|
63
|
-
pricePoint =>
|
|
63
|
+
(pricePoint) =>
|
|
64
64
|
pricePoint.currency === currency &&
|
|
65
65
|
(billingCountryCode ? pricePoint.billingCountryCode === billingCountryCode : true),
|
|
66
66
|
),
|
|
@@ -45,8 +45,7 @@ export function PoweredByStigg({ source, showWatermark, align, style = {} }: Pow
|
|
|
45
45
|
$alignSelf={align}
|
|
46
46
|
className={STIGG_WATERMARK_CLASSNAME}
|
|
47
47
|
style={{ cursor: 'pointer', ...style }}
|
|
48
|
-
onClick={onWatermarkClick}
|
|
49
|
-
>
|
|
48
|
+
onClick={onWatermarkClick}>
|
|
50
49
|
<PoweredByStiggThemedSvg />
|
|
51
50
|
</StyledPoweredByStigg>
|
|
52
51
|
);
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Theme } from '@emotion/react';
|
|
2
2
|
|
|
3
|
-
export type IconColor =
|
|
4
|
-
| 'primary'
|
|
5
|
-
| 'secondary'
|
|
3
|
+
export type IconColor = 'primary' | 'secondary';
|
|
6
4
|
|
|
7
|
-
export const getIconColor = (color: IconColor | string | undefined, theme: Theme
|
|
5
|
+
export const getIconColor = (color: IconColor | string | undefined, theme: Theme) => {
|
|
8
6
|
switch (color) {
|
|
9
7
|
case 'primary':
|
|
10
8
|
return theme.stigg.palette.text.primary;
|
|
@@ -5,7 +5,7 @@ export const CustomerPortalLayout = styled.div`
|
|
|
5
5
|
display: flex;
|
|
6
6
|
flex-direction: column;
|
|
7
7
|
align-items: center;
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
& * {
|
|
10
10
|
box-sizing: border-box;
|
|
11
11
|
}
|
|
@@ -17,4 +17,4 @@ export const CustomerPortalSections = styled.div`
|
|
|
17
17
|
flex-direction: column;
|
|
18
18
|
align-items: center;
|
|
19
19
|
row-gap: 24px;
|
|
20
|
-
`;
|
|
20
|
+
`;
|
|
@@ -42,8 +42,7 @@ export function InformationGrid({ title, rows }: InformationGridProps) {
|
|
|
42
42
|
variant="body1"
|
|
43
43
|
color="secondary"
|
|
44
44
|
style={{ width: 80 }}
|
|
45
|
-
{...labelTypographyProps}
|
|
46
|
-
>
|
|
45
|
+
{...labelTypographyProps}>
|
|
47
46
|
{label}
|
|
48
47
|
</Typography>
|
|
49
48
|
<Typography className={`${classNamePrefix}-text`} variant="body1" color="secondary" {...valueTypographyProps}>
|
|
@@ -10,7 +10,9 @@ export function InvoicesSection() {
|
|
|
10
10
|
const { customerPortal, isLoading, textOverrides, theme } = useCustomerPortalContext();
|
|
11
11
|
const isLoadingData = !customerPortal || isLoading;
|
|
12
12
|
|
|
13
|
-
const viewInvoiceHistoryButton = isLoadingData ?
|
|
13
|
+
const viewInvoiceHistoryButton = isLoadingData ? (
|
|
14
|
+
<SkeletonButton />
|
|
15
|
+
) : customerPortal?.billingPortalUrl ? (
|
|
14
16
|
<ExternalLinkButton
|
|
15
17
|
url={customerPortal.billingPortalUrl}
|
|
16
18
|
text={textOverrides.viewInvoiceHistory}
|
|
@@ -26,10 +28,13 @@ export function InvoicesSection() {
|
|
|
26
28
|
<SectionContainer
|
|
27
29
|
className="stigg-invoices-section-layout"
|
|
28
30
|
$backgroundColor={theme.backgroundColor}
|
|
29
|
-
$borderColor={theme.borderColor}
|
|
30
|
-
>
|
|
31
|
+
$borderColor={theme.borderColor}>
|
|
31
32
|
<SectionHeader className="stigg-invoices-section-header">
|
|
32
|
-
<SectionTitle
|
|
33
|
+
<SectionTitle
|
|
34
|
+
isLoading={isLoadingData}
|
|
35
|
+
className="stigg-invoices-section-title"
|
|
36
|
+
title={textOverrides.invoicesTitle}
|
|
37
|
+
/>
|
|
33
38
|
{viewInvoiceHistoryButton}
|
|
34
39
|
</SectionHeader>
|
|
35
40
|
</SectionContainer>
|
|
@@ -28,9 +28,8 @@ export function ExternalLinkButton({ text, url, className }: ExternalLinkButtonP
|
|
|
28
28
|
className={className}
|
|
29
29
|
variant="outlined"
|
|
30
30
|
startIcon={<LinkIcon size={20} strokeWidth={2.5} />}
|
|
31
|
-
onClick={onClick}
|
|
32
|
-
>
|
|
31
|
+
onClick={onClick}>
|
|
33
32
|
<ExternalLinkText color="primary.main">{text}</ExternalLinkText>
|
|
34
33
|
</StyledButton>
|
|
35
34
|
);
|
|
36
|
-
}
|
|
35
|
+
}
|
|
@@ -5,9 +5,11 @@ export const SectionHeader = styled.div<{ $disableMargin?: boolean }>`
|
|
|
5
5
|
align-items: center;
|
|
6
6
|
justify-content: space-between;
|
|
7
7
|
|
|
8
|
-
${({ $disableMargin }) =>
|
|
8
|
+
${({ $disableMargin }) =>
|
|
9
|
+
!$disableMargin &&
|
|
10
|
+
`
|
|
9
11
|
&:not(:last-child) {
|
|
10
12
|
margin-bottom: 32px;
|
|
11
13
|
}
|
|
12
14
|
`};
|
|
13
|
-
`;
|
|
15
|
+
`;
|
|
@@ -38,8 +38,7 @@ export function ContactCustomerSupport({ onContactSupport, label, linkLabel }: C
|
|
|
38
38
|
className="stigg-contact-support-button"
|
|
39
39
|
style={{ textTransform: 'none' }}
|
|
40
40
|
variant="text"
|
|
41
|
-
onClick={onContactSupport}
|
|
42
|
-
>
|
|
41
|
+
onClick={onContactSupport}>
|
|
43
42
|
{contactSupportText}
|
|
44
43
|
</ContactSupportButton>
|
|
45
44
|
) : (
|
|
@@ -42,8 +42,7 @@ export function SubscriptionsOverview({
|
|
|
42
42
|
<SectionContainer
|
|
43
43
|
className="stigg-customer-portal-subscriptions-overview"
|
|
44
44
|
$backgroundColor={theme.backgroundColor}
|
|
45
|
-
$borderColor={theme.borderColor}
|
|
46
|
-
>
|
|
45
|
+
$borderColor={theme.borderColor}>
|
|
47
46
|
{!isLoadingData && activeSubscription && activeSubscription.scheduledUpdates && (
|
|
48
47
|
<SubscriptionScheduledUpdatesAlert
|
|
49
48
|
theme={theme}
|
|
@@ -28,20 +28,15 @@ export function SubscriptionsOverviewHeader({
|
|
|
28
28
|
}: SubscriptionsOverviewHeaderProps) {
|
|
29
29
|
return (
|
|
30
30
|
<SectionHeader className="stigg-customer-portal-overview-header" $disableMargin>
|
|
31
|
-
<SectionTitle title=
|
|
31
|
+
<SectionTitle title="Subscription" className="stigg-overview-title" />
|
|
32
32
|
{!hideManageButton && (
|
|
33
|
-
<StyledButton
|
|
34
|
-
className="stigg-manage-subscription-button"
|
|
35
|
-
variant="outlined"
|
|
36
|
-
onClick={onManageSubscription}
|
|
37
|
-
>
|
|
33
|
+
<StyledButton className="stigg-manage-subscription-button" variant="outlined" onClick={onManageSubscription}>
|
|
38
34
|
<StyledEditIcon className="stigg-manage-subscription-button-image" />
|
|
39
35
|
<Typography
|
|
40
36
|
className="stigg-manage-subscription-button-text"
|
|
41
37
|
color="primary.main"
|
|
42
38
|
style={{ marginLeft: '8px' }}
|
|
43
|
-
variant="body1"
|
|
44
|
-
>
|
|
39
|
+
variant="body1">
|
|
45
40
|
{textOverrides?.manageSubscription}
|
|
46
41
|
</Typography>
|
|
47
42
|
</StyledButton>
|
|
@@ -32,7 +32,7 @@ export function ChargeItem({
|
|
|
32
32
|
hasCustomSubscription,
|
|
33
33
|
}: UsageBasedChargeProps) {
|
|
34
34
|
return (
|
|
35
|
-
<div className=
|
|
35
|
+
<div className="stigg-charge-list-item" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
|
36
36
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}>
|
|
37
37
|
<div style={{ display: 'flex', gap: 12 }}>
|
|
38
38
|
<LongText variant="body1" color="primary">
|
|
@@ -32,7 +32,7 @@ export function ChargeList({
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
|
-
<div className=
|
|
35
|
+
<div className="stigg-charge-list" style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 32 }}>
|
|
36
36
|
{filteredSubscriptionPrices.map(({ feature, price, billingModel }) => {
|
|
37
37
|
if (!feature || !price) {
|
|
38
38
|
return null;
|
package/src/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.tsx
CHANGED
|
@@ -11,15 +11,19 @@ type SubscriptionViewProps = {
|
|
|
11
11
|
theme: CustomerPortalTheme;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export function SubscriptionView({
|
|
14
|
+
export function SubscriptionView({
|
|
15
|
+
mainSubscription,
|
|
16
|
+
trialSubscription,
|
|
17
|
+
onManageSubscription,
|
|
18
|
+
theme,
|
|
19
|
+
}: SubscriptionViewProps) {
|
|
15
20
|
return (
|
|
16
21
|
<div className="stigg-subscription-view-layout">
|
|
17
22
|
<Typography
|
|
18
23
|
className="stigg-subscription-plan-name"
|
|
19
|
-
variant=
|
|
24
|
+
variant="h1"
|
|
20
25
|
overrideColor={theme.planNameColor}
|
|
21
|
-
style={{ marginTop: 8 }}
|
|
22
|
-
>
|
|
26
|
+
style={{ marginTop: 8 }}>
|
|
23
27
|
{mainSubscription.planName} plan
|
|
24
28
|
</Typography>
|
|
25
29
|
|
|
@@ -6,7 +6,7 @@ import { useCustomerPortalContext } from '../../CustomerPortalProvider';
|
|
|
6
6
|
|
|
7
7
|
export function AddonsList() {
|
|
8
8
|
const { customerPortal } = useCustomerPortalContext();
|
|
9
|
-
const addons = flatMap(customerPortal?.subscriptions, subscription => subscription.addons);
|
|
9
|
+
const addons = flatMap(customerPortal?.subscriptions, (subscription) => subscription.addons);
|
|
10
10
|
if (isEmpty(addons)) {
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
@@ -47,7 +47,7 @@ export function Promotions() {
|
|
|
47
47
|
Expiration date
|
|
48
48
|
</Typography>
|
|
49
49
|
</Row>
|
|
50
|
-
{promotionalEntitlements?.map(promotionalEntitlement => (
|
|
50
|
+
{promotionalEntitlements?.map((promotionalEntitlement) => (
|
|
51
51
|
<Row $borderColor={theme.borderColor}>
|
|
52
52
|
<Typography variant="body1">{getPromotionTitle(promotionalEntitlement)}</Typography>
|
|
53
53
|
<Typography variant="body1" color="disabled">
|
|
@@ -50,9 +50,9 @@ function TabTitle({ isSelected, label, icon }: { isSelected: boolean; label: str
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function SubscriptionTabs({ customerPortal, hiddenSections, textOverrides, theme }: SubscriptionTabsProps) {
|
|
53
|
-
const allAddons = flatMap(customerPortal.subscriptions, subscription => subscription.addons);
|
|
53
|
+
const allAddons = flatMap(customerPortal.subscriptions, (subscription) => subscription.addons);
|
|
54
54
|
const isSectionHidden = (sectionName: CustomerPortalSection) =>
|
|
55
|
-
hiddenSections?.some(section => section === sectionName);
|
|
55
|
+
hiddenSections?.some((section) => section === sectionName);
|
|
56
56
|
const showAddons = allAddons.length > 0 && !isSectionHidden('addons');
|
|
57
57
|
const showPromotions =
|
|
58
58
|
customerPortal.promotionalEntitlements.length > 0 && !isSectionHidden('promotionalEntitlements');
|
package/src/components/customerPortal/subscriptionOverview/upcomingBilling/NoUpcomingBilling.tsx
CHANGED
|
@@ -8,8 +8,10 @@ type NoUpcomingBillingProps = {
|
|
|
8
8
|
export function NoUpcomingBilling({ description }: NoUpcomingBillingProps) {
|
|
9
9
|
return (
|
|
10
10
|
<>
|
|
11
|
-
<Typography variant=
|
|
12
|
-
|
|
11
|
+
<Typography variant="h6" color="secondary">
|
|
12
|
+
No upcoming bill
|
|
13
|
+
</Typography>
|
|
14
|
+
<Typography variant="body1" color="secondary">
|
|
13
15
|
{description}
|
|
14
16
|
</Typography>
|
|
15
17
|
</>
|
package/src/components/customerPortal/subscriptionOverview/upcomingBilling/UpcomingBilling.tsx
CHANGED
|
@@ -35,7 +35,7 @@ export function UpcomingBilling({ subscription, theme, textOverrides, onContactS
|
|
|
35
35
|
const { pricingType } = subscription;
|
|
36
36
|
let content: ReactNode;
|
|
37
37
|
const noUsageBasedPrices =
|
|
38
|
-
subscription.prices?.every(price => price.billingModel !== BillingModel.UsageBased) ?? true;
|
|
38
|
+
subscription.prices?.every((price) => price.billingModel !== BillingModel.UsageBased) ?? true;
|
|
39
39
|
const scheduledDowngradeToFree = subscription.scheduledUpdates?.find(
|
|
40
40
|
({ subscriptionScheduleType, targetPackage }) =>
|
|
41
41
|
subscriptionScheduleType === SubscriptionScheduleType.Downgrade &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { CustomerPortalEntitlement } from '@stigg/js-client-sdk';
|
|
2
|
-
import { FeatureFragment
|
|
2
|
+
import { FeatureFragment } from '@stigg/api-client-js/src/generated/sdk';
|
|
3
3
|
|
|
4
|
-
export type OnBuyMoreCallbackFn = (feature: FeatureFragment, entitlement: CustomerPortalEntitlement) => void
|
|
4
|
+
export type OnBuyMoreCallbackFn = (feature: FeatureFragment, entitlement: CustomerPortalEntitlement) => void;
|
|
@@ -23,8 +23,15 @@ export type EntitlementCtaButtonProps = {
|
|
|
23
23
|
hasCustomSubscription: boolean;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
export function EntitlementCtaButton({
|
|
27
|
-
|
|
26
|
+
export function EntitlementCtaButton({
|
|
27
|
+
entitlement,
|
|
28
|
+
feature,
|
|
29
|
+
onManageSubscription,
|
|
30
|
+
onBuyMore,
|
|
31
|
+
canBuyMore,
|
|
32
|
+
canUpgradeSubscription,
|
|
33
|
+
hasCustomSubscription,
|
|
34
|
+
}: EntitlementCtaButtonProps) {
|
|
28
35
|
if (hasCustomSubscription || entitlement.hasUnlimitedUsage) {
|
|
29
36
|
return null;
|
|
30
37
|
}
|
|
@@ -50,4 +57,4 @@ export function EntitlementCtaButton({ entitlement, feature, onManageSubscriptio
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
return null;
|
|
53
|
-
}
|
|
60
|
+
}
|
|
@@ -51,8 +51,7 @@ export function FeatureUsage({
|
|
|
51
51
|
? 'Billed for committed usage'
|
|
52
52
|
: 'Billed for actual usage'}
|
|
53
53
|
</Typography>
|
|
54
|
-
}
|
|
55
|
-
>
|
|
54
|
+
}>
|
|
56
55
|
<Icon icon="DollarCoin" svgStrokeColor={theme.iconsColor} />
|
|
57
56
|
</InformationTooltip>
|
|
58
57
|
)}
|
|
@@ -62,8 +61,7 @@ export function FeatureUsage({
|
|
|
62
61
|
<LongText
|
|
63
62
|
variant="body1"
|
|
64
63
|
color={hasOverageUsage ? 'error' : 'primary'}
|
|
65
|
-
data-testid={`usage-data-${entitlement.feature?.refId}`}
|
|
66
|
-
>
|
|
64
|
+
data-testid={`usage-data-${entitlement.feature?.refId}`}>
|
|
67
65
|
{entitlement.currentUsage?.toLocaleString()}
|
|
68
66
|
{!entitlement.hasUnlimitedUsage &&
|
|
69
67
|
` / ${entitlement.usageLimit?.toLocaleString()} (${getUsagePercentage(
|
|
@@ -7,8 +7,8 @@ const CHARGES_BILLING_MODEL_ORDER = [BillingModel.FlatFee, BillingModel.PerUnit,
|
|
|
7
7
|
|
|
8
8
|
export const sortCharges = (charges: Price[]) => {
|
|
9
9
|
return sortBy(charges, [
|
|
10
|
-
charge => CHARGES_BILLING_MODEL_ORDER.indexOf(charge.pricingModel),
|
|
11
|
-
charge => charge.feature?.displayName,
|
|
10
|
+
(charge) => CHARGES_BILLING_MODEL_ORDER.indexOf(charge.pricingModel),
|
|
11
|
+
(charge) => charge.feature?.displayName,
|
|
12
12
|
]);
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -33,8 +33,8 @@ export function PlanEntitlements({
|
|
|
33
33
|
billingPeriod: BillingPeriod;
|
|
34
34
|
paywallLocale: PaywallLocalization;
|
|
35
35
|
}) {
|
|
36
|
-
const prices = plan.pricePoints?.filter(price => price.billingPeriod === billingPeriod);
|
|
37
|
-
const unitBasedEntitlements = prices?.map(price => {
|
|
36
|
+
const prices = plan.pricePoints?.filter((price) => price.billingPeriod === billingPeriod);
|
|
37
|
+
const unitBasedEntitlements = prices?.map((price) => {
|
|
38
38
|
const shouldRenderUnitBasedEntitlement =
|
|
39
39
|
(price?.minUnitQuantity && price?.minUnitQuantity > 1) || price?.maxUnitQuantity;
|
|
40
40
|
|
|
@@ -59,8 +59,8 @@ export function PlanEntitlements({
|
|
|
59
59
|
</Typography>
|
|
60
60
|
{unitBasedEntitlements}
|
|
61
61
|
{plan.entitlements
|
|
62
|
-
.filter(entitlement => !(entitlement.hiddenFromWidgets || []).includes(WidgetType.Paywall))
|
|
63
|
-
.map(entitlement => (
|
|
62
|
+
.filter((entitlement) => !(entitlement.hiddenFromWidgets || []).includes(WidgetType.Paywall))
|
|
63
|
+
.map((entitlement) => (
|
|
64
64
|
<EntitlementRow
|
|
65
65
|
key={entitlement.feature?.id}
|
|
66
66
|
displayNameOverride={entitlement.displayNameOverride}
|
|
@@ -51,7 +51,7 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
|
|
|
51
51
|
custom: 'Contact us',
|
|
52
52
|
currentPlan: 'Current plan',
|
|
53
53
|
startNew: 'Get started',
|
|
54
|
-
switchToBillingPeriod: billingPeriod => {
|
|
54
|
+
switchToBillingPeriod: (billingPeriod) => {
|
|
55
55
|
return billingPeriod === BillingPeriod.Monthly ? 'Switch to monthly billing' : 'Switch to annual billing';
|
|
56
56
|
},
|
|
57
57
|
cancelScheduledUpdate: 'Cancel',
|
|
@@ -59,7 +59,7 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
|
|
|
59
59
|
price: {
|
|
60
60
|
startingAtCaption: 'Starts at',
|
|
61
61
|
pricePeriod: (billingPeriod: BillingPeriod) => (billingPeriod === BillingPeriod.Monthly ? '/ month' : '/ year'),
|
|
62
|
-
free: currency => ({
|
|
62
|
+
free: (currency) => ({
|
|
63
63
|
price: `${currency?.symbol}0`,
|
|
64
64
|
}),
|
|
65
65
|
custom: 'Custom',
|
|
@@ -6,7 +6,7 @@ export function computeBillingPeriods(
|
|
|
6
6
|
activeSubscriptions?: Subscription[] | null,
|
|
7
7
|
preferredBillingPeriod?: BillingPeriod,
|
|
8
8
|
): { defaultBillingPeriod: BillingPeriod; availableBillingPeriods: BillingPeriod[] } {
|
|
9
|
-
const billingPeriods = plans.flatMap(x => x.pricePoints).map(x => x.billingPeriod);
|
|
9
|
+
const billingPeriods = plans.flatMap((x) => x.pricePoints).map((x) => x.billingPeriod);
|
|
10
10
|
const counts = countBy(billingPeriods);
|
|
11
11
|
|
|
12
12
|
const availableBillingPeriods = uniq(billingPeriods);
|
|
@@ -15,7 +15,7 @@ export function computeBillingPeriods(
|
|
|
15
15
|
if (preferredBillingPeriod && availableBillingPeriods.includes(preferredBillingPeriod)) {
|
|
16
16
|
defaultBillingPeriod = preferredBillingPeriod;
|
|
17
17
|
} else if (activeSubscriptions) {
|
|
18
|
-
const activeSubscription = activeSubscriptions.find(x => x.status == SubscriptionStatus.Active);
|
|
18
|
+
const activeSubscription = activeSubscriptions.find((x) => x.status == SubscriptionStatus.Active);
|
|
19
19
|
|
|
20
20
|
if (activeSubscription && activeSubscription.prices.length > 0) {
|
|
21
21
|
defaultBillingPeriod = activeSubscription?.prices[0].billingPeriod;
|
|
@@ -2,9 +2,9 @@ import { PaywallPlan } from '../types';
|
|
|
2
2
|
import { BillingPeriod } from '@stigg/js-client-sdk';
|
|
3
3
|
|
|
4
4
|
export function hasPricePointsForPlans(plans: PaywallPlan[], billingPeriod: BillingPeriod): boolean {
|
|
5
|
-
return plans.some(plan => hasPricePoints(plan, billingPeriod));
|
|
5
|
+
return plans.some((plan) => hasPricePoints(plan, billingPeriod));
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export function hasPricePoints(plan: PaywallPlan, billingPeriod: BillingPeriod): boolean {
|
|
9
|
-
return plan.pricePoints.some(pricePoint => pricePoint.billingPeriod === billingPeriod);
|
|
10
|
-
}
|
|
9
|
+
return plan.pricePoints.some((pricePoint) => pricePoint.billingPeriod === billingPeriod);
|
|
10
|
+
}
|
|
@@ -14,14 +14,14 @@ export function calculateDiscountRate(monthlyPrice?: number | null, annuallyPric
|
|
|
14
14
|
function getPlanBillingPeriodAmount(plan: PaywallPlan, billingPeriod: BillingPeriod) {
|
|
15
15
|
let pricePoint: PaywallCalculatedPricePoint | Price | undefined;
|
|
16
16
|
|
|
17
|
-
pricePoint = plan.paywallCalculatedPricePoints?.find(price => price.billingPeriod === billingPeriod);
|
|
17
|
+
pricePoint = plan.paywallCalculatedPricePoints?.find((price) => price.billingPeriod === billingPeriod);
|
|
18
18
|
|
|
19
19
|
if (!pricePoint) {
|
|
20
|
-
pricePoint = plan.pricePoints.find(price => price.billingPeriod === billingPeriod);
|
|
20
|
+
pricePoint = plan.pricePoints.find((price) => price.billingPeriod === billingPeriod);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
if (!pricePoint?.amount) {
|
|
24
|
-
const tieredPrice = plan.pricePoints.find(price => {
|
|
24
|
+
const tieredPrice = plan.pricePoints.find((price) => {
|
|
25
25
|
return price.isTieredPrice && price.billingPeriod === billingPeriod;
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -5,8 +5,12 @@ export function getFeatureDisplayName(feature: FeatureFragment) {
|
|
|
5
5
|
return getFeatureDisplayNameText(feature.displayName, feature.featureUnits, feature.featureUnitsPlural);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export function getFeatureDisplayNameText(
|
|
9
|
-
|
|
8
|
+
export function getFeatureDisplayNameText(
|
|
9
|
+
featureDisplayName: string,
|
|
10
|
+
featureUnits: string | undefined | null,
|
|
11
|
+
featureUnitsPlural: string | undefined | null,
|
|
12
|
+
) {
|
|
13
|
+
if (!featureUnits && !featureUnitsPlural) {
|
|
10
14
|
return featureDisplayName;
|
|
11
15
|
}
|
|
12
16
|
|
|
@@ -19,4 +23,4 @@ export function getFeatureDisplayNameText(featureDisplayName: string, featureUni
|
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
return `${featureDisplayName} (${featureUnitsPlural})`;
|
|
22
|
-
}
|
|
26
|
+
}
|
|
@@ -30,9 +30,9 @@ export function getPlanPrice(
|
|
|
30
30
|
price: paywallLocale.price.custom,
|
|
31
31
|
};
|
|
32
32
|
case PricingType.Paid: {
|
|
33
|
-
const planPrices = plan.pricePoints.filter(pricePoint => pricePoint.billingPeriod === billingPeriod);
|
|
33
|
+
const planPrices = plan.pricePoints.filter((pricePoint) => pricePoint.billingPeriod === billingPeriod);
|
|
34
34
|
const paywallCalculatedPrice = plan.paywallCalculatedPricePoints?.find(
|
|
35
|
-
pricePoint => pricePoint.billingPeriod === billingPeriod,
|
|
35
|
+
(pricePoint) => pricePoint.billingPeriod === billingPeriod,
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
if (!planPrices?.length && !paywallCalculatedPrice) {
|
|
@@ -50,7 +50,9 @@ export function getSelectedTier(
|
|
|
50
50
|
currentSubscription: Subscription | null,
|
|
51
51
|
selectedTierByFeature: Record<string, PriceTierFragment>,
|
|
52
52
|
): Record<string, PriceTierFragment> {
|
|
53
|
-
const planTierPrices = plan.pricePoints.filter(
|
|
53
|
+
const planTierPrices = plan.pricePoints.filter(
|
|
54
|
+
(price) => price.billingPeriod === billingPeriod && price.isTieredPrice,
|
|
55
|
+
);
|
|
54
56
|
|
|
55
57
|
if (planTierPrices.length == 1) {
|
|
56
58
|
const [price] = planTierPrices;
|
|
@@ -59,10 +61,10 @@ export function getSelectedTier(
|
|
|
59
61
|
let currentTier = price.tiers![0];
|
|
60
62
|
|
|
61
63
|
if (selectedTierByFeature[featureId]) {
|
|
62
|
-
currentTier = price.tiers?.find(tier => tier.upTo === selectedTierByFeature[featureId].upTo) || currentTier;
|
|
64
|
+
currentTier = price.tiers?.find((tier) => tier.upTo === selectedTierByFeature[featureId].upTo) || currentTier;
|
|
63
65
|
} else if (currentSubscription) {
|
|
64
66
|
const tieredPrice = currentSubscription.prices.find(
|
|
65
|
-
subscriptionPrice =>
|
|
67
|
+
(subscriptionPrice) =>
|
|
66
68
|
subscriptionPrice.pricingModel == BillingModel.PerUnit &&
|
|
67
69
|
subscriptionPrice.tiersMode &&
|
|
68
70
|
subscriptionPrice.feature?.featureId === featureId,
|
|
@@ -97,7 +99,7 @@ export function compareSelectedTierToCurrentTier(
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
const currentTierPrice = currentSubscription.prices.find(
|
|
100
|
-
price => price.pricingModel == BillingModel.PerUnit && price.tiersMode,
|
|
102
|
+
(price) => price.pricingModel == BillingModel.PerUnit && price.tiersMode,
|
|
101
103
|
);
|
|
102
104
|
if (!currentTierPrice) {
|
|
103
105
|
return PriceTierComparison.Equal;
|
package/src/types.ts
CHANGED