@stigg/react-sdk 4.4.0-beta.1 → 4.4.0-beta.11

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.
Files changed (94) hide show
  1. package/dist/components/checkout/Checkout.d.ts +1 -1
  2. package/dist/components/checkout/CheckoutContainer.d.ts +7 -2
  3. package/dist/components/checkout/CheckoutProvider.d.ts +3 -1
  4. package/dist/components/checkout/components/Button.d.ts +0 -1
  5. package/dist/components/checkout/components/ChangePlanButton.d.ts +8 -0
  6. package/dist/components/checkout/components/DowngradeToFreeContainer.d.ts +28 -0
  7. package/dist/components/checkout/components/StyledArrow.d.ts +5 -0
  8. package/dist/components/checkout/hooks/useCheckoutModel.d.ts +2 -0
  9. package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +8 -2
  10. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +8 -1
  11. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +3 -0
  12. package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +2 -1
  13. package/dist/components/checkout/index.d.ts +2 -0
  14. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +3 -2
  15. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +3 -2
  16. package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -1
  17. package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -1
  18. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +4 -0
  19. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +4 -3
  20. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +1 -0
  21. package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +6 -1
  22. package/dist/components/checkout/summary/CheckoutSuccess.d.ts +4 -1
  23. package/dist/components/checkout/summary/CheckoutSummary.d.ts +3 -1
  24. package/dist/components/checkout/summary/components/CheckoutCaptions.d.ts +2 -1
  25. package/dist/components/checkout/summary/components/LineItems.d.ts +8 -8
  26. package/dist/components/checkout/textOverrides.d.ts +28 -3
  27. package/dist/components/checkout/theme.d.ts +0 -1
  28. package/dist/components/checkout/types.d.ts +7 -0
  29. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.style.d.ts +1 -1
  30. package/dist/components/paywall/paywallTextOverrides.d.ts +4 -0
  31. package/dist/components/utils/getPaidPriceText.d.ts +3 -1
  32. package/dist/react-sdk.cjs.development.js +1234 -599
  33. package/dist/react-sdk.cjs.development.js.map +1 -1
  34. package/dist/react-sdk.cjs.production.min.js +1 -1
  35. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  36. package/dist/react-sdk.esm.js +1273 -622
  37. package/dist/react-sdk.esm.js.map +1 -1
  38. package/dist/theme/getResolvedTheme.d.ts +1 -0
  39. package/dist/theme/types.d.ts +1 -0
  40. package/package.json +2 -2
  41. package/src/assets/payment-method.svg +3 -10
  42. package/src/components/checkout/Checkout.tsx +2 -1
  43. package/src/components/checkout/CheckoutContainer.style.ts +1 -0
  44. package/src/components/checkout/CheckoutContainer.tsx +59 -28
  45. package/src/components/checkout/CheckoutProvider.tsx +18 -18
  46. package/src/components/checkout/components/Button.tsx +19 -35
  47. package/src/components/checkout/components/ChangePlanButton.tsx +32 -0
  48. package/src/components/checkout/components/DowngradeToFreeContainer.tsx +115 -0
  49. package/src/components/checkout/components/Skeletons.style.ts +4 -1
  50. package/src/components/checkout/components/StyledArrow.tsx +9 -0
  51. package/src/components/checkout/hooks/useCheckoutModel.ts +12 -2
  52. package/src/components/checkout/hooks/usePaymentStepModel.ts +22 -3
  53. package/src/components/checkout/hooks/usePlanStepModel.ts +25 -10
  54. package/src/components/checkout/hooks/usePreviewSubscription.ts +112 -40
  55. package/src/components/checkout/hooks/useProgressBarModel.ts +18 -0
  56. package/src/components/checkout/hooks/useSubscriptionModel.ts +8 -2
  57. package/src/components/checkout/hooks/useSubscriptionState.ts +2 -1
  58. package/src/components/checkout/index.ts +2 -0
  59. package/src/components/checkout/planHeader/PlanHeader.tsx +19 -34
  60. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +6 -3
  61. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +13 -9
  62. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +8 -8
  63. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +58 -11
  64. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +1 -0
  65. package/src/components/checkout/steps/payment/PaymentMethods.tsx +13 -6
  66. package/src/components/checkout/steps/payment/PaymentStep.tsx +3 -1
  67. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +35 -4
  68. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +4 -3
  69. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +61 -48
  70. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +27 -6
  71. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +26 -5
  72. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +62 -12
  73. package/src/components/checkout/summary/CheckoutSuccess.tsx +52 -6
  74. package/src/components/checkout/summary/CheckoutSummary.tsx +74 -48
  75. package/src/components/checkout/summary/components/CheckoutCaptions.tsx +30 -29
  76. package/src/components/checkout/summary/components/LineItems.tsx +18 -33
  77. package/src/components/checkout/textOverrides.ts +33 -13
  78. package/src/components/checkout/theme.ts +0 -4
  79. package/src/components/checkout/types.ts +9 -0
  80. package/src/components/common/Icon.tsx +4 -6
  81. package/src/components/common/mapExternalTheme.ts +1 -2
  82. package/src/components/paywall/PlanPrice.tsx +10 -2
  83. package/src/components/paywall/paywallTextOverrides.ts +3 -0
  84. package/src/components/utils/getPaidPriceText.ts +8 -2
  85. package/src/components/utils/getPlanPrice.ts +1 -1
  86. package/src/stories/Checkout.stories.tsx +6 -5
  87. package/src/theme/Theme.tsx +10 -1
  88. package/src/theme/getResolvedTheme.ts +1 -0
  89. package/src/theme/types.ts +1 -0
  90. package/dist/components/checkout/planHeader/PlanHeader.style.d.ts +0 -25
  91. package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +0 -2
  92. package/src/assets/nyancat.svg +0 -634
  93. package/src/components/checkout/planHeader/PlanHeader.style.tsx +0 -23
  94. package/src/components/checkout/steps/surprise/SurpriseStep.tsx +0 -27
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import partition from 'lodash/partition';
3
3
  import styled from '@emotion/styled/macro';
