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

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 (91) 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 +32 -0
  7. package/dist/components/checkout/hooks/useCheckoutModel.d.ts +2 -0
  8. package/dist/components/checkout/hooks/usePaymentStepModel.d.ts +8 -2
  9. package/dist/components/checkout/hooks/usePreviewSubscription.d.ts +10 -1
  10. package/dist/components/checkout/hooks/useProgressBarModel.d.ts +3 -0
  11. package/dist/components/checkout/hooks/useSubscriptionModel.d.ts +2 -1
  12. package/dist/components/checkout/index.d.ts +2 -0
  13. package/dist/components/checkout/progressBar/CheckoutProgressBar.style.d.ts +3 -2
  14. package/dist/components/checkout/steps/payment/PaymentMethods.d.ts +3 -2
  15. package/dist/components/checkout/steps/payment/PaymentStep.d.ts +2 -1
  16. package/dist/components/checkout/steps/payment/stripe/StripePaymentForm.d.ts +2 -1
  17. package/dist/components/checkout/steps/payment/stripe/stripe.utils.d.ts +4 -0
  18. package/dist/components/checkout/steps/payment/stripe/useSubmit.d.ts +4 -3
  19. package/dist/components/checkout/steps/plan/BillingPeriodPicker.style.d.ts +1 -0
  20. package/dist/components/checkout/steps/plan/CheckoutChargeList.d.ts +6 -1
  21. package/dist/components/checkout/summary/CheckoutSuccess.d.ts +4 -1
  22. package/dist/components/checkout/summary/CheckoutSummary.d.ts +3 -1
  23. package/dist/components/checkout/summary/components/CheckoutCaptions.d.ts +2 -1
  24. package/dist/components/checkout/summary/components/LineItems.d.ts +2 -2
  25. package/dist/components/checkout/textOverrides.d.ts +7 -3
  26. package/dist/components/checkout/theme.d.ts +0 -1
  27. package/dist/components/checkout/types.d.ts +7 -0
  28. package/dist/components/customerPortal/subscriptionOverview/subscriptionView/SubscriptionView.style.d.ts +1 -1
  29. package/dist/components/paywall/paywallTextOverrides.d.ts +4 -0
  30. package/dist/components/utils/getPaidPriceText.d.ts +3 -1
  31. package/dist/react-sdk.cjs.development.js +1147 -524
  32. package/dist/react-sdk.cjs.development.js.map +1 -1
  33. package/dist/react-sdk.cjs.production.min.js +1 -1
  34. package/dist/react-sdk.cjs.production.min.js.map +1 -1
  35. package/dist/react-sdk.esm.js +1181 -532
  36. package/dist/react-sdk.esm.js.map +1 -1
  37. package/dist/theme/getResolvedTheme.d.ts +1 -0
  38. package/dist/theme/types.d.ts +1 -0
  39. package/package.json +2 -2
  40. package/src/assets/payment-method.svg +3 -10
  41. package/src/components/checkout/Checkout.tsx +2 -1
  42. package/src/components/checkout/CheckoutContainer.style.ts +1 -0
  43. package/src/components/checkout/CheckoutContainer.tsx +59 -28
  44. package/src/components/checkout/CheckoutProvider.tsx +18 -18
  45. package/src/components/checkout/components/Button.tsx +19 -35
  46. package/src/components/checkout/components/ChangePlanButton.tsx +32 -0
  47. package/src/components/checkout/components/DowngradeToFreeContainer.tsx +118 -0
  48. package/src/components/checkout/components/Skeletons.style.ts +4 -1
  49. package/src/components/checkout/hooks/useCheckoutModel.ts +12 -2
  50. package/src/components/checkout/hooks/usePaymentStepModel.ts +22 -3
  51. package/src/components/checkout/hooks/usePlanStepModel.ts +25 -10
  52. package/src/components/checkout/hooks/usePreviewSubscription.ts +112 -40
  53. package/src/components/checkout/hooks/useProgressBarModel.ts +18 -0
  54. package/src/components/checkout/hooks/useSubscriptionModel.ts +8 -2
  55. package/src/components/checkout/hooks/useSubscriptionState.ts +2 -1
  56. package/src/components/checkout/index.ts +2 -0
  57. package/src/components/checkout/planHeader/PlanHeader.style.tsx +1 -1
  58. package/src/components/checkout/planHeader/PlanHeader.tsx +7 -15
  59. package/src/components/checkout/progressBar/CheckoutProgressBar.style.ts +6 -3
  60. package/src/components/checkout/progressBar/CheckoutProgressBar.tsx +13 -9
  61. package/src/components/checkout/promotionCode/AddPromotionCode.tsx +6 -7
  62. package/src/components/checkout/steps/addons/CheckoutAddonsStep.tsx +58 -11
  63. package/src/components/checkout/steps/payment/PaymentMethods.style.ts +1 -0
  64. package/src/components/checkout/steps/payment/PaymentMethods.tsx +13 -6
  65. package/src/components/checkout/steps/payment/PaymentStep.tsx +3 -1
  66. package/src/components/checkout/steps/payment/stripe/StripePaymentForm.tsx +35 -4
  67. package/src/components/checkout/steps/payment/stripe/stripe.utils.ts +4 -3
  68. package/src/components/checkout/steps/payment/stripe/useSubmit.ts +61 -48
  69. package/src/components/checkout/steps/plan/BillingPeriodPicker.style.tsx +27 -6
  70. package/src/components/checkout/steps/plan/BillingPeriodPicker.tsx +26 -5
  71. package/src/components/checkout/steps/plan/CheckoutChargeList.tsx +62 -12
  72. package/src/components/checkout/summary/CheckoutSuccess.tsx +52 -6
  73. package/src/components/checkout/summary/CheckoutSummary.tsx +48 -33
  74. package/src/components/checkout/summary/components/CheckoutCaptions.tsx +30 -29
  75. package/src/components/checkout/summary/components/LineItems.tsx +8 -16
  76. package/src/components/checkout/textOverrides.ts +15 -12
  77. package/src/components/checkout/theme.ts +0 -4
  78. package/src/components/checkout/types.ts +9 -0
  79. package/src/components/common/Icon.tsx +4 -6
  80. package/src/components/common/mapExternalTheme.ts +1 -2
  81. package/src/components/paywall/PlanPrice.tsx +10 -2
  82. package/src/components/paywall/paywallTextOverrides.ts +3 -0
  83. package/src/components/utils/getPaidPriceText.ts +8 -2
  84. package/src/components/utils/getPlanPrice.ts +1 -1
  85. package/src/stories/Checkout.stories.tsx +6 -5
  86. package/src/theme/Theme.tsx +10 -1
  87. package/src/theme/getResolvedTheme.ts +1 -0
  88. package/src/theme/types.ts +1 -0
  89. package/dist/components/checkout/steps/surprise/SurpriseStep.d.ts +0 -2
  90. package/src/assets/nyancat.svg +0 -634
  91. 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';
