@blocklet/payment-react 1.14.21 → 1.14.22

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 (136) hide show
  1. package/es/checkout/donate.d.ts +2 -1
  2. package/es/checkout/donate.js +9 -10
  3. package/es/checkout/form.d.ts +1 -1
  4. package/es/checkout/form.js +23 -1
  5. package/es/checkout/table.d.ts +1 -1
  6. package/es/checkout/table.js +8 -1
  7. package/es/components/blockchain/tx.js +2 -1
  8. package/es/components/country-select.d.ts +16 -0
  9. package/es/components/country-select.js +82 -0
  10. package/es/components/input.d.ts +21 -21
  11. package/es/components/input.js +43 -42
  12. package/es/components/livemode.js +1 -0
  13. package/es/components/pricing-table.js +0 -2
  14. package/es/components/status.js +2 -3
  15. package/es/components/table.d.ts +2 -0
  16. package/es/components/table.js +186 -0
  17. package/es/contexts/payment.d.ts +2 -0
  18. package/es/contexts/payment.js +5 -2
  19. package/es/history/invoice/list.d.ts +3 -1
  20. package/es/history/invoice/list.js +215 -48
  21. package/es/hooks/mobile.d.ts +4 -0
  22. package/es/hooks/mobile.js +10 -0
  23. package/es/index.d.ts +5 -1
  24. package/es/index.js +7 -1
  25. package/es/libs/util.d.ts +15 -2
  26. package/es/libs/util.js +92 -28
  27. package/es/locales/en.js +22 -7
  28. package/es/locales/index.d.ts +0 -1
  29. package/es/locales/index.js +10 -1
  30. package/es/locales/zh.js +21 -6
  31. package/es/payment/error.js +2 -2
  32. package/es/payment/footer.js +1 -1
  33. package/es/payment/form/address.d.ts +9 -2
  34. package/es/payment/form/address.js +69 -69
  35. package/es/payment/form/currency.js +39 -25
  36. package/es/payment/form/index.d.ts +1 -1
  37. package/es/payment/form/index.js +83 -81
  38. package/es/payment/form/phone.js +15 -51
  39. package/es/payment/index.d.ts +1 -10
  40. package/es/payment/index.js +274 -219
  41. package/es/payment/product-card.js +4 -4
  42. package/es/payment/product-donation.js +7 -2
  43. package/es/payment/product-item.d.ts +2 -2
  44. package/es/payment/product-item.js +120 -81
  45. package/es/payment/summary.js +188 -118
  46. package/es/theme/index.css +240 -0
  47. package/es/theme/index.d.ts +9 -0
  48. package/es/theme/index.js +243 -0
  49. package/es/theme/typography.d.ts +2 -0
  50. package/es/theme/typography.js +53 -0
  51. package/es/types/index.d.ts +11 -0
  52. package/lib/checkout/donate.d.ts +2 -1
  53. package/lib/checkout/donate.js +14 -2
  54. package/lib/checkout/form.d.ts +1 -1
  55. package/lib/checkout/form.js +22 -1
  56. package/lib/checkout/table.d.ts +1 -1
  57. package/lib/checkout/table.js +14 -1
  58. package/lib/components/blockchain/tx.js +4 -1
  59. package/lib/components/country-select.d.ts +16 -0
  60. package/lib/components/country-select.js +115 -0
  61. package/lib/components/input.d.ts +21 -21
  62. package/lib/components/input.js +21 -12
  63. package/lib/components/livemode.js +1 -0
  64. package/lib/components/pricing-table.js +0 -2
  65. package/lib/components/status.js +2 -3
  66. package/lib/components/table.d.ts +2 -0
  67. package/lib/components/table.js +220 -0
  68. package/lib/contexts/payment.d.ts +2 -0
  69. package/lib/contexts/payment.js +4 -1
  70. package/lib/history/invoice/list.d.ts +3 -1
  71. package/lib/history/invoice/list.js +290 -62
  72. package/lib/hooks/mobile.d.ts +4 -0
  73. package/lib/hooks/mobile.js +17 -0
  74. package/lib/index.d.ts +5 -1
  75. package/lib/index.js +36 -0
  76. package/lib/libs/util.d.ts +15 -2
  77. package/lib/libs/util.js +115 -37
  78. package/lib/locales/en.js +22 -7
  79. package/lib/locales/index.d.ts +0 -1
  80. package/lib/locales/index.js +14 -3
  81. package/lib/locales/zh.js +21 -6
  82. package/lib/payment/error.js +5 -1
  83. package/lib/payment/footer.js +1 -1
  84. package/lib/payment/form/address.d.ts +9 -2
  85. package/lib/payment/form/address.js +67 -59
  86. package/lib/payment/form/currency.js +31 -24
  87. package/lib/payment/form/index.d.ts +1 -1
  88. package/lib/payment/form/index.js +92 -93
  89. package/lib/payment/form/phone.js +11 -59
  90. package/lib/payment/index.d.ts +1 -10
  91. package/lib/payment/index.js +291 -219
  92. package/lib/payment/product-card.js +5 -4
  93. package/lib/payment/product-donation.js +9 -2
  94. package/lib/payment/product-item.d.ts +2 -2
  95. package/lib/payment/product-item.js +38 -19
  96. package/lib/payment/summary.js +219 -127
  97. package/lib/theme/index.css +240 -0
  98. package/lib/theme/index.d.ts +9 -0
  99. package/lib/theme/index.js +259 -0
  100. package/lib/theme/typography.d.ts +2 -0
  101. package/lib/theme/typography.js +59 -0
  102. package/lib/types/index.d.ts +11 -0
  103. package/package.json +14 -11
  104. package/src/checkout/donate.tsx +16 -10
  105. package/src/checkout/form.tsx +23 -0
  106. package/src/checkout/table.tsx +13 -1
  107. package/src/components/blockchain/tx.tsx +2 -1
  108. package/src/components/country-select.tsx +93 -0
  109. package/src/components/input.tsx +49 -46
  110. package/src/components/livemode.tsx +1 -0
  111. package/src/components/pricing-table.tsx +0 -2
  112. package/src/components/status.tsx +1 -2
  113. package/src/components/table.tsx +200 -0
  114. package/src/contexts/payment.tsx +6 -1
  115. package/src/history/invoice/list.tsx +254 -49
  116. package/src/hooks/mobile.ts +13 -0
  117. package/src/index.ts +7 -0
  118. package/src/libs/util.ts +120 -31
  119. package/src/locales/en.tsx +18 -4
  120. package/src/locales/index.tsx +10 -3
  121. package/src/locales/zh.tsx +17 -3
  122. package/src/payment/error.tsx +2 -2
  123. package/src/payment/footer.tsx +1 -1
  124. package/src/payment/form/address.tsx +56 -47
  125. package/src/payment/form/currency.tsx +29 -23
  126. package/src/payment/form/index.tsx +89 -76
  127. package/src/payment/form/phone.tsx +14 -51
  128. package/src/payment/index.tsx +294 -242
  129. package/src/payment/product-card.tsx +4 -4
  130. package/src/payment/product-donation.tsx +7 -3
  131. package/src/payment/product-item.tsx +49 -20
  132. package/src/payment/summary.tsx +191 -108
  133. package/src/theme/index.css +240 -0
  134. package/src/theme/index.tsx +250 -0
  135. package/src/theme/typography.ts +56 -0
  136. package/src/types/index.ts +12 -0