4
4
  import { Box, CircularProgress, Divider, Grid, Paper } from '@mui/material';
5
- import { BillingModel, SubscriptionPreview } from '@stigg/js-client-sdk';
5
+ import { BillingModel } from '@stigg/js-client-sdk';
6
6
  import { PoweredByStigg } from '../../common/PoweredByStigg';
7
7
  import { Typography } from '../../common/Typography';
8
8
  import { useChargesSort } from '../../hooks/useChargeSort';
@@ -44,6 +44,7 @@ SummaryCard.defaultProps = {
44
44
 
45
45
  const PlanName = styled(Typography)`
46
46
  margin-bottom: 16px;
47
+ font-weight: 500;
47
48
  `;
48
49
 
49
50
  const StyledDivider = styled(Divider)`
@@ -60,31 +61,37 @@ const TotalDueText = styled(Typography)`
60
61
 
61
62
  function resolveCheckoutButtonText({
62
63
  isLastStep,
63
- subscriptionPreview,
64
+ isFreeDowngrade,
64
65
  checkoutLocalization,
65
- isFirstSubscription,
66
+ isPlanUpdate,
66
67
  }: {
67
68
  isLastStep?: boolean;
68
- isFirstSubscription?: boolean;
69
- subscriptionPreview?: SubscriptionPreview | null;
69
+ isFreeDowngrade: boolean;
70
70
  checkoutLocalization: CheckoutLocalization;
71
+ isPlanUpdate?: boolean;
71
72
  }) {
72
73
  if (!isLastStep) {
73
74
  return checkoutLocalization.checkoutButton.nextText;
74
75
  }
75
76
 
76
- if (subscriptionPreview?.isPlanDowngrade) {
77
- return checkoutLocalization.checkoutButton.downgradeText;
77
+ if (isPlanUpdate) {
78
+ return checkoutLocalization.checkoutButton.updateText;
78
79
  }
79
80
 
80
- if (!isFirstSubscription) {
81
- return checkoutLocalization.checkoutButton.upgradeText;
81
+ if (isFreeDowngrade) {
82
+ return checkoutLocalization.checkoutButton.downgradeToFreeText;
82
83
  }
83
84
 
84
- return checkoutLocalization.checkoutButton.purchaseText;
85
+ return checkoutLocalization.checkoutButton.upgradeText;
85
86
  }
86
87
 
87
- export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutContainerProps) => {
88
+ export const CheckoutSummary = ({
89
+ onCheckout,
90
+ onCheckoutCompleted,
91
+ disablePromotionCode,
92
+ disableSuccessAnimation,
93
+ isFreeDowngrade,
94
+ }: CheckoutContainerProps & { isFreeDowngrade: boolean }) => {
88
95
  const [isCheckoutCompletedSuccessfully, setIsCheckoutCompletedSuccessfully] = useState(false);
89
96
  const { setErrorMessage } = usePaymentStepModel();
90
97
  const progressBar = useProgressBarModel();
@@ -96,12 +103,12 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
96
103
  );
97
104
  const [baseCharges, usageCharges] = partition(planPrices, (price) => price.pricingModel === BillingModel.FlatFee);
98
105
  const [baseCharge] = baseCharges || [];
99
- const isFirstSubscription = !activeSubscription?.id;
100
- const isLastStep = progressBar.isCheckoutComplete && progressBar.isLastStep;
106
+ const isLastStep = isFreeDowngrade || (progressBar.isCheckoutComplete && progressBar.isLastStep);
101
107
 
102
108
  const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription();
103
109
 
104
110
  const { handleSubmit, isLoading } = useSubmit({
111
+ disableSuccessAnimation,
105
112
  onCheckout,
106
113
  onCheckoutCompleted,
107
114
  onSuccess: () => {
@@ -119,11 +126,9 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
119
126
  if (errorMessage) {
120
127
  setErrorMessage(errorMessage);
121
128
  setIsCheckoutCompletedSuccessfully(false);
122
- return;
129
+ } else {
130
+ setErrorMessage(undefined);
123
131
  }
124
-
125
- setErrorMessage(undefined);
126
- setIsCheckoutCompletedSuccessfully(true);
127
132
  };
128
133
 
129
134
  const onCheckoutClick = async (e: any): Promise<void> => {
@@ -138,6 +143,14 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
138
143
  }
139
144
  };
140
145
 
146
+ const showPromotionCodeLine = !disablePromotionCode && !isFreeDowngrade;
147
+ const showDiscountLine = !!subscriptionPreview?.subTotal && !!subscriptionPreview?.discount && !isFreeDowngrade;
148
+ const showTaxLine =
149
+ !!subscriptionPreview?.taxDetails && !!subscriptionPreview?.tax && subscriptionPreview?.tax.amount > 0;
150
+ const showAppliedCreditsLine = !!subscriptionPreview?.credits && subscriptionPreview?.credits.used.amount > 0;
151
+
152
+ const showAdditionalDivider = showPromotionCodeLine || showDiscountLine || showTaxLine || showAppliedCreditsLine;
153
+
141
154
  return (
142
155
  <Box flex={1}>
143
156
  <SummaryCard>
@@ -146,7 +159,7 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
146
159
  {baseCharge && (
147
160
  <LineItemContainer>
148
161
  <LineItemRow>
149
- <Typography variant="h6" color="primary">
162
+ <Typography variant="body1" color="secondary">
150
163
  {typeof checkoutLocalization.baseChargeText === 'function'
151
164
  ? checkoutLocalization.baseChargeText({ billingPeriod: subscription.billingPeriod })
152
165
  : checkoutLocalization.baseChargeText}
@@ -188,11 +201,13 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
188
201
 
189
202
  if (!addonPrice) return null;
190
203
 
204
+ const addonQuantity = addon.quantity && addon.quantity > 0 ? addon.quantity : 1;
205
+
191
206
  return (
192
207
  <BilledPriceLineItem
193
208
  key={addon?.addon?.id}
194
209
  label={addon.addon.displayName}
195
- quantity={addon.quantity}
210
+ quantity={addonQuantity}
196
211
  price={addonPrice}
197
212
  />
198
213
  );
@@ -211,30 +226,32 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
211
226
 
212
227
  <StyledDivider className="stigg-checkout-summary-divider" />
213
228
 
214
- {isFirstSubscription && (
215
- <>
216
- <PromotionCodeSection checkoutLocalization={checkoutLocalization} />
229
+ {showPromotionCodeLine && <PromotionCodeSection checkoutLocalization={checkoutLocalization} />}
217
230
 
218
- <StyledDivider className="stigg-checkout-summary-divider" />
219
- </>
231
+ {showDiscountLine && (
232
+ <DiscountLineItem
233
+ subscriptionPreview={subscriptionPreview!}
234
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
235
+ />
220
236
  )}
221
237
 
222
- <AppliedCreditsLineItem
223
- subscriptionPreview={subscriptionPreview}
224
- isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
225
- checkoutLocalization={checkoutLocalization}
226
- />
238
+ {showTaxLine && (
239
+ <TaxLineItem
240
+ subscriptionPreview={subscriptionPreview!}
241
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
242
+ checkoutLocalization={checkoutLocalization}
243
+ />
244
+ )}
227
245
 
228
- <DiscountLineItem
229
- subscriptionPreview={subscriptionPreview}
230
- isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
231
- />
246
+ {showAppliedCreditsLine && (
247
+ <AppliedCreditsLineItem
248
+ subscriptionPreview={subscriptionPreview!}
249
+ isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
250
+ checkoutLocalization={checkoutLocalization}
251
+ />
252
+ )}
232
253
 
233
- <TaxLineItem
234
- subscriptionPreview={subscriptionPreview}
235
- isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
236
- checkoutLocalization={checkoutLocalization}
237
- />
254
+ {showAdditionalDivider && <StyledDivider className="stigg-checkout-summary-divider" />}
238
255
 
239
256
  <LineItemContainer>
240
257
  <LineItemRow>
@@ -253,15 +270,15 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
253
270
  subscriptionPreview={subscriptionPreview}
254
271
  isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
255
272
  checkoutLocalization={checkoutLocalization}
273
+ billingPeriod={subscription.billingPeriod}
256
274
  />
257
275
 
258
276
  <Button
259
- disableRipple={isLoading}
260
- $isLoading={isLoading}
261
277
  $success={isCheckoutCompletedSuccessfully}
262
- $error={isLastStep && subscriptionPreview?.isPlanDowngrade}
278
+ $error={isLastStep && isFreeDowngrade}
279
+ disabled={isLoading || isFetchingSubscriptionPreview || progressBar.progressBarState.isDisabled}
263
280
  className="stigg-checkout-summary-cta-button"
264
- sx={{ textTransform: 'none', borderRadius: '10px', marginTop: '24px' }}
281
+ sx={{ textTransform: 'none', borderRadius: '10px', marginTop: '24px', height: '36px' }}
265
282
  variant="contained"
266
283
  size="medium"
267
284
  onClick={(e: any) => {
@@ -269,11 +286,18 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
269
286
  }}
270
287
  fullWidth>
271
288
  <Typography className="stigg-checkout-summary-cta-button-text" color="white" style={{ display: 'flex' }}>
272
- {isCheckoutCompletedSuccessfully && <Icon icon="Check" style={{ display: 'contents' }} />}
273
- {isLoading && <CircularProgress size={20} sx={{ color: 'white' }} />}
274
- {!isLoading &&
275
- !isCheckoutCompletedSuccessfully &&
276
- resolveCheckoutButtonText({ isLastStep, subscriptionPreview, checkoutLocalization })}
289
+ {isCheckoutCompletedSuccessfully ? (
290
+ <Icon icon="Check" style={{ display: 'contents' }} />
291
+ ) : isLoading || isFetchingSubscriptionPreview ? (
292
+ <CircularProgress size={20} sx={{ color: 'white' }} />
293
+ ) : (
294
+ resolveCheckoutButtonText({
295
+ isLastStep,
296
+ isFreeDowngrade,
297
+ checkoutLocalization,
298
+ isPlanUpdate: !!activeSubscription && activeSubscription?.plan.id === plan?.id,
299
+ })
300
+ )}
277
301
  </Typography>
278
302
  </Button>
279
303
  </SummaryCard>
@@ -282,7 +306,9 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
282
306
  showWatermark
283
307
  style={{ marginTop: 8, display: 'flex', justifyContent: 'center' }}
284
308
  />
285
- {isCheckoutCompletedSuccessfully && <CheckoutSuccess />}
309
+ {!disableSuccessAnimation && isCheckoutCompletedSuccessfully && (
310
+ <CheckoutSuccess checkoutLocalization={checkoutLocalization} />
311
+ )}
286
312
  </Box>
287
313
  );
288
314
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import moment from 'moment';
3
- import { Plan, Subscription, SubscriptionPreview } from '@stigg/js-client-sdk';
3
+ import { BillingModel, BillingPeriod, Plan, Subscription, SubscriptionPreview } from '@stigg/js-client-sdk';
4
4
  import { Typography } from '../../../common/Typography';
5
5
  import { currencyPriceFormatter } from '../../../utils/currencyUtils';
6
6
  import { CheckoutLocalization } from '../../textOverrides';
@@ -12,6 +12,7 @@ export type CheckoutCaptionProps = {
12
12
  activeSubscription?: Subscription | null;
13
13
  plan?: Plan;
14
14
  checkoutLocalization: CheckoutLocalization;
15
+ billingPeriod: BillingPeriod;
15
16
  };
16
17
 
17
18
  // TODO: move to localization
@@ -21,12 +22,17 @@ const RemainingCreditsCaption = ({ subscriptionPreview, isFetchingSubscriptionPr
21
22
  return null;
22
23
  }
23
24
 
24
- const credits = currencyPriceFormatter(subscriptionPreview?.proration?.netAmount);
25
+ const positiveAmount = subscriptionPreview.proration.netAmount.amount * -1;
26
+
27
+ const credits = currencyPriceFormatter({
28
+ amount: positiveAmount,
29
+ currency: subscriptionPreview.proration.netAmount.currency,
30
+ });
25
31
 
26
32
  return (
27
33
  <Typography variant="caption" style={{ marginTop: 14 }}>
28
34
  <WithSkeleton isLoading={isFetchingSubscriptionPreview} width="100%">
29
- {`Your remaining credits, which are ${credits}, will be kept for you for future use.`}
35
+ {`Your account will be granted credits worth ${credits} for unused time, which will be automatically applied to future payments.`}
30
36
  </WithSkeleton>
31
37
  </Typography>
32
38
  );
@@ -57,49 +63,46 @@ const ScheduledUpdatesCaption = ({
57
63
  );
58
64
  };
59
65
 
60
- const ChargeDueTodayCaption = ({ subscriptionPreview, plan, isFetchingSubscriptionPreview }: CheckoutCaptionProps) => {
61
- if (!subscriptionPreview?.total) {
62
- return null;
63
- }
64
-
65
- const total = currencyPriceFormatter(subscriptionPreview?.total);
66
- const usedCredits = !!subscriptionPreview.credits?.used;
67
-
68
- return (
69
- <Typography variant="caption" style={{ marginTop: 14 }}>
70
- <WithSkeleton isLoading={isFetchingSubscriptionPreview} width="100%">
71
- {`Today we’ll charge you ${total} (incl. taxes) for your new ${plan?.displayName} plan${
72
- usedCredits ? ' minus credits left from your existing plan.' : ''
73
- } `}
74
- </WithSkeleton>
75
- </Typography>
76
- );
77
- };
78
-
79
66
  const NextBillingCaption = ({
80
67
  subscriptionPreview,
81
68
  activeSubscription,
82
69
  plan,
83
70
  isFetchingSubscriptionPreview,
71
+ billingPeriod,
84
72
  }: CheckoutCaptionProps) => {
85
73
  if (!subscriptionPreview?.subscription?.total) {
86
74
  return null;
87
75
  }
88
76
 
89
- const isUpdatingSubscription = activeSubscription?.plan?.id && plan?.id && activeSubscription.plan.id === plan.id;
90
- const isScheduledPlanDowngrade = subscriptionPreview.isPlanDowngrade && subscriptionPreview.hasScheduledUpdates;
91
77
  const currentBillingPeriodEnd = subscriptionPreview.hasScheduledUpdates
92
78
  ? activeSubscription?.currentBillingPeriodEnd
93
79
  : subscriptionPreview?.billingPeriodRange.end;
94
80
  const billingDate = moment(currentBillingPeriodEnd).format('MMM D, YYYY');
95
81
  const total = currencyPriceFormatter(subscriptionPreview?.subscription.total);
96
82
 
83
+ const hasUnitBasedPricing = plan?.pricePoints.some((price) => price.pricingModel === BillingModel.UsageBased);
84
+ const hasNonUnitBasedPricing = plan?.pricePoints.some((price) => price.pricingModel !== BillingModel.UsageBased);
85
+
86
+ let text = 'We will bill you ';
87
+ let totalAmountText = `${total} `;
88
+
89
+ if (hasUnitBasedPricing) {
90
+ if (!hasNonUnitBasedPricing) {
91
+ totalAmountText = 'for';
92
+ } else {
93
+ totalAmountText += '+';
94
+ }
95
+
96
+ totalAmountText += ' applicable usage-based fees for this subscription ';
97
+ }
98
+
99
+ const billingPeriodText = billingPeriod === BillingPeriod.Monthly ? 'month' : 'year';
100
+ text += `${totalAmountText}for this subscription every ${billingPeriodText} on ${billingDate}, unless you cancel.`;
101
+
97
102
  return (
98
103
  <Typography variant="caption" style={{ marginTop: 14 }}>
99
104
  <WithSkeleton isLoading={isFetchingSubscriptionPreview} width="100%">
100
- {`Your${isUpdatingSubscription ? '' : ' new'} ${plan?.displayName} plan will ${
101
- isScheduledPlanDowngrade ? 'start' : 'renew'
102
- } on ${billingDate} for ${total} (incl. taxes) unless you cancel it.`}
105
+ {text}
103
106
  </WithSkeleton>
104
107
  </Typography>
105
108
  );
@@ -112,8 +115,6 @@ export function CheckoutCaptions(props: CheckoutCaptionProps) {
112
115
 
113
116
  <ScheduledUpdatesCaption {...props} />
114
117
 
115
- <ChargeDueTodayCaption {...props} />
116
-
117
118
  <NextBillingCaption {...props} />
118
119
  </>
119
120
  );
@@ -21,24 +21,16 @@ export const LineItemRow = styled.div`
21
21
  justify-content: space-between;
22
22
  `;
23
23
 
24
- export const getPriceString = ({
25
- amountPerMonth,
26
- price,
27
- quantity,
28
- }: {
29
- amountPerMonth: number;
30
- price: Price;
31
- quantity: number;
32
- }) => {
24
+ export const getPriceString = ({ amount, price, quantity }: { amount: number; price: Price; quantity: number }) => {
33
25
  const { billingPeriod } = price;
34
26
  let billingPeriodString = null;
35
27
 
36
28
  if (billingPeriod === BillingPeriod.Annually) {
37
- amountPerMonth /= 12;
29
+ amount /= 12;
38
30
  billingPeriodString = '12 months';
39
31
  }
40
32
 
41
- const addonPriceFormat = currencyPriceFormatter({ amount: amountPerMonth, currency: price.currency });
33
+ const addonPriceFormat = currencyPriceFormatter({ amount, currency: price.currency });
42
34
 
43
35
  return `${quantity > 1 ? `${quantity} x ${addonPriceFormat} each` : addonPriceFormat}${
44
36
  billingPeriodString ? ` x ${billingPeriodString}` : ''
@@ -48,30 +40,30 @@ export const getPriceString = ({
48
40
  export const BilledPriceLineItem = ({ label, quantity, price }: { label: string; quantity: number; price: Price }) => {
49
41
  const { billingPeriod } = price;
50
42
 
51
- let amountPerMonth;
43
+ let amount;
52
44
  if (price.isTieredPrice) {
53
45
  const tier = getTierByQuantity(price.tiers!, quantity);
54
- amountPerMonth = tier!.unitPrice.amount!;
46
+ amount = tier!.unitPrice.amount!;
55
47
  } else {
56
- amountPerMonth = price.amount!;
48
+ amount = price.amount!;
57
49
  }
58
50
 
59
51
  return (
60
52
  <LineItemContainer>
61
53
  <LineItemRow style={{ alignItems: 'flex-end' }}>
62
54
  <Grid item>
63
- <Typography variant="h6" color="primary">
55
+ <Typography variant="body1" color="secondary">
64
56
  {label}
65
57
  </Typography>
66
58
  {(quantity > 1 || billingPeriod === BillingPeriod.Annually) && (
67
59
  <Typography variant="body1" color="secondary">
68
- {getPriceString({ amountPerMonth, price, quantity })}
60
+ {getPriceString({ amount, price, quantity })}
69
61
  </Typography>
70
62
  )}
71
63
  </Grid>
72
64
  <Grid item>
73
65
  <Typography variant="body1" color="secondary" style={{ wordBreak: 'break-word' }}>
74
- {currencyPriceFormatter({ amount: quantity * amountPerMonth, currency: price.currency })}
66
+ {currencyPriceFormatter({ amount: quantity * amount, currency: price.currency })}
75
67
  </Typography>
76
68
  </Grid>
77
69
  </LineItemRow>
@@ -83,13 +75,11 @@ export const DiscountLineItem = ({
83
75
  subscriptionPreview,
84
76
  isFetchingSubscriptionPreview,
85
77
  }: {
86
- subscriptionPreview: SubscriptionPreview | null;
78
+ subscriptionPreview: SubscriptionPreview;
87
79
  isFetchingSubscriptionPreview: boolean;
88
80
  }) => {
89
- const { subTotal, discount } = subscriptionPreview || {};
90
- if (!subTotal || !discount) {
91
- return null;
92
- }
81
+ const { subTotal } = subscriptionPreview;
82
+ const discount = subscriptionPreview.discount!;
93
83
 
94
84
  let discountAmount: number;
95
85
  if (discount.type === DiscountType.Percentage) {
@@ -121,14 +111,11 @@ export const AppliedCreditsLineItem = ({
121
111
  isFetchingSubscriptionPreview,
122
112
  checkoutLocalization,
123
113
  }: {
124
- subscriptionPreview: SubscriptionPreview | null;
114
+ subscriptionPreview: SubscriptionPreview;
125
115
  isFetchingSubscriptionPreview: boolean;
126
116
  checkoutLocalization: CheckoutLocalization;
127
117
  }) => {
128
- const { credits } = subscriptionPreview || {};
129
- if (!credits || credits.used.amount <= 0) {
130
- return null;
131
- }
118
+ const { credits } = subscriptionPreview;
132
119
 
133
120
  return (
134
121
  <LineItemContainer>
@@ -138,7 +125,7 @@ export const AppliedCreditsLineItem = ({
138
125
  </Typography>
139
126
  <Typography variant="body1" color="secondary">
140
127
  <WithSkeleton isLoading={isFetchingSubscriptionPreview}>
141
- {currencyPriceFormatter({ amount: -1 * credits.used.amount, currency: credits.used.currency })}
128
+ {currencyPriceFormatter({ amount: -1 * credits!.used.amount, currency: credits!.used.currency })}
142
129
  </WithSkeleton>
143
130
  </Typography>
144
131
  </LineItemRow>
@@ -151,14 +138,12 @@ export const TaxLineItem = ({
151
138
  isFetchingSubscriptionPreview,
152
139
  checkoutLocalization,
153
140
  }: {
154
- subscriptionPreview: SubscriptionPreview | null;
141
+ subscriptionPreview: SubscriptionPreview;
155
142
  isFetchingSubscriptionPreview: boolean;
156
143
  checkoutLocalization: CheckoutLocalization;
157
144
  }) => {
158
- const { tax, taxDetails } = subscriptionPreview || {};
159
- if (!taxDetails || !tax) {
160
- return null;
161
- }
145
+ const tax = subscriptionPreview.tax!;
146
+ const taxDetails = subscriptionPreview.taxDetails!;
162
147
 
163
148
  return (
164
149
  <LineItemContainer>
@@ -1,8 +1,7 @@
1
- import { BillingPeriod, SubscriptionPreviewTaxDetails } from '@stigg/js-client-sdk';
1
+ import { BillingPeriod, Plan, SubscriptionPreviewTaxDetails } from '@stigg/js-client-sdk';
2
2
  import moment from 'moment';
3
3
  import merge from 'lodash/merge';
4
4
  import { DeepPartial } from '../../types';
5
- import { formatBillingPeriod } from './formatting';
6
5
 
7
6
  export type CheckoutLocalization = {
8
7
  changePlan: string;
@@ -20,42 +19,63 @@ export type CheckoutLocalization = {
20
19
  changesWillApplyAtEndOfBillingPeriod: string | ((params: { billingPeriodEnd: Date }) => string);
21
20
  checkoutButton: {
22
21
  nextText: string;
23
- downgradeText: string;
22
+ updateText: string;
23
+ downgradeToFreeText: string;
24
24
  upgradeText: string;
25
- purchaseText: string;
26
25
  };
27
26
  appliedCreditsTitle: string;
28
27
  taxTitle: (params: { taxDetails: SubscriptionPreviewTaxDetails }) => string;
28
+ downgradeToFree: {
29
+ alertText: (params: { plan: Plan }) => string;
30
+ freePlanHeader: (params: { plan: Plan }) => string;
31
+ freePlanName: (params: { plan: Plan }) => string;
32
+ freePlanPriceText: (params: { plan: Plan }) => string;
33
+ paidPlanHeader: (params: { plan: Plan }) => string;
34
+ paidPlanName: (params: { plan: Plan }) => string;
35
+ paidPlanPriceText: (params: { plan: Plan; billingPeriod?: BillingPeriod }) => string;
36
+ };
37
+ checkoutSuccessText: string;
29
38
  };
30
39
 
31
40
  export function getResolvedCheckoutLocalize(
32
41
  localizeOverride?: DeepPartial<CheckoutLocalization>,
33
42
  ): CheckoutLocalization {
34
43
  const checkoutDefaultLocalization: CheckoutLocalization = {
35
- changePlan: 'Change plan',
44
+ changePlan: 'Change',
36
45
  billingPeriodsTitle: 'Billing cycle',
37
46
  addAddonText: 'Add',
38
47
  newPaymentMethodText: 'New payment method',
39
48
  newPaymentMethodBillingAddressTitle: 'Billing address',
40
49
  newPaymentMethodCardTitle: 'Payment method',
41
- baseChargeText: ({ billingPeriod }) => `${formatBillingPeriod(billingPeriod)} charge`,
50
+ baseChargeText: () => 'Base charge',
42
51
  totalText: 'Total due today',
43
52
  subTotalText: 'Subtotal',
44
- addCouponCodeText: 'Add coupon code',
45
- couponCodeTitle: 'Coupon code',
53
+ addCouponCodeText: 'Add promotion code',
54
+ couponCodeTitle: 'Promotion code',
46
55
  addonsSectionTitle: 'Add-ons',
47
56
  changesWillApplyAtEndOfBillingPeriod: ({ billingPeriodEnd }) =>
48
- `Your changes will apply on the end of your current billing cycle on ${moment(billingPeriodEnd).format(
57
+ `Your changes will be applied at the end of your billing cycle on ${moment(billingPeriodEnd).format(
49
58
  'MMM D, YYYY',
50
59
  )}.`,
51
60
  checkoutButton: {
52
61
  nextText: 'Next',
53
- downgradeText: 'Downgrade',
54
- upgradeText: 'Upgrade',
55
- purchaseText: 'Purchase',
62
+ updateText: 'Update subscription',
63
+ downgradeToFreeText: 'Cancel subscription',
64
+ upgradeText: 'Subscribe',
56
65
  },
57
66
  appliedCreditsTitle: 'Applied credits',
58
- taxTitle: ({ taxDetails }) => `${taxDetails.displayName} (${taxDetails?.percentage}%)`,
67
+ taxTitle: ({ taxDetails }) => `Tax (${taxDetails?.percentage}%)`,
68
+ downgradeToFree: {
69
+ alertText: () => `We’re sorry to see you cancel your paid subscription 😭`,
70
+ freePlanHeader: () => 'New plan',
71
+ freePlanName: ({ plan }) => `${plan.displayName}`,
72
+ freePlanPriceText: () => 'Free',
73
+ paidPlanHeader: () => 'Current plan',
74
+ paidPlanName: ({ plan }) => `${plan.displayName}`,
75
+ paidPlanPriceText: ({ billingPeriod }) =>
76
+ `Paid plan${billingPeriod ? `, billed ${billingPeriod.toLowerCase()}` : ''}`,
77
+ },
78
+ checkoutSuccessText: 'Changes applied',
59
79
  };
60
80
 
61
81
  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 ||
@@ -0,0 +1,9 @@
1
+ import { SubscriptionBillingInfo } from '@stigg/js-client-sdk';
2
+
3
+ export type BillingInformation = {
4
+ taxDetails?: TaxDetailsInput;
5
+ };
6
+
7
+ export type TaxDetailsInput = {
8
+ taxPercentage?: SubscriptionBillingInfo['taxPercentage'];
9
+ };
@@ -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, Theme, useTheme } from '@emotion/react';
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() as Theme;
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
  );
@@ -123,8 +123,7 @@ export function mapCheckoutConfiguration(configuration: CheckoutConfiguration):
123
123
  text: {
124
124
  primary: palette?.textColor || undefined,
125
125
  },
126
- backgroundHighlight: palette?.selectionColor || undefined,
127
- backgroundSection: palette?.summaryBackgroundColor || undefined,
126
+ backgroundHighlight: palette?.summaryBackgroundColor || undefined,
128
127
  },
129
128
  typography: mapTypography(typography),
130
129
  };
@@ -28,14 +28,21 @@ type PriceBillingPeriodProps = {
28
28
  billingPeriod: BillingPeriod;
29
29
  hasMonthlyPrice: boolean;
30
30
  hasAnnuallyPrice: boolean;
31
+ paywallLocale: PaywallLocalization;
31
32
  };
32
33
 
33
- function PriceBillingPeriod({ plan, billingPeriod, hasMonthlyPrice, hasAnnuallyPrice }: PriceBillingPeriodProps) {
34
+ function PriceBillingPeriod({
35
+ plan,
36
+ billingPeriod,
37
+ hasMonthlyPrice,
38
+ hasAnnuallyPrice,
39
+ paywallLocale,
40
+ }: PriceBillingPeriodProps) {
34
41
  const hasPrice = plan.pricePoints.find(pricePoint => pricePoint.billingPeriod === billingPeriod);
35
42
 
36
43
  let content = EMPTY_CHAR;
37
44
  if (hasPrice && hasMonthlyPrice && hasAnnuallyPrice) {
38
- content = `, billed ${billingPeriod.toLowerCase()}`;
45
+ content = paywallLocale.price.billingPeriod?.(billingPeriod) || `, billed ${billingPeriod.toLowerCase()}`;
39
46
  }
40
47
 
41
48
  return (
@@ -133,6 +140,7 @@ export const PlanPrice = ({
133
140
  billingPeriod={billingPeriod}
134
141
  hasAnnuallyPrice={hasAnnuallyPrice}
135
142
  hasMonthlyPrice={hasMonthlyPrice}
143
+ paywallLocale={paywallLocale}
136
144
  />
137
145
  </Typography>
138
146
  )}