@@ -60,31 +60,37 @@ const TotalDueText = styled(Typography)`
60
60
 
61
61
  function resolveCheckoutButtonText({
62
62
  isLastStep,
63
- subscriptionPreview,
63
+ isFreeDowngrade,
64
64
  checkoutLocalization,
65
- isFirstSubscription,
65
+ isPlanUpdate,
66
66
  }: {
67
67
  isLastStep?: boolean;
68
- isFirstSubscription?: boolean;
69
- subscriptionPreview?: SubscriptionPreview | null;
68
+ isFreeDowngrade: boolean;
70
69
  checkoutLocalization: CheckoutLocalization;
70
+ isPlanUpdate?: boolean;
71
71
  }) {
72
72
  if (!isLastStep) {
73
73
  return checkoutLocalization.checkoutButton.nextText;
74
74
  }
75
75
 
76
- if (subscriptionPreview?.isPlanDowngrade) {
77
- return checkoutLocalization.checkoutButton.downgradeText;
76
+ if (isPlanUpdate) {
77
+ return checkoutLocalization.checkoutButton.updateText;
78
78
  }
79
79
 
80
- if (!isFirstSubscription) {
81
- return checkoutLocalization.checkoutButton.upgradeText;
80
+ if (isFreeDowngrade) {
81
+ return checkoutLocalization.checkoutButton.downgradeToFreeText;
82
82
  }
83
83
 
84
- return checkoutLocalization.checkoutButton.purchaseText;
84
+ return checkoutLocalization.checkoutButton.upgradeText;
85
85
  }
86
86
 
87
- export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutContainerProps) => {
87
+ export const CheckoutSummary = ({
88
+ onCheckout,
89
+ onCheckoutCompleted,
90
+ disablePromotionCode,
91
+ disableSuccessAnimation,
92
+ isFreeDowngrade,
93
+ }: CheckoutContainerProps & { isFreeDowngrade: boolean }) => {
88
94
  const [isCheckoutCompletedSuccessfully, setIsCheckoutCompletedSuccessfully] = useState(false);
89
95
  const { setErrorMessage } = usePaymentStepModel();
90
96
  const progressBar = useProgressBarModel();
@@ -96,12 +102,12 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
96
102
  );
97
103
  const [baseCharges, usageCharges] = partition(planPrices, (price) => price.pricingModel === BillingModel.FlatFee);
98
104
  const [baseCharge] = baseCharges || [];
99
- const isFirstSubscription = !activeSubscription?.id;
100
- const isLastStep = progressBar.isCheckoutComplete && progressBar.isLastStep;
105
+ const isLastStep = isFreeDowngrade || (progressBar.isCheckoutComplete && progressBar.isLastStep);
101
106
 
102
107
  const { subscriptionPreview, isFetchingSubscriptionPreview } = usePreviewSubscription();
103
108
 
104
109
  const { handleSubmit, isLoading } = useSubmit({
110
+ disableSuccessAnimation,
105
111
  onCheckout,
106
112
  onCheckoutCompleted,
107
113
  onSuccess: () => {
@@ -119,11 +125,9 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
119
125
  if (errorMessage) {
120
126
  setErrorMessage(errorMessage);
121
127
  setIsCheckoutCompletedSuccessfully(false);
122
- return;
128
+ } else {
129
+ setErrorMessage(undefined);
123
130
  }
124
-
125
- setErrorMessage(undefined);
126
- setIsCheckoutCompletedSuccessfully(true);
127
131
  };
128
132
 
129
133
  const onCheckoutClick = async (e: any): Promise<void> => {
@@ -188,11 +192,13 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
188
192
 
189
193
  if (!addonPrice) return null;
190
194
 
195
+ const addonQuantity = addon.quantity && addon.quantity > 0 ? addon.quantity : 1;
196
+
191
197
  return (
192
198
  <BilledPriceLineItem
193
199
  key={addon?.addon?.id}
194
200
  label={addon.addon.displayName}
195
- quantity={addon.quantity}
201
+ quantity={addonQuantity}
196
202
  price={addonPrice}
197
203
  />
198
204
  );
@@ -211,7 +217,7 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
211
217
 
212
218
  <StyledDivider className="stigg-checkout-summary-divider" />
213
219
 
214
- {isFirstSubscription && (
220
+ {!disablePromotionCode && !isFreeDowngrade && (
215
221
  <>
216
222
  <PromotionCodeSection checkoutLocalization={checkoutLocalization} />
217
223
 
@@ -219,18 +225,18 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
219
225
  </>
220
226
  )}
221
227
 
222
- <AppliedCreditsLineItem
228
+ <DiscountLineItem
223
229
  subscriptionPreview={subscriptionPreview}
224
230
  isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
225
- checkoutLocalization={checkoutLocalization}
226
231
  />
227
232
 
228
- <DiscountLineItem
233
+ <TaxLineItem
229
234
  subscriptionPreview={subscriptionPreview}
230
235
  isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
236
+ checkoutLocalization={checkoutLocalization}
231
237
  />
232
238
 
233
- <TaxLineItem
239
+ <AppliedCreditsLineItem
234
240
  subscriptionPreview={subscriptionPreview}
235
241
  isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
236
242
  checkoutLocalization={checkoutLocalization}
@@ -253,15 +259,15 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
253
259
  subscriptionPreview={subscriptionPreview}
254
260
  isFetchingSubscriptionPreview={isFetchingSubscriptionPreview}
255
261
  checkoutLocalization={checkoutLocalization}
262
+ billingPeriod={subscription.billingPeriod}
256
263
  />
257
264
 
258
265
  <Button
259
- disableRipple={isLoading}
260
- $isLoading={isLoading}
261
266
  $success={isCheckoutCompletedSuccessfully}
262
- $error={isLastStep && subscriptionPreview?.isPlanDowngrade}
267
+ $error={isLastStep && isFreeDowngrade}
268
+ disabled={isLoading || isFetchingSubscriptionPreview || progressBar.progressBarState.isDisabled}
263
269
  className="stigg-checkout-summary-cta-button"
264
- sx={{ textTransform: 'none', borderRadius: '10px', marginTop: '24px' }}
270
+ sx={{ textTransform: 'none', borderRadius: '10px', marginTop: '24px', height: '36px' }}
265
271
  variant="contained"
266
272
  size="medium"
267
273
  onClick={(e: any) => {
@@ -269,11 +275,18 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
269
275
  }}
270
276
  fullWidth>
271
277
  <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 })}
278
+ {isCheckoutCompletedSuccessfully ? (
279
+ <Icon icon="Check" style={{ display: 'contents' }} />
280
+ ) : isLoading || isFetchingSubscriptionPreview ? (
281
+ <CircularProgress size={20} sx={{ color: 'white' }} />
282
+ ) : (
283
+ resolveCheckoutButtonText({
284
+ isLastStep,
285
+ isFreeDowngrade,
286
+ checkoutLocalization,
287
+ isPlanUpdate: !!activeSubscription && activeSubscription?.plan.id === plan?.id,
288
+ })
289
+ )}
277
290
  </Typography>
278
291
  </Button>
279
292
  </SummaryCard>
@@ -282,7 +295,9 @@ export const CheckoutSummary = ({ onCheckout, onCheckoutCompleted }: CheckoutCon
282
295
  showWatermark
283
296
  style={{ marginTop: 8, display: 'flex', justifyContent: 'center' }}
284
297
  />
285
- {isCheckoutCompletedSuccessfully && <CheckoutSuccess />}
298
+ {!disableSuccessAnimation && isCheckoutCompletedSuccessfully && (
299
+ <CheckoutSuccess checkoutLocalization={checkoutLocalization} />
300
+ )}
286
301
  </Box>
287
302
  );
288
303
  };
@@ -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,12 +40,12 @@ 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 (
@@ -65,13 +57,13 @@ export const BilledPriceLineItem = ({ label, quantity, price }: { label: string;
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>
@@ -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,12 +19,14 @@ 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
+ downgradeToFreeAlertText: (params: { plan: Plan }) => string;
29
+ checkoutSuccessText: string;
29
30
  };
30
31
 
31
32
  export function getResolvedCheckoutLocalize(
@@ -38,24 +39,26 @@ export function getResolvedCheckoutLocalize(
38
39
  newPaymentMethodText: 'New payment method',
39
40
  newPaymentMethodBillingAddressTitle: 'Billing address',
40
41
  newPaymentMethodCardTitle: 'Payment method',
41
- baseChargeText: ({ billingPeriod }) => `${formatBillingPeriod(billingPeriod)} charge`,
42
+ baseChargeText: () => 'Base charge',
42
43
  totalText: 'Total due today',
43
44
  subTotalText: 'Subtotal',
44
- addCouponCodeText: 'Add coupon code',
45
- couponCodeTitle: 'Coupon code',
45
+ addCouponCodeText: 'Add promotion code',
46
+ couponCodeTitle: 'Promotion code',
46
47
  addonsSectionTitle: 'Add-ons',
47
48
  changesWillApplyAtEndOfBillingPeriod: ({ billingPeriodEnd }) =>
48
- `Your changes will apply on the end of your current billing cycle on ${moment(billingPeriodEnd).format(
49
+ `Your changes will be applied at the end of your billing cycle on ${moment(billingPeriodEnd).format(
49
50
  'MMM D, YYYY',
50
51
  )}.`,
51
52
  checkoutButton: {
52
53
  nextText: 'Next',
53
- downgradeText: 'Downgrade',
54
- upgradeText: 'Upgrade',
55
- purchaseText: 'Purchase',
54
+ updateText: 'Update subscription',
55
+ downgradeToFreeText: 'Cancel subscription',
56
+ upgradeText: 'Subscribe',
56
57
  },
57
58
  appliedCreditsTitle: 'Applied credits',
58
- taxTitle: ({ taxDetails }) => `${taxDetails.displayName} (${taxDetails?.percentage}%)`,
59
+ taxTitle: ({ taxDetails }) => `Tax (${taxDetails?.percentage}%)`,
60
+ downgradeToFreeAlertText: () => `We’re sorry to see you cancel your paid subscription 😭`,
61
+ checkoutSuccessText: 'Payment successful',
59
62
  };
60
63
 
61
64
  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
  )}