@@ -14,7 +14,7 @@ type Props = {
14
14
  export default function ProductCard({ size, variant, name, logo, description, extra }: Props) {
15
15
  const s = { width: size, height: size };
16
16
  return (
17
- <Stack direction="row" alignItems="flex-start" spacing={1} flex={2} sx={{ width: '100%' }}>
17
+ <Stack direction="row" alignItems="center" spacing={1} flex={2} sx={{ width: '100%' }}>
18
18
  {logo ? (
19
19
  // @ts-ignore
20
20
  <Avatar src={logo} alt={name} variant={variant} sx={s} />
@@ -33,7 +33,7 @@ export default function ProductCard({ size, variant, name, logo, description, ex
33
33
  className="cko-ellipsis"
34
34
  variant="body1"
35
35
  title={name}
36
- sx={{ fontWeight: 500, mb: 0.5, lineHeight: 1 }}
36
+ sx={{ fontWeight: 500, mb: 0.5, lineHeight: 1, fontSize: 16 }}
37
37
  color="text.primary">
38
38
  {name}
39
39
  </Typography>
@@ -42,12 +42,12 @@ export default function ProductCard({ size, variant, name, logo, description, ex
42
42
  variant="body1"
43
43
  title={description}
44
44
  sx={{ fontSize: '0.85rem', mb: 0.5, lineHeight: 1, textAlign: 'left' }}
45
- color="text.secondary">
45
+ color="text.lighter">
46
46
  {description}
47
47
  </Typography>
48
48
  )}
49
49
  {extra && (
50
- <Typography variant="body1" sx={{ fontSize: '0.85rem' }} color="text.secondary">
50
+ <Typography variant="body1" sx={{ fontSize: '0.85rem' }} color="text.lighter">
51
51
  {extra}
52
52
  </Typography>
53
53
  )}
@@ -6,6 +6,7 @@ import { useEffect } from 'react';
6
6
 
7
7
  import Switch from '../components/switch-button';
8
8
  import { formatAmountPrecisionLimit } from '../libs/util';
9
+ import { usePaymentContext } from '../contexts/payment';
9
10
 
10
11
  export default function ProductDonation({
11
12
  item,
@@ -19,6 +20,7 @@ export default function ProductDonation({
19
20
  currency: TPaymentCurrency;
20
21
  }) {
21
22
  const { t, locale } = useLocaleContext();
23
+ const { setPayable } = usePaymentContext();
22
24
  const preset = settings.amount.preset || settings.amount.presets?.[0] || '0';
23
25
  const [state, setState] = useSetState({
24
26
  selected: preset,
@@ -51,14 +53,16 @@ export default function ProductDonation({
51
53
 
52
54
  if (formatAmountPrecisionLimit(value, locale)) {
53
55
  setState({ input: value, error: formatAmountPrecisionLimit(value, locale, precision) });
56
+ setPayable(false);
54
57
  return;
55
58
  }
56
59
 
57
60
  if (value < min || value > max) {
58
61
  setState({ input: value, error: t('payment.checkout.donation.between', { min, max }) });
62
+ setPayable(false);
59
63
  return;
60
64
  }
61
-
65
+ setPayable(true);
62
66
  setState({ error: '', input: value });
63
67
  onChange({ priceId: item.price_id, amount: value });
64
68
  };
@@ -77,7 +81,7 @@ export default function ProductDonation({
77
81
  <FormControlLabel
78
82
  control={<Switch checked={state.custom} sx={{ marginRight: 0.4 }} onChange={handleToggle} />}
79
83
  label={state.custom ? t('payment.checkout.donation.select') : t('payment.checkout.donation.custom')}
80
- sx={{ marginRight: 2, marginLeft: 0.5, color: 'text.secondary' }}
84
+ sx={{ marginRight: 2, marginLeft: 0.5, color: 'text.lighter' }}
81
85
  />
82
86
  )}
83
87
  {!state.custom && (
@@ -89,7 +93,7 @@ export default function ProductDonation({
89
93
  key={amount}
90
94
  variant="outlined"
91
95
  sx={{
92
- minWidth: 120,
96
+ minWidth: 115,
93
97
  textAlign: 'center',
94
98
  ...(state.selected === amount && !state.custom ? { borderColor: 'primary.main' } : {}),
95
99
  }}>
@@ -2,6 +2,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import type { PriceRecurring, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
3
  import { Box, Stack, Typography } from '@mui/material';
4
4
 
5
+ import React, { useMemo } from 'react';
5
6
  import Status from '../components/status';
6
7
  import Switch from '../components/switch-button';
7
8
  import {
@@ -44,55 +45,74 @@ export default function ProductItem({
44
45
  const saving = formatUpsellSaving(items, currency);
45
46
  const metered = item.price?.recurring?.usage_type === 'metered' ? t('common.metered') : '';
46
47
  const canUpsell = mode === 'normal' && items.length === 1;
48
+ const primaryText = useMemo(() => {
49
+ const price = item.upsell_price || item.price || {};
50
+ const isRecurring = price?.type === 'recurring' && price?.recurring;
51
+ if (isRecurring && trialInDays <= 0 && price?.recurring?.usage_type !== 'metered') {
52
+ return `${pricing.primary} ${price.recurring ? formatRecurring(price.recurring, false, 'slash', locale) : ''}`;
53
+ }
54
+ return pricing.primary;
55
+ }, [trialInDays, pricing, item, locale]);
56
+
47
57
  return (
48
- <Stack direction="column" alignItems="flex-start" spacing={1} sx={{ width: '100%' }}>
49
- <Stack direction="column" alignItems="flex-end" sx={{ width: '100%' }}>
58
+ <Stack direction="column" alignItems="flex-start" spacing={1} sx={{ width: '100%' }} className="product-item">
59
+ <Stack direction="column" alignItems="flex-start" sx={{ width: '100%' }} className="product-item-content">
50
60
  <Stack
51
61
  direction="row"
52
- alignItems="flex-start"
62
+ alignItems="center"
63
+ flexWrap="wrap"
53
64
  spacing={0.5}
54
65
  justifyContent="space-between"
55
66
  sx={{ width: '100%' }}>
56
67
  <ProductCard
57
68
  logo={item.price.product?.images[0]}
58
69
  name={item.price.product?.name}
59
- description={item.price.product?.description}
70
+ // description={item.price.product?.description}
60
71
  extra={
61
72
  <Box display="flex" alignItems="center">
62
73
  {item.price.type === 'recurring' && item.price.recurring
63
74
  ? [pricing.quantity, t('common.billed', { rule: `${formatRecurring(item.upsell_price?.recurring || item.price.recurring, true, 'per', locale)} ${metered}` })].filter(Boolean).join(', ') // prettier-ignore
64
75
  : pricing.quantity}
65
-
66
- {formatQuantityInventory(item.price, item.quantity, locale) ? (
67
- <Typography sx={{ fontSize: '0.85rem', color: 'red' }}>
68
- ({formatQuantityInventory(item.price, item.quantity, locale)})
69
- </Typography>
70
- ) : (
71
- ''
72
- )}
73
76
  </Box>
74
77
  }
75
78
  />
76
79
  <Stack direction="column" alignItems="flex-end" flex={1}>
77
- <Typography sx={{ color: 'text.primary', fontWeight: 500 }} gutterBottom>
78
- {pricing.primary}
80
+ <Typography sx={{ color: 'text.primary', fontWeight: 500, whiteSpace: 'nowrap' }} gutterBottom>
81
+ {primaryText}
79
82
  </Typography>
80
83
  {pricing.secondary && (
81
- <Typography sx={{ fontSize: '0.85rem', color: 'text.secondary' }}>{pricing.secondary}</Typography>
84
+ <Typography sx={{ fontSize: '0.85rem', color: 'text.lighter' }}>{pricing.secondary}</Typography>
82
85
  )}
83
86
  </Stack>
84
87
  </Stack>
88
+ {formatQuantityInventory(item.price, item.quantity, locale) ? (
89
+ <Status
90
+ label={formatQuantityInventory(item.price, item.quantity, locale)}
91
+ variant="outlined"
92
+ sx={{
93
+ mt: 1,
94
+ borderColor: 'var(--tags-tag-red-border, #FFC8D3)',
95
+ background: 'var(--tags-tag-red-bg, #FFE2E6)',
96
+ color: 'var(--tags-tag-red-text, #E40031)',
97
+ }}
98
+ />
99
+ ) : null}
85
100
  {children}
86
101
  </Stack>
87
102
  {canUpsell && !item.upsell_price_id && item.price.upsell?.upsells_to && (
88
- <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: '100%' }}>
103
+ <Stack
104
+ direction="row"
105
+ alignItems="center"
106
+ justifyContent="space-between"
107
+ sx={{ width: '100%' }}
108
+ className="product-item-upsell">
89
109
  <Typography
90
110
  component="label"
91
111
  htmlFor="upsell-switch"
92
112
  sx={{
93
113
  fontSize: 12,
94
114
  cursor: 'pointer',
95
- color: 'text.primary',
115
+ color: 'text.secondary',
96
116
  }}>
97
117
  <Switch
98
118
  id="upsell-switch"
@@ -106,9 +126,13 @@ export default function ProductItem({
106
126
  })}
107
127
  <Status
108
128
  label={t('payment.checkout.upsell.off', { saving })}
109
- color="primary"
110
129
  variant="outlined"
111
- sx={{ ml: 1 }}
130
+ sx={{
131
+ ml: 1,
132
+ borderColor: ' var(--tags-tag-orange-border, #FFE467)',
133
+ background: 'var(--tags-tag-orange-bg, #FFF4BC)',
134
+ color: 'var(--tags-tag-orange-text, #D24000)',
135
+ }}
112
136
  />
113
137
  </Typography>
114
138
  <Typography component="span" sx={{ fontSize: 12 }}>
@@ -117,7 +141,12 @@ export default function ProductItem({
117
141
  </Stack>
118
142
  )}
119
143
  {canUpsell && item.upsell_price_id && (
120
- <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: '100%' }}>
144
+ <Stack
145
+ direction="row"
146
+ alignItems="center"
147
+ justifyContent="space-between"
148
+ sx={{ width: '100%' }}
149
+ className="product-item-upsell">
121
150
  <Typography
122
151
  component="label"
123
152
  htmlFor="upsell-switch"
@@ -1,37 +1,67 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
- import { InfoOutlined } from '@mui/icons-material';
3
+ import { HelpOutline } from '@mui/icons-material';
4
4
  import { LoadingButton } from '@mui/lab';
5
- import { Fade, Grow, Stack, Tooltip, Typography, keyframes } from '@mui/material';
6
- import { BN, fromTokenToUnit } from '@ocap/util';
5
+ import {
6
+ Box,
7
+ Divider,
8
+ Fade,
9
+ Grow,
10
+ Stack,
11
+ Tooltip,
12
+ Typography,
13
+ Collapse,
14
+ IconButton,
15
+ IconButtonProps,
16
+ } from '@mui/material';
17
+ import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
7
18
  import { useRequest, useSetState } from 'ahooks';
8
19
  import noop from 'lodash/noop';
9
20
  import useBus from 'use-bus';
10
-
21
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
22
+ import { styled } from '@mui/material/styles';
11
23
  import Status from '../components/status';
12
24
  import api from '../libs/api';
13
25
  import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from '../libs/util';
14
26
  import PaymentAmount from './amount';
15
27
  import ProductDonation from './product-donation';
16
28
  import ProductItem from './product-item';
29
+ import Livemode from '../components/livemode';
30
+ import { usePaymentContext } from '../contexts/payment';
31
+ import { useMobile } from '../hooks/mobile';
17
32
 
18
- const shake = keyframes`
19
- 0% {
20
- transform: rotate(0deg);
21
- }
22
- 25% {
23
- transform: rotate(2deg);
24
- }
25
- 50% {
26
- transform: rotate(0eg);
27
- }
28
- 75% {
29
- transform: rotate(-2deg);
30
- }
31
- 100% {
32
- transform: rotate(0deg);
33
- }
34
- `;
33
+ // const shake = keyframes`
34
+ // 0% {
35
+ // transform: rotate(0deg);
36
+ // }
37
+ // 25% {
38
+ // transform: rotate(2deg);
39
+ // }
40
+ // 50% {
41
+ // transform: rotate(0eg);
42
+ // }
43
+ // 75% {
44
+ // transform: rotate(-2deg);
45
+ // }
46
+ // 100% {
47
+ // transform: rotate(0deg);
48
+ // }
49
+ // `;
50
+
51
+ interface ExpandMoreProps extends IconButtonProps {
52
+ expand: boolean;
53
+ }
54
+
55
+ const ExpandMore = styled((props: ExpandMoreProps) => {
56
+ const { expand, ...other } = props;
57
+ return <IconButton {...other} />;
58
+ })(({ theme, expand }) => ({
59
+ transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
60
+ marginLeft: 'auto',
61
+ transition: theme.transitions.create('transform', {
62
+ duration: theme.transitions.duration.shortest,
63
+ }),
64
+ }));
35
65
 
36
66
  type Props = {
37
67
  items: TLineItemExpanded[];
@@ -121,13 +151,18 @@ export default function PaymentSummary({
121
151
  ...rest
122
152
  }: Props) {
123
153
  const { t, locale } = useLocaleContext();
124
- const [state, setState] = useSetState({ loading: false, shake: false });
154
+ const { isMobile } = useMobile();
155
+ const settings = usePaymentContext();
156
+ const [state, setState] = useSetState({ loading: false, shake: false, expanded: items?.length < 3 });
125
157
  const { data, runAsync } = useRequest(() =>
126
158
  checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null)
127
159
  );
128
160
  const headlines = formatCheckoutHeadlines(items, currency, trialInDays, locale);
129
161
  const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : '0';
130
-
162
+ const totalAmount = fromUnitToToken(
163
+ new BN(fromTokenToUnit(headlines.actualAmount, currency?.decimal)).add(new BN(staking)).toString(),
164
+ currency?.decimal
165
+ );
131
166
  useBus(
132
167
  'error.REQUIRE_CROSS_SELL',
133
168
  () => {
@@ -173,44 +208,35 @@ export default function PaymentSummary({
173
208
  }
174
209
  };
175
210
 
176
- return (
177
- <Fade in>
178
- <Stack className="cko-product" direction="column" {...rest}>
179
- <Stack className="cko-product-summary" direction="column" alignItems="flex-start" sx={{ mb: { xs: 1, sm: 3 } }}>
180
- <Typography
181
- className="cko-ellipsis"
182
- component="div"
183
- title={action || headlines.action}
184
- sx={{ fontWeight: 500, fontSize: '1.15rem', color: 'text.secondary' }}>
185
- {action || headlines.action}
186
- </Typography>
187
- <PaymentAmount amount={headlines.amount} />
188
- {headlines.then && (
189
- <Typography component="div" sx={{ fontSize: '0.9rem', color: 'text.secondary' }}>
190
- {headlines.then}
191
- </Typography>
192
- )}
193
- </Stack>
194
- <Stack spacing={{ xs: 1, sm: 2 }}>
195
- {items.map((x: TLineItemExpanded) =>
196
- x.price.custom_unit_amount && onChangeAmount && donationSettings ? (
197
- <ProductDonation
198
- key={`${x.price_id}-${currency.id}`}
199
- item={x}
200
- settings={donationSettings}
201
- onChange={onChangeAmount}
202
- currency={currency}
203
- />
204
- ) : (
205
- <ProductItem
206
- key={`${x.price_id}-${currency.id}`}
207
- item={x}
208
- items={items}
209
- trialInDays={trialInDays}
210
- currency={currency}
211
- onUpsell={handleUpsell}
212
- onDownsell={handleDownsell}>
213
- {x.cross_sell && (
211
+ const ProductCardList = (
212
+ <Stack
213
+ className="cko-product-list"
214
+ sx={{
215
+ flex: '0 1 auto',
216
+ overflow: 'auto',
217
+ }}>
218
+ <Stack spacing={{ xs: 1, sm: 2 }}>
219
+ {items.map((x: TLineItemExpanded) =>
220
+ x.price.custom_unit_amount && onChangeAmount && donationSettings ? (
221
+ <ProductDonation
222
+ key={`${x.price_id}-${currency.id}`}
223
+ item={x}
224
+ settings={donationSettings}
225
+ onChange={onChangeAmount}
226
+ currency={currency}
227
+ />
228
+ ) : (
229
+ <ProductItem
230
+ key={`${x.price_id}-${currency.id}`}
231
+ item={x}
232
+ items={items}
233
+ trialInDays={trialInDays}
234
+ currency={currency}
235
+ onUpsell={handleUpsell}
236
+ onDownsell={handleDownsell}>
237
+ {x.cross_sell && (
238
+ <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: 1 }}>
239
+ <Typography />
214
240
  <LoadingButton
215
241
  size="small"
216
242
  loadingPosition="end"
@@ -220,32 +246,22 @@ export default function PaymentSummary({
220
246
  onClick={handleCancelCrossSell}>
221
247
  {t('payment.checkout.cross_sell.remove')}
222
248
  </LoadingButton>
223
- )}
224
- </ProductItem>
225
- )
226
- )}
227
- </Stack>
228
- {data && items.some((x) => x.price_id === data.id) === false && (
229
- <Grow in>
230
- <Stack
231
- direction="column"
232
- alignItems="flex-end"
233
- spacing={0.5}
234
- sx={{
235
- border: '1px solid #eee',
236
- borderRadius: 1,
237
- padding: 1,
238
- animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : 'none',
239
- mt: { xs: 1, sm: 2 },
240
- }}>
241
- <ProductItem
242
- item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
243
- items={items}
244
- trialInDays={trialInDays}
245
- currency={currency}
246
- onUpsell={noop}
247
- onDownsell={noop}
248
- />
249
+ </Stack>
250
+ )}
251
+ </ProductItem>
252
+ )
253
+ )}
254
+ </Stack>
255
+ {data && items.some((x) => x.price_id === data.id) === false && (
256
+ <Grow in>
257
+ <Stack mt={1}>
258
+ <ProductItem
259
+ item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
260
+ items={items}
261
+ trialInDays={trialInDays}
262
+ currency={currency}
263
+ onUpsell={noop}
264
+ onDownsell={noop}>
249
265
  <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: 1 }}>
250
266
  <Typography>
251
267
  {crossSellBehavior === 'required' && (
@@ -262,31 +278,98 @@ export default function PaymentSummary({
262
278
  {t('payment.checkout.cross_sell.add')}
263
279
  </LoadingButton>
264
280
  </Stack>
281
+ </ProductItem>
282
+ </Stack>
283
+ </Grow>
284
+ )}
285
+ </Stack>
286
+ );
287
+ return (
288
+ <Fade in>
289
+ <Stack className="cko-product" direction="column" {...rest}>
290
+ <Box display="flex" alignItems="center" sx={{ mb: 2.5 }}>
291
+ <Typography
292
+ title={t('payment.checkout.orderSummary')}
293
+ sx={{
294
+ color: 'text.primary',
295
+ fontSize: {
296
+ xs: '18px',
297
+ md: '24px',
298
+ },
299
+ fontWeight: '700',
300
+ lineHeight: '32px',
301
+ }}>
302
+ {action || t('payment.checkout.orderSummary')}
303
+ </Typography>
304
+ {!settings.livemode && <Livemode />}
305
+ </Box>
306
+ {isMobile ? (
307
+ <>
308
+ <Stack
309
+ justifyContent="space-between"
310
+ flexDirection="row"
311
+ alignItems="center"
312
+ mb={1.5}
313
+ onClick={() => setState({ expanded: !state.expanded })}>
314
+ <Typography>{t('payment.checkout.productListTotal', { total: items.length })}</Typography>
315
+ <ExpandMore expand={state.expanded} aria-expanded={state.expanded} aria-label="show more">
316
+ <ExpandMoreIcon />
317
+ </ExpandMore>
265
318
  </Stack>
266
- </Grow>
319
+ <Collapse in={state.expanded || !isMobile} timeout="auto" unmountOnExit>
320
+ {ProductCardList}
321
+ </Collapse>
322
+ </>
323
+ ) : (
324
+ ProductCardList
267
325
  )}
326
+
327
+ <Divider sx={{ mt: 2.5, mb: 2.5 }} />
268
328
  {staking > 0 && (
269
- <Stack
270
- direction="row"
271
- justifyContent="space-between"
272
- alignItems="center"
273
- spacing={1}
274
- sx={{
275
- border: '1px solid #eee',
276
- borderRadius: 1,
277
- padding: 1,
278
- mt: { xs: 1, sm: 2 },
279
- }}>
280
- <Stack direction="row" alignItems="center" spacing={0.5}>
281
- <Typography>{t('payment.checkout.staking.title')}</Typography>
282
- <Tooltip title={t('payment.checkout.staking.tooltip')} placement="top" sx={{ maxWidth: '150px' }}>
283
- <InfoOutlined fontSize="small" sx={{ color: 'text.secondary' }} />
284
- </Tooltip>
329
+ <>
330
+ <Stack direction="row" justifyContent="space-between" alignItems="center" spacing={1}>
331
+ <Stack direction="row" alignItems="center" spacing={0.5}>
332
+ <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.paymentRequired')}</Typography>
333
+ <Tooltip
334
+ title={<Typography>{t('payment.checkout.stakingConfirm')}</Typography>}
335
+ placement="top"
336
+ sx={{ maxWidth: '150px' }}>
337
+ <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
338
+ </Tooltip>
339
+ </Stack>
340
+ <Typography>{headlines.amount}</Typography>
285
341
  </Stack>
286
- <Typography>
287
- {formatAmount(staking, currency.decimal)} {currency.symbol}
288
- </Typography>
289
- </Stack>
342
+ <Stack direction="row" justifyContent="space-between" alignItems="center" spacing={1}>
343
+ <Stack direction="row" alignItems="center" spacing={0.5}>
344
+ <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.staking.title')}</Typography>
345
+ <Tooltip
346
+ title={<Typography>{t('payment.checkout.staking.tooltip')}</Typography>}
347
+ placement="top"
348
+ sx={{ maxWidth: '150px' }}>
349
+ <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
350
+ </Tooltip>
351
+ </Stack>
352
+ <Typography>
353
+ {formatAmount(staking, currency.decimal)} {currency.symbol}
354
+ </Typography>
355
+ </Stack>
356
+ </>
357
+ )}
358
+ <Stack
359
+ display="flex"
360
+ justifyContent="space-between"
361
+ flexDirection="row"
362
+ alignItems="center"
363
+ sx={{ width: '100%' }}>
364
+ <Box className="base-label">{t('common.total')} </Box>
365
+ <PaymentAmount amount={`${totalAmount} ${currency.symbol}`} sx={{ fontSize: '16px' }} />
366
+ </Stack>
367
+ {headlines.then && headlines.showThen && (
368
+ <Typography
369
+ component="div"
370
+ sx={{ fontSize: '0.9rem', color: 'text.lighter', textAlign: 'right', margin: '-2px 0 8px' }}>
371
+ {headlines.then}
372
+ </Typography>
290
373
  )}
291
374
  </Stack>
292
375
  </Fade>