@stigg/react-sdk 4.4.0-beta.9 → 4.4.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/checkout/Checkout.d.ts +3 -2
- package/dist/components/checkout/CheckoutContainer.d.ts +4 -2
- package/dist/components/checkout/CheckoutProvider.d.ts +3 -2
- package/dist/components/checkout/components/DowngradeToFreeContainer.d.ts +3 -7
- package/dist/components/checkout/components/StyledArrow.d.ts +5 -0
- package/dist/components/checkout/hooks/useCheckoutModel.d.ts +2 -0
- package/dist/components/checkout/hooks/useLoadCheckout.d.ts +3 -1
- package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +17 -8
- package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +1 -0
- package/dist/components/checkout/promotionCode/AddPromotionCode.d.ts +2 -4
- package/dist/components/checkout/promotionCode/AddPromotionCodeButton.d.ts +2 -1
- package/dist/components/checkout/promotionCode/PromotionCodeSection.d.ts +6 -2
- package/dist/components/checkout/steps/plan/BillingPeriodPicker.d.ts +1 -1
- package/dist/components/checkout/steps/plan/CheckoutPlanStep.d.ts +2 -1
- package/dist/components/checkout/summary/CheckoutSummary.d.ts +1 -1
- package/dist/components/checkout/summary/components/CheckoutCaptions.d.ts +2 -2
- package/dist/components/checkout/summary/components/LineItems.d.ts +12 -8
- package/dist/components/checkout/textOverrides.d.ts +63 -20
- package/dist/components/checkout/theme.d.ts +0 -1
- package/dist/components/checkout/types.d.ts +7 -1
- package/dist/components/common/TiersSelectContainer.d.ts +1 -2
- package/dist/components/common/Typography.d.ts +2 -2
- package/dist/components/common/customIcons.d.ts +2 -0
- package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.style.d.ts +1 -1
- package/dist/components/paywall/PlanPrice.d.ts +1 -1
- package/dist/components/utils/currencyUtils.d.ts +2 -1
- package/dist/components/utils/getFeatureName.d.ts +1 -0
- package/dist/react-sdk.cjs.development.js +1027 -559
- 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 +1041 -582
- package/dist/react-sdk.esm.js.map +1 -1
- package/dist/stories/mocks/checkout/consts.d.ts +11 -0
- package/dist/stories/mocks/checkout/mockCheckoutPreview.d.ts +2 -0
- package/dist/stories/mocks/checkout/mockCheckoutState.d.ts +2 -0
- package/dist/theme/getResolvedTheme.d.ts +1 -0
- package/dist/theme/types.d.ts +1 -0
- package/package.json +28 -20
- package/src/assets/coupon.svg +6 -0
- package/src/assets/pay-as-you-go-charge.svg +11 -0
- package/src/components/checkout/Checkout.tsx +5 -2
- package/src/components/checkout/CheckoutContainer.tsx +18 -12
- package/src/components/checkout/CheckoutProvider.tsx +5 -3
- package/src/components/checkout/components/DowngradeToFreeContainer.tsx +33 -36
- package/src/components/checkout/components/StyledArrow.tsx +9 -0
- package/src/components/checkout/hooks/useCheckoutModel.ts +12 -2
- package/src/components/checkout/hooks/useLoadCheckout.ts +10 -2
- package/src/components/checkout/hooks/usePreviewSubscription.ts +102 -50
- package/src/components/checkout/planHeader/PlanHeader.tsx +18 -25
- package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +11 -12
- package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +7 -6
- package/src/components/checkout/promotionCode/AddPromotionCode.tsx +32 -9
- package/src/components/checkout/promotionCode/AddPromotionCodeButton.tsx +15 -11
- package/src/components/checkout/promotionCode/AppliedPromotionCode.tsx +4 -3
- package/src/components/checkout/promotionCode/PromotionCodeSection.tsx +21 -7
- package/src/components/checkout/steps/addons/CheckoutAddonsStep.style.tsx +0 -1
- package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +4 -3
- package/src/components/checkout/steps/payment/PaymentMethods.style.ts +4 -1
- package/src/components/checkout/steps/payment/PaymentStep.tsx +0 -1
- package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +3 -2
- package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +5 -2
- package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +35 -14
- package/src/components/checkout/steps/plan/CheckoutPlanStep.tsx +10 -5
- package/src/components/checkout/summary/CheckoutSuccess.tsx +1 -1
- package/src/components/checkout/summary/CheckoutSummary.tsx +143 -46
- package/src/components/checkout/summary/components/CheckoutCaptions.tsx +38 -15
- package/src/components/checkout/summary/components/LineItems.tsx +77 -28
- package/src/components/checkout/textOverrides.ts +107 -27
- package/src/components/checkout/theme.ts +0 -4
- package/src/components/checkout/types.ts +15 -1
- package/src/components/common/Icon.tsx +4 -6
- package/src/components/common/TiersSelectContainer.tsx +7 -8
- package/src/components/common/Typography.tsx +12 -3
- package/src/components/common/customIcons.ts +2 -0
- package/src/components/common/mapExternalTheme.ts +1 -2
- package/src/components/customerPortal/paywall/CustomerPortalPaywall.style.ts +4 -3
- package/src/components/paywall/PlanOfferingButton.tsx +6 -8
- package/src/components/paywall/PlanPrice.tsx +14 -17
- package/src/components/utils/currencyUtils.ts +4 -2
- package/src/components/utils/getFeatureName.ts +13 -5
- package/src/stories/Checkout.stories.tsx +37 -6
- package/src/stories/CustomerPortal.stories.tsx +2 -2
- package/src/stories/mocks/checkout/consts.ts +15 -0
- package/src/stories/mocks/checkout/mockCheckoutPreview.ts +138 -0
- package/src/stories/mocks/checkout/mockCheckoutState.ts +206 -0
- package/src/theme/Theme.tsx +10 -1
- package/src/theme/getResolvedTheme.ts +1 -0
- package/src/theme/types.ts +1 -0
- package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +0 -25
- package/src/components/checkout/planHeader/PlanHeader.style.tsx +0 -23
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from '@emotion/styled/macro';
|
|
3
3
|
import { Grid } from '@mui/material';
|
|
4
|
-
import {
|
|
4
|
+
import { BillingModel, BillingPeriod, Price, SubscriptionPreviewV2 } from '@stigg/js-client-sdk';
|
|
5
5
|
import { Typography } from '../../../common/Typography';
|
|
6
6
|
import { currencyPriceFormatter } from '../../../utils/currencyUtils';
|
|
7
7
|
import { getTierByQuantity } from '../../../utils/priceTierUtils';
|
|
8
8
|
import { WithSkeleton } from './WithSkeleton';
|
|
9
9
|
import { Skeleton } from '../../components/Skeletons.style';
|
|
10
10
|
import { CheckoutLocalization } from '../../textOverrides';
|
|
11
|
+
import { Icon } from '../../../common/Icon';
|
|
12
|
+
import { InformationTooltip } from '../../../common/InformationTooltip';
|
|
11
13
|
|
|
12
14
|
export const LineItemContainer = styled.div`
|
|
13
15
|
& + & {
|
|
@@ -30,15 +32,35 @@ export const getPriceString = ({ amount, price, quantity }: { amount: number; pr
|
|
|
30
32
|
billingPeriodString = '12 months';
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
const addonPriceFormat = currencyPriceFormatter({ amount, currency: price.currency });
|
|
35
|
+
const addonPriceFormat = currencyPriceFormatter({ amount, currency: price.currency, minimumFractionDigits: 2 });
|
|
34
36
|
|
|
35
37
|
return `${quantity > 1 ? `${quantity} x ${addonPriceFormat} each` : addonPriceFormat}${
|
|
36
38
|
billingPeriodString ? ` x ${billingPeriodString}` : ''
|
|
37
39
|
}`;
|
|
38
40
|
};
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const PayAsYouGoPriceTooltip = ({ checkoutLocalization }: { checkoutLocalization: CheckoutLocalization }) => {
|
|
43
|
+
const title = <Typography variant="body1">{checkoutLocalization.summary.payAsYouGoTooltipText}</Typography>;
|
|
44
|
+
return (
|
|
45
|
+
<InformationTooltip placement="left" title={title}>
|
|
46
|
+
<Icon icon="PayAsYouGoCharge" style={{ display: 'flex' }} />
|
|
47
|
+
</InformationTooltip>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const BilledPriceLineItem = ({
|
|
52
|
+
checkoutLocalization,
|
|
53
|
+
label,
|
|
54
|
+
quantity,
|
|
55
|
+
price,
|
|
56
|
+
}: {
|
|
57
|
+
checkoutLocalization: CheckoutLocalization;
|
|
58
|
+
label: string;
|
|
59
|
+
quantity: number;
|
|
60
|
+
price: Price;
|
|
61
|
+
}) => {
|
|
41
62
|
const { billingPeriod } = price;
|
|
63
|
+
const isPayAsYouGo = price.pricingModel === BillingModel.UsageBased;
|
|
42
64
|
|
|
43
65
|
let amount;
|
|
44
66
|
if (price.isTieredPrice) {
|
|
@@ -52,7 +74,7 @@ export const BilledPriceLineItem = ({ label, quantity, price }: { label: string;
|
|
|
52
74
|
<LineItemContainer>
|
|
53
75
|
<LineItemRow style={{ alignItems: 'flex-end' }}>
|
|
54
76
|
<Grid item>
|
|
55
|
-
<Typography variant="
|
|
77
|
+
<Typography variant="body1" color="secondary">
|
|
56
78
|
{label}
|
|
57
79
|
</Typography>
|
|
58
80
|
{(quantity > 1 || billingPeriod === BillingPeriod.Annually) && (
|
|
@@ -61,9 +83,30 @@ export const BilledPriceLineItem = ({ label, quantity, price }: { label: string;
|
|
|
61
83
|
</Typography>
|
|
62
84
|
)}
|
|
63
85
|
</Grid>
|
|
86
|
+
<Grid item display="flex" gap={1} alignItems="center">
|
|
87
|
+
{isPayAsYouGo && <PayAsYouGoPriceTooltip checkoutLocalization={checkoutLocalization} />}
|
|
88
|
+
<Typography variant="body1" color="secondary" style={{ wordBreak: 'break-word' }}>
|
|
89
|
+
{currencyPriceFormatter({ amount: quantity * amount, currency: price.currency, minimumFractionDigits: 2 })}
|
|
90
|
+
{isPayAsYouGo && ' / unit'}
|
|
91
|
+
</Typography>
|
|
92
|
+
</Grid>
|
|
93
|
+
</LineItemRow>
|
|
94
|
+
</LineItemContainer>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const FreeChargeLineItem = ({ label }: { label: string }) => {
|
|
99
|
+
return (
|
|
100
|
+
<LineItemContainer>
|
|
101
|
+
<LineItemRow style={{ alignItems: 'flex-end' }}>
|
|
64
102
|
<Grid item>
|
|
103
|
+
<Typography variant="body1" color="secondary">
|
|
104
|
+
{label}
|
|
105
|
+
</Typography>
|
|
106
|
+
</Grid>
|
|
107
|
+
<Grid item display="flex" gap={1} alignItems="center">
|
|
65
108
|
<Typography variant="body1" color="secondary" style={{ wordBreak: 'break-word' }}>
|
|
66
|
-
|
|
109
|
+
Free
|
|
67
110
|
</Typography>
|
|
68
111
|
</Grid>
|
|
69
112
|
</LineItemRow>
|
|
@@ -74,33 +117,35 @@ export const BilledPriceLineItem = ({ label, quantity, price }: { label: string;
|
|
|
74
117
|
export const DiscountLineItem = ({
|
|
75
118
|
subscriptionPreview,
|
|
76
119
|
isFetchingSubscriptionPreview,
|
|
120
|
+
checkoutLocalization,
|
|
77
121
|
}: {
|
|
78
|
-
subscriptionPreview:
|
|
122
|
+
subscriptionPreview: SubscriptionPreviewV2;
|
|
79
123
|
isFetchingSubscriptionPreview: boolean;
|
|
124
|
+
checkoutLocalization: CheckoutLocalization;
|
|
80
125
|
}) => {
|
|
81
|
-
const {
|
|
82
|
-
if (!
|
|
126
|
+
const { discount, discountDetails } = subscriptionPreview.recurringSubscription || {};
|
|
127
|
+
if (!discount || !discountDetails) {
|
|
83
128
|
return null;
|
|
84
129
|
}
|
|
85
130
|
|
|
86
|
-
let discountAmount: number;
|
|
87
|
-
if (discount.type === DiscountType.Percentage) {
|
|
88
|
-
discountAmount = -1 * Math.abs((discount.value / 100) * subTotal.amount);
|
|
89
|
-
} else {
|
|
90
|
-
discountAmount = -1 * Math.abs(discount.value);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
131
|
return (
|
|
94
132
|
<LineItemContainer>
|
|
95
133
|
<LineItemRow>
|
|
96
134
|
<Typography variant="body1" color="secondary">
|
|
97
|
-
{
|
|
135
|
+
{checkoutLocalization.summary.discountText({
|
|
136
|
+
discountDetails,
|
|
137
|
+
currency: subscriptionPreview.total.currency,
|
|
138
|
+
})}
|
|
98
139
|
</Typography>
|
|
99
140
|
<Typography variant="body1" color="secondary">
|
|
100
141
|
{isFetchingSubscriptionPreview ? (
|
|
101
142
|
<Skeleton width={50} height={16} />
|
|
102
143
|
) : (
|
|
103
|
-
currencyPriceFormatter({
|
|
144
|
+
currencyPriceFormatter({
|
|
145
|
+
amount: discount.amount,
|
|
146
|
+
currency: discount.currency,
|
|
147
|
+
minimumFractionDigits: 2,
|
|
148
|
+
})
|
|
104
149
|
)}
|
|
105
150
|
</Typography>
|
|
106
151
|
</LineItemRow>
|
|
@@ -113,12 +158,13 @@ export const AppliedCreditsLineItem = ({
|
|
|
113
158
|
isFetchingSubscriptionPreview,
|
|
114
159
|
checkoutLocalization,
|
|
115
160
|
}: {
|
|
116
|
-
subscriptionPreview:
|
|
161
|
+
subscriptionPreview: SubscriptionPreviewV2 | null;
|
|
117
162
|
isFetchingSubscriptionPreview: boolean;
|
|
118
163
|
checkoutLocalization: CheckoutLocalization;
|
|
119
164
|
}) => {
|
|
120
165
|
const { credits } = subscriptionPreview || {};
|
|
121
|
-
|
|
166
|
+
|
|
167
|
+
if (!credits || !credits.used || credits.used.amount <= 0) {
|
|
122
168
|
return null;
|
|
123
169
|
}
|
|
124
170
|
|
|
@@ -126,11 +172,15 @@ export const AppliedCreditsLineItem = ({
|
|
|
126
172
|
<LineItemContainer>
|
|
127
173
|
<LineItemRow>
|
|
128
174
|
<Typography variant="body1" color="secondary">
|
|
129
|
-
{checkoutLocalization.appliedCreditsTitle}
|
|
175
|
+
{checkoutLocalization.summary.appliedCreditsTitle}
|
|
130
176
|
</Typography>
|
|
131
177
|
<Typography variant="body1" color="secondary">
|
|
132
178
|
<WithSkeleton isLoading={isFetchingSubscriptionPreview}>
|
|
133
|
-
{currencyPriceFormatter({
|
|
179
|
+
{currencyPriceFormatter({
|
|
180
|
+
amount: -1 * credits.used.amount,
|
|
181
|
+
currency: credits.used.currency,
|
|
182
|
+
minimumFractionDigits: 2,
|
|
183
|
+
})}
|
|
134
184
|
</WithSkeleton>
|
|
135
185
|
</Typography>
|
|
136
186
|
</LineItemRow>
|
|
@@ -139,16 +189,15 @@ export const AppliedCreditsLineItem = ({
|
|
|
139
189
|
};
|
|
140
190
|
|
|
141
191
|
export const TaxLineItem = ({
|
|
142
|
-
|
|
192
|
+
tax,
|
|
193
|
+
taxDetails,
|
|
143
194
|
isFetchingSubscriptionPreview,
|
|
144
195
|
checkoutLocalization,
|
|
145
196
|
}: {
|
|
146
|
-
subscriptionPreview: SubscriptionPreview | null;
|
|
147
197
|
isFetchingSubscriptionPreview: boolean;
|
|
148
198
|
checkoutLocalization: CheckoutLocalization;
|
|
149
|
-
}) => {
|
|
150
|
-
|
|
151
|
-
if (!taxDetails || !tax) {
|
|
199
|
+
} & Pick<SubscriptionPreviewV2, 'tax' | 'taxDetails'>) => {
|
|
200
|
+
if (!taxDetails || !tax || tax?.amount <= 0) {
|
|
152
201
|
return null;
|
|
153
202
|
}
|
|
154
203
|
|
|
@@ -156,11 +205,11 @@ export const TaxLineItem = ({
|
|
|
156
205
|
<LineItemContainer>
|
|
157
206
|
<LineItemRow>
|
|
158
207
|
<Typography variant="body1" color="secondary">
|
|
159
|
-
{checkoutLocalization.taxTitle({ taxDetails })}
|
|
208
|
+
{checkoutLocalization.summary.taxTitle({ taxDetails })}
|
|
160
209
|
</Typography>
|
|
161
210
|
<Typography variant="body1" color="secondary">
|
|
162
211
|
<WithSkeleton isLoading={isFetchingSubscriptionPreview}>
|
|
163
|
-
{currencyPriceFormatter({ amount: tax?.amount, currency: tax?.currency })}
|
|
212
|
+
{currencyPriceFormatter({ amount: tax?.amount, currency: tax?.currency, minimumFractionDigits: 2 })}
|
|
164
213
|
</WithSkeleton>
|
|
165
214
|
</Typography>
|
|
166
215
|
</LineItemRow>
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BillingPeriod,
|
|
3
|
+
DiscountType,
|
|
4
|
+
Plan,
|
|
5
|
+
SubscriptionPreviewDiscount,
|
|
6
|
+
SubscriptionPreviewTaxDetails,
|
|
7
|
+
DiscountDurationType,
|
|
8
|
+
} from '@stigg/js-client-sdk';
|
|
2
9
|
import moment from 'moment';
|
|
3
10
|
import merge from 'lodash/merge';
|
|
4
11
|
import { DeepPartial } from '../../types';
|
|
12
|
+
import { currencyPriceFormatter } from '../utils/currencyUtils';
|
|
5
13
|
|
|
6
14
|
export type CheckoutLocalization = {
|
|
7
15
|
changePlan: string;
|
|
@@ -10,55 +18,127 @@ export type CheckoutLocalization = {
|
|
|
10
18
|
newPaymentMethodText: string;
|
|
11
19
|
newPaymentMethodCardTitle: string;
|
|
12
20
|
newPaymentMethodBillingAddressTitle: string;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
summary: {
|
|
22
|
+
title: string;
|
|
23
|
+
planName: (params: { plan: Plan }) => string;
|
|
24
|
+
addCouponCodeText: string;
|
|
25
|
+
couponCodeTitle: string;
|
|
26
|
+
addonsSectionTitle: string;
|
|
27
|
+
discountsSectionTitle: string;
|
|
28
|
+
onlyPayAsYouGoText: string;
|
|
29
|
+
startsAtText: string;
|
|
30
|
+
proratedTotalDueText: string;
|
|
31
|
+
baseChargeText: string | ((params: { billingPeriod: BillingPeriod }) => string);
|
|
32
|
+
totalText: string;
|
|
33
|
+
totalDueText: string;
|
|
34
|
+
totalBillingPeriodText: (params: { billingPeriod: BillingPeriod }) => string;
|
|
35
|
+
discountText: (params: { discountDetails: SubscriptionPreviewDiscount; currency: string }) => string;
|
|
36
|
+
appliedCreditsTitle: string;
|
|
37
|
+
taxTitle: (params: { taxDetails: SubscriptionPreviewTaxDetails }) => string;
|
|
38
|
+
checkoutSuccessText: string;
|
|
39
|
+
payAsYouGoTooltipText: string;
|
|
40
|
+
changesWillApplyAtEndOfBillingPeriod: string | ((params: { billingPeriodEnd: Date }) => string);
|
|
41
|
+
creditsForUnusedTimeText: (params: { credits: string }) => string;
|
|
42
|
+
};
|
|
20
43
|
checkoutButton: {
|
|
21
44
|
nextText: string;
|
|
45
|
+
noChangesText: string;
|
|
22
46
|
updateText: string;
|
|
23
47
|
downgradeToFreeText: string;
|
|
24
48
|
upgradeText: string;
|
|
25
49
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
downgradeToFree: {
|
|
51
|
+
alertText: (params: { plan: Plan }) => string;
|
|
52
|
+
freePlanHeader: (params: { plan: Plan }) => string;
|
|
53
|
+
freePlanName: (params: { plan: Plan }) => string;
|
|
54
|
+
freePlanPriceText: (params: { plan: Plan }) => string;
|
|
55
|
+
paidPlanHeader: (params: { plan: Plan }) => string;
|
|
56
|
+
paidPlanName: (params: { plan: Plan }) => string;
|
|
57
|
+
paidPlanPriceText: (params: { plan: Plan; billingPeriod?: BillingPeriod }) => string;
|
|
58
|
+
};
|
|
30
59
|
};
|
|
31
60
|
|
|
32
61
|
export function getResolvedCheckoutLocalize(
|
|
33
62
|
localizeOverride?: DeepPartial<CheckoutLocalization>,
|
|
34
63
|
): CheckoutLocalization {
|
|
35
64
|
const checkoutDefaultLocalization: CheckoutLocalization = {
|
|
36
|
-
changePlan: 'Change
|
|
65
|
+
changePlan: 'Change',
|
|
37
66
|
billingPeriodsTitle: 'Billing cycle',
|
|
38
67
|
addAddonText: 'Add',
|
|
39
68
|
newPaymentMethodText: 'New payment method',
|
|
40
69
|
newPaymentMethodBillingAddressTitle: 'Billing address',
|
|
41
70
|
newPaymentMethodCardTitle: 'Payment method',
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
summary: {
|
|
72
|
+
title: 'Order summary',
|
|
73
|
+
planName: ({ plan }) => `${plan.displayName} plan`,
|
|
74
|
+
addCouponCodeText: 'Add promotion code',
|
|
75
|
+
couponCodeTitle: 'Promotion code',
|
|
76
|
+
addonsSectionTitle: 'Add-ons',
|
|
77
|
+
discountsSectionTitle: 'Discounts',
|
|
78
|
+
onlyPayAsYouGoText: 'Varies by usage',
|
|
79
|
+
startsAtText: 'Starts at ',
|
|
80
|
+
proratedTotalDueText: 'Prorated charge today',
|
|
81
|
+
baseChargeText: () => 'Base charge',
|
|
82
|
+
totalText: 'Total',
|
|
83
|
+
totalDueText: 'Total due today',
|
|
84
|
+
totalBillingPeriodText: ({ billingPeriod }) => `Billed ${billingPeriod.toLowerCase()}`,
|
|
85
|
+
appliedCreditsTitle: 'Applied credits',
|
|
86
|
+
creditsForUnusedTimeText: ({ credits }) =>
|
|
87
|
+
`Your account will be granted credits worth ${credits} for unused time, which will be automatically applied to future payments.`,
|
|
88
|
+
discountText: ({ discountDetails, currency }) => {
|
|
89
|
+
let discountText = '';
|
|
90
|
+
if (discountDetails.type === DiscountType.Percentage) {
|
|
91
|
+
discountText = `${discountDetails.value}% off`;
|
|
92
|
+
} else {
|
|
93
|
+
discountText = `${currencyPriceFormatter({ amount: discountDetails.value, currency })}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let discountTextPostfix = '';
|
|
97
|
+
switch (discountDetails.durationType) {
|
|
98
|
+
case DiscountDurationType.Once: {
|
|
99
|
+
discountTextPostfix = ' once';
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case DiscountDurationType.Repeating: {
|
|
103
|
+
const prefix = discountDetails.type === DiscountType.Fixed ? ' per month' : '';
|
|
104
|
+
discountTextPostfix = `${prefix} for ${discountDetails.durationInMonths} months`;
|
|
105
|
+
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case DiscountDurationType.Forever:
|
|
110
|
+
default: {
|
|
111
|
+
discountTextPostfix = '';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return `${discountText}${discountTextPostfix}`;
|
|
116
|
+
},
|
|
117
|
+
taxTitle: ({ taxDetails }) => `Tax (${taxDetails?.percentage}%)`,
|
|
118
|
+
changesWillApplyAtEndOfBillingPeriod: ({ billingPeriodEnd }) =>
|
|
119
|
+
`Your changes will take effect at the end of your current billing cycle on ${moment(billingPeriodEnd).format(
|
|
120
|
+
'MMMM D, YYYY',
|
|
121
|
+
)}.`,
|
|
122
|
+
checkoutSuccessText: 'Changes applied',
|
|
123
|
+
payAsYouGoTooltipText: 'Billed according to actual usage',
|
|
124
|
+
},
|
|
52
125
|
checkoutButton: {
|
|
53
126
|
nextText: 'Next',
|
|
127
|
+
noChangesText: 'No changes',
|
|
54
128
|
updateText: 'Update subscription',
|
|
55
129
|
downgradeToFreeText: 'Cancel subscription',
|
|
56
130
|
upgradeText: 'Subscribe',
|
|
57
131
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
132
|
+
downgradeToFree: {
|
|
133
|
+
alertText: () => `We’re sorry to see you cancel your paid subscription 😭`,
|
|
134
|
+
freePlanHeader: () => 'New plan',
|
|
135
|
+
freePlanName: ({ plan }) => `${plan.displayName}`,
|
|
136
|
+
freePlanPriceText: () => 'Free',
|
|
137
|
+
paidPlanHeader: () => 'Current plan',
|
|
138
|
+
paidPlanName: ({ plan }) => `${plan.displayName}`,
|
|
139
|
+
paidPlanPriceText: ({ billingPeriod }) =>
|
|
140
|
+
`Paid plan${billingPeriod ? `, billed ${billingPeriod.toLowerCase()}` : ''}`,
|
|
141
|
+
},
|
|
62
142
|
};
|
|
63
143
|
|
|
64
144
|
return merge(checkoutDefaultLocalization, localizeOverride);
|
|
@@ -7,7 +7,6 @@ export type CheckoutTheme = {
|
|
|
7
7
|
textColor: string;
|
|
8
8
|
backgroundColor: string;
|
|
9
9
|
borderColor: string;
|
|
10
|
-
selectionColor: string;
|
|
11
10
|
summaryBackgroundColor: string;
|
|
12
11
|
};
|
|
13
12
|
|
|
@@ -16,7 +15,6 @@ const defaultCheckoutTheme: CheckoutTheme = {
|
|
|
16
15
|
textColor: 'rgb(0, 30, 108)',
|
|
17
16
|
backgroundColor: 'rgb(255, 255, 255)',
|
|
18
17
|
borderColor: 'rgb(235, 237, 243)',
|
|
19
|
-
selectionColor: 'rgb(229, 242, 255)',
|
|
20
18
|
summaryBackgroundColor: 'rgb(109, 121, 144)',
|
|
21
19
|
};
|
|
22
20
|
|
|
@@ -33,8 +31,6 @@ export function getResolvedCheckoutTheme(
|
|
|
33
31
|
backgroundColor:
|
|
34
32
|
themeOverride?.backgroundColor || globalPalette?.backgroundPaper || defaultCheckoutTheme.backgroundColor,
|
|
35
33
|
borderColor: themeOverride?.borderColor || globalPalette?.outlinedBorder || defaultCheckoutTheme.borderColor,
|
|
36
|
-
selectionColor:
|
|
37
|
-
themeOverride?.selectionColor || globalPalette?.backgroundSection || defaultCheckoutTheme.selectionColor,
|
|
38
34
|
summaryBackgroundColor:
|
|
39
35
|
themeOverride?.summaryBackgroundColor ||
|
|
40
36
|
globalPalette?.backgroundHighlight ||
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GetCheckoutState,
|
|
3
|
+
GetCheckoutStateResults,
|
|
4
|
+
PreviewSubscription,
|
|
5
|
+
SubscriptionBillingInfo,
|
|
6
|
+
SubscriptionPreviewV2,
|
|
7
|
+
} from '@stigg/js-client-sdk';
|
|
2
8
|
|
|
3
9
|
export type BillingInformation = {
|
|
4
10
|
taxDetails?: TaxDetailsInput;
|
|
@@ -7,3 +13,11 @@ export type BillingInformation = {
|
|
|
7
13
|
export type TaxDetailsInput = {
|
|
8
14
|
taxPercentage?: SubscriptionBillingInfo['taxPercentage'];
|
|
9
15
|
};
|
|
16
|
+
|
|
17
|
+
export type MockCheckoutPreviewCallback = (params: PreviewSubscription) => SubscriptionPreviewV2;
|
|
18
|
+
export type MockCheckoutStateCallback = (params: GetCheckoutState) => GetCheckoutStateResults;
|
|
19
|
+
|
|
20
|
+
export type CheckoutMockProps = {
|
|
21
|
+
onMockCheckoutPreview?: MockCheckoutPreviewCallback;
|
|
22
|
+
onMockCheckoutState?: MockCheckoutStateCallback;
|
|
23
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import styled from '@emotion/styled/macro';
|
|
3
|
-
import { CSSProperties } from 'react';
|
|
4
|
-
import { css,
|
|
2
|
+
import React, { CSSProperties } from 'react';
|
|
3
|
+
import { css, useTheme } from '@emotion/react';
|
|
5
4
|
import { getIconColor, IconColor } from './iconColor';
|
|
6
5
|
import * as customIcons from './customIcons';
|
|
7
6
|
|
|
@@ -45,7 +44,7 @@ export type IconProps = {
|
|
|
45
44
|
|
|
46
45
|
export function Icon({ icon, className, style, svgPathColor, svgRectColor, svgStrokeColor }: IconProps) {
|
|
47
46
|
const IconComponent = (customIcons as any)[icon];
|
|
48
|
-
const theme = useTheme()
|
|
47
|
+
const theme = useTheme();
|
|
49
48
|
|
|
50
49
|
return (
|
|
51
50
|
<IconWrapper
|
|
@@ -53,8 +52,7 @@ export function Icon({ icon, className, style, svgPathColor, svgRectColor, svgSt
|
|
|
53
52
|
style={style}
|
|
54
53
|
$pathColor={getIconColor(svgPathColor, theme)}
|
|
55
54
|
$rectColor={getIconColor(svgRectColor, theme)}
|
|
56
|
-
$strokeColor={getIconColor(svgStrokeColor, theme)}
|
|
57
|
-
>
|
|
55
|
+
$strokeColor={getIconColor(svgStrokeColor, theme)}>
|
|
58
56
|
<IconComponent />
|
|
59
57
|
</IconWrapper>
|
|
60
58
|
);
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { PriceTierFragment } from '@stigg/js-client-sdk';
|
|
2
2
|
import { MenuItem, OutlinedInput, Select, SelectChangeEvent } from '@mui/material';
|
|
3
|
-
import { Typography } from '../common/Typography';
|
|
4
3
|
import { map } from 'lodash';
|
|
5
4
|
import React, { ReactNode } from 'react';
|
|
6
5
|
import styled from '@emotion/styled/macro';
|
|
7
6
|
import { getTierByQuantity } from '../utils/priceTierUtils';
|
|
7
|
+
import { Typography } from './Typography';
|
|
8
8
|
|
|
9
9
|
const TierSelect = styled(Select)`
|
|
10
10
|
border-radius: 10px;
|
|
11
|
+
min-height: 42px;
|
|
12
|
+
min-width: 120px;
|
|
11
13
|
|
|
12
14
|
&:hover .MuiOutlinedInput-notchedOutline {
|
|
13
15
|
border-color: ${({ theme }) => theme.stigg.palette.outlinedBorder};
|
|
@@ -16,7 +18,7 @@ const TierSelect = styled(Select)`
|
|
|
16
18
|
|
|
17
19
|
const TierInput = styled(OutlinedInput)`
|
|
18
20
|
& .MuiInputBase-input {
|
|
19
|
-
padding:
|
|
21
|
+
padding: 10px 12px;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
&.Mui-focused .MuiOutlinedInput-notchedOutline {
|
|
@@ -27,13 +29,11 @@ const TierInput = styled(OutlinedInput)`
|
|
|
27
29
|
export function TiersSelectContainer({
|
|
28
30
|
componentId,
|
|
29
31
|
tiers,
|
|
30
|
-
tierUnits,
|
|
31
32
|
selectedTier,
|
|
32
33
|
handleTierChange,
|
|
33
34
|
}: {
|
|
34
35
|
componentId: string;
|
|
35
36
|
tiers?: PriceTierFragment[] | null;
|
|
36
|
-
tierUnits?: string;
|
|
37
37
|
selectedTier?: PriceTierFragment;
|
|
38
38
|
handleTierChange: (tier: PriceTierFragment) => void;
|
|
39
39
|
}) {
|
|
@@ -57,12 +57,11 @@ export function TiersSelectContainer({
|
|
|
57
57
|
PaperProps: {
|
|
58
58
|
sx: { marginTop: '4px', borderRadius: '10px' },
|
|
59
59
|
},
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
60
|
+
}}>
|
|
62
61
|
{map(tiers, (tier: PriceTierFragment) => (
|
|
63
62
|
<MenuItem className="stigg-price-tier-menu-item-text" key={tier.upTo} value={tier.upTo.toString()}>
|
|
64
|
-
<Typography variant="body1" color="primary">
|
|
65
|
-
{tier.upTo}
|
|
63
|
+
<Typography variant="body1" color="primary" style={{ lineHeight: 'unset' }}>
|
|
64
|
+
{tier.upTo}
|
|
66
65
|
</Typography>
|
|
67
66
|
</MenuItem>
|
|
68
67
|
))}
|
|
@@ -4,7 +4,15 @@ import { FontWeight as StyledFontWeight, Text, TypeProps } from 'styled-typograp
|
|
|
4
4
|
import { Theme, useTheme } from '@emotion/react';
|
|
5
5
|
import { FontWeight } from '../../theme/types';
|
|
6
6
|
|
|
7
|
-
type Colors =
|
|
7
|
+
type Colors =
|
|
8
|
+
| 'primary'
|
|
9
|
+
| 'primary.main'
|
|
10
|
+
| 'primary.main.light'
|
|
11
|
+
| 'secondary'
|
|
12
|
+
| 'disabled'
|
|
13
|
+
| 'white'
|
|
14
|
+
| 'warning'
|
|
15
|
+
| 'error';
|
|
8
16
|
|
|
9
17
|
export type TypographyProps = {
|
|
10
18
|
children: React.ReactNode;
|
|
@@ -25,6 +33,8 @@ function getColor(theme: Theme, $color: Colors) {
|
|
|
25
33
|
return 'white';
|
|
26
34
|
case 'primary.main':
|
|
27
35
|
return theme.stigg.palette.primary;
|
|
36
|
+
case 'primary.main.light':
|
|
37
|
+
return theme.stigg.palette.primaryLight;
|
|
28
38
|
case 'warning':
|
|
29
39
|
return theme.stigg.palette.warning;
|
|
30
40
|
case 'error':
|
|
@@ -111,8 +121,7 @@ export const Typography = forwardRef((props: TypographyProps, ref) => {
|
|
|
111
121
|
level={level}
|
|
112
122
|
color={overrideColor || getColor(theme, color)}
|
|
113
123
|
fontWeight={fontWeight ?? (bold ? StyledFontWeight.Bold : getFontWeight(theme, variant))}
|
|
114
|
-
$span={span}
|
|
115
|
-
>
|
|
124
|
+
$span={span}>
|
|
116
125
|
{children}
|
|
117
126
|
</StyledText>
|
|
118
127
|
);
|
|
@@ -17,3 +17,5 @@ export { default as OutlinedCheckedCircleDisabled } from '../../assets/outlined-
|
|
|
17
17
|
export { default as ArrowForward } from '../../assets/arrow-forward.svg';
|
|
18
18
|
export { default as Close } from '../../assets/close.svg';
|
|
19
19
|
export { default as Check } from '../../assets/check.svg';
|
|
20
|
+
export { default as PayAsYouGoCharge } from '../../assets/pay-as-you-go-charge.svg';
|
|
21
|
+
export { default as Coupon } from '../../assets/coupon.svg';
|
|
@@ -123,8 +123,7 @@ export function mapCheckoutConfiguration(configuration: CheckoutConfiguration):
|
|
|
123
123
|
text: {
|
|
124
124
|
primary: palette?.textColor || undefined,
|
|
125
125
|
},
|
|
126
|
-
backgroundHighlight: palette?.
|
|
127
|
-
backgroundSection: palette?.summaryBackgroundColor || undefined,
|
|
126
|
+
backgroundHighlight: palette?.summaryBackgroundColor || undefined,
|
|
128
127
|
},
|
|
129
128
|
typography: mapTypography(typography),
|
|
130
129
|
};
|
|
@@ -13,14 +13,15 @@ export const CustomerPortalPaywallLayout = styled(SectionContainer)<{
|
|
|
13
13
|
.stigg-paywall-layout {
|
|
14
14
|
width: 100%;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
.stigg-paywall-plans-layout {
|
|
18
18
|
flex-wrap: nowrap;
|
|
19
19
|
width: 100%;
|
|
20
20
|
overflow-x: auto;
|
|
21
21
|
justify-content: unset;
|
|
22
|
-
padding:
|
|
22
|
+
padding: 10px 0px 0px 0px;
|
|
23
23
|
}
|
|
24
|
+
|
|
24
25
|
.stigg-paywall-plans-layout .stigg-plan-offering-container:first-of-type {
|
|
25
26
|
margin-left: auto;
|
|
26
27
|
}
|
|
@@ -37,6 +38,6 @@ export const CustomerPortalPaywallLayout = styled(SectionContainer)<{
|
|
|
37
38
|
`}
|
|
38
39
|
|
|
39
40
|
.${STIGG_WATERMARK_CLASSNAME} {
|
|
40
|
-
display: none
|
|
41
|
+
display: none;
|
|
41
42
|
}
|
|
42
43
|
`;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { BillingPeriod, Customer, PriceTierFragment, PricingType, Subscription } from '@stigg/js-client-sdk';
|
|
3
|
+
import { isFunction } from 'lodash';
|
|
4
|
+
import ClipLoader from 'react-spinners/ClipLoader';
|
|
3
5
|
import styled from '@emotion/styled/macro';
|
|
4
|
-
import { css,
|
|
6
|
+
import { css, useTheme } from '@emotion/react';
|
|
5
7
|
import { PaywallPlan, SubscribeIntentionType } from './types';
|
|
6
8
|
import { PaywallLocalization } from './paywallTextOverrides';
|
|
7
9
|
import { flexLayoutMapper } from '../../theme/getResolvedTheme';
|
|
8
|
-
import ClipLoader from 'react-spinners/ClipLoader';
|
|
9
10
|
import { Typography } from '../common/Typography';
|
|
10
11
|
import { getSubscriptionScheduleUpdateTexts } from '../utils/getSubscriptionScheduleUpdateTexts';
|
|
11
|
-
import { isFunction } from 'lodash';
|
|
12
12
|
import { compareSelectedTierToCurrentTier, PriceTierComparison } from '../utils/priceTierUtils';
|
|
13
13
|
|
|
14
14
|
const LoadingIndicator = styled(ClipLoader)`
|
|
@@ -99,7 +99,7 @@ export function PlanOfferingButton({
|
|
|
99
99
|
currentSubscription,
|
|
100
100
|
selectedTierByFeature,
|
|
101
101
|
}: PlanOfferingButtonProps) {
|
|
102
|
-
const theme = useTheme()
|
|
102
|
+
const theme = useTheme();
|
|
103
103
|
const [isLoading, setIsLoading] = useState(false);
|
|
104
104
|
const {
|
|
105
105
|
currentPlan,
|
|
@@ -187,8 +187,7 @@ export function PlanOfferingButton({
|
|
|
187
187
|
onClick={() => {
|
|
188
188
|
setIsLoading(true);
|
|
189
189
|
Promise.resolve(onPlanSelected(buttonProps.intentionType)).finally(() => setIsLoading(false));
|
|
190
|
-
}}
|
|
191
|
-
>
|
|
190
|
+
}}>
|
|
192
191
|
{buttonProps.title}
|
|
193
192
|
</CancelScheduledUpdateButton>
|
|
194
193
|
</ScheduledUpdateText>
|
|
@@ -202,8 +201,7 @@ export function PlanOfferingButton({
|
|
|
202
201
|
onClick={() => {
|
|
203
202
|
setIsLoading(true);
|
|
204
203
|
Promise.resolve(onPlanSelected(buttonProps.intentionType)).finally(() => setIsLoading(false));
|
|
205
|
-
}}
|
|
206
|
-
>
|
|
204
|
+
}}>
|
|
207
205
|
<ButtonText className="stigg-paywall-plan-button-text" variant="h6" color="primary.main">
|
|
208
206
|
{buttonProps.title}
|
|
209
207
|
</ButtonText>
|