@@ -26,6 +26,8 @@ export type PaywallLocalization = {
26
26
  };
27
27
  price: {
28
28
  startingAtCaption: string;
29
+ billingPeriod?: (billingPeriod: BillingPeriod) => string;
30
+ pricePeriod: (billingPeriod: BillingPeriod) => string;
29
31
  custom: string;
30
32
  priceNotSet: string;
31
33
  free: PlanPriceText | ((currency?: PaywallCurrency) => PlanPriceText);
@@ -56,6 +58,7 @@ export function getResolvedPaywallLocalize(localizeOverride?: DeepPartial<Paywal
56
58
  },
57
59
  price: {
58
60
  startingAtCaption: 'Starts at',
61
+ pricePeriod: (billingPeriod: BillingPeriod) => (billingPeriod === BillingPeriod.Monthly ? '/ month' : '/ year'),
59
62
  free: currency => ({
60
63
  price: `${currency?.symbol}0`,
61
64
  }),
@@ -8,6 +8,7 @@ import {
8
8
  import { currencyPriceFormatter } from './currencyUtils';
9
9
  import { PlanPriceText } from './getPlanPrice';
10
10
  import { calculateTierPrice, getPriceFeatureUnit } from './priceTierUtils';
11
+ import { PaywallLocalization } from '../paywall';
11
12
 
12
13
  type GetPaidPriceTextParams = {
13
14
  planPrices: Price[];
@@ -16,6 +17,7 @@ type GetPaidPriceTextParams = {
16
17
  locale: string;
17
18
  shouldShowMonthlyPriceAmount: boolean;
18
19
  selectedTierByFeature: Record<string, PriceTierFragment>;
20
+ paywallLocale: PaywallLocalization;
19
21
  };
20
22
 
21
23
  export function getPaidPriceText({
@@ -25,6 +27,7 @@ export function getPaidPriceText({
25
27
  locale,
26
28
  shouldShowMonthlyPriceAmount,
27
29
  selectedTierByFeature,
30
+ paywallLocale,
28
31
  }: GetPaidPriceTextParams): PlanPriceText {
29
32
  const { amount, currency } = paywallCalculatedPrice || planPrices[0];
30
33
  const priceAmount = amount || 0;
@@ -35,7 +38,10 @@ export function getPaidPriceText({
35
38
 
36
39
  let tiers;
37
40
  let tierUnits;
38
- let unit = shouldShowMonthlyPriceAmount ? '/ month' : '/ year';
41
+ const pricePeriod = paywallLocale.price.pricePeriod(
42
+ shouldShowMonthlyPriceAmount ? BillingPeriod.Monthly : BillingPeriod.Annually,
43
+ );
44
+ let unit = pricePeriod;
39
45
 
40
46
  for (const price of planPrices) {
41
47
  if (price.isTieredPrice) {
@@ -56,7 +62,7 @@ export function getPaidPriceText({
56
62
  const featureUnit = price.feature?.units || '';
57
63
 
58
64
  if (price.pricingModel === BillingModel.PerUnit && !price.isTieredPrice) {
59
- unit = shouldShowMonthlyPriceAmount ? `per ${featureUnit} / month` : `per ${featureUnit} / year`;
65
+ unit = shouldShowMonthlyPriceAmount ? `per ${featureUnit} ${pricePeriod}` : `per ${featureUnit} ${pricePeriod}`;
60
66
  } else if (price.pricingModel === BillingModel.UsageBased) {
61
67
  unit = `per ${featureUnit}`;
62
68
  }
@@ -50,7 +50,7 @@ export function getPlanPrice(
50
50
 
51
51
  return paywallLocale.price.paid
52
52
  ? paywallLocale.price.paid({ ...paidParams, plan })
53
- : getPaidPriceText({ ...paidParams, locale, shouldShowMonthlyPriceAmount });
53
+ : getPaidPriceText({ ...paidParams, locale, shouldShowMonthlyPriceAmount, paywallLocale });
54
54
  }
55
55
  default:
56
56
  return {
@@ -46,7 +46,8 @@ const Template: ComponentStory<any> = (args) => (
46
46
  onChangePlan={({ currentPlan }) => {
47
47
  console.log('plan changed clicked!', { currentPlan });
48
48
  }}
49
- billingInformation={{ taxPercentage: 27 }}
49
+ // disableSuccessAnimation
50
+ // billingInformation={{ taxPercentage: 27 }}
50
51
  />
51
52
  </Wrapper>
52
53
  );
@@ -55,8 +56,8 @@ export const DefaultCheckout = Template.bind({});
55
56
  DefaultCheckout.args = {
56
57
  ...defaultArgsWithCustomer,
57
58
  planId: 'plan-revvenu-essentials',
58
- baseUri: 'http://localhost:4000',
59
- apiKey: 'client-72b058a6-0f22-4c86-adce-bf266d12e12e:9f356ceb-c94c-42a4-9572-10b12824da81',
60
- // baseUri: 'https://api-staging.stigg.io',
61
- // apiKey: 'client-79584f52-7ef9-4c58-b9ac-5080acf492e4:71f2274c-100a-4fa4-8a43-48fa3b16c627',
59
+ // baseUri: 'http://localhost:4000',
60
+ // apiKey: 'client-72b058a6-0f22-4c86-adce-bf266d12e12e:9f356ceb-c94c-42a4-9572-10b12824da81',
61
+ baseUri: 'https://api-staging.stigg.io',
62
+ apiKey: 'client-79584f52-7ef9-4c58-b9ac-5080acf492e4:71f2274c-100a-4fa4-8a43-48fa3b16c627',
62
63
  };
@@ -61,13 +61,22 @@ function createTypographyTheme(theme: StiggTheme): Partial<TypographyProps> {
61
61
  };
62
62
  }
63
63
 
64
+ const createMuiPalette = (theme: StiggTheme) => {
65
+ return {
66
+ primary: {
67
+ main: theme.palette.primary,
68
+ },
69
+ };
70
+ };
71
+
64
72
  export const SdkThemeProvider: React.FC<PropsWithChildren<SdkThemeProviderProps>> = ({ children, componentTheme }) => {
65
73
  const theme = useStiggTheme(componentTheme);
74
+ const muiPalette = createMuiPalette(theme);
66
75
 
67
76
  return (
68
77
  // We are using styled-components theme here only because we are using styled-typography
69
78
  // which depends on styled-components for the typography theming
70
- <MuiThemeProvider theme={createTheme({ stigg: theme })}>
79
+ <MuiThemeProvider theme={createTheme({ palette: muiPalette, stigg: theme })}>
71
80
  <ThemeProvider theme={{ stigg: theme }}>
72
81
  <CustomCssGlobal customCss={theme.customCss}>
73
82
  <Fonts externalFontUrl={theme.typography.fontFamilyUrl} />
@@ -21,6 +21,7 @@ export const getResolvedTheme = (customizedTheme?: CustomizedTheme): StiggTheme
21
21
  palette: {
22
22
  primary: primaryColor.hex(),
23
23
  primaryDark: primaryColor.darken(0.3).hex(),
24
+ primaryLight: primaryColor.lighten(0.6).hex(),
24
25
  backgroundPaper: '#FFFFFF',
25
26
  backgroundHighlight: '#F5F6F9',
26
27
  backgroundSection: primaryColor.alpha(0.1).toString(),