@blocklet/payment-react 1.18.6 → 1.18.8

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 (70) hide show
  1. package/README.md +394 -341
  2. package/es/checkout/donate.d.ts +29 -4
  3. package/es/checkout/donate.js +193 -95
  4. package/es/components/livemode.js +1 -1
  5. package/es/components/loading-button.d.ts +10 -0
  6. package/es/components/loading-button.js +75 -0
  7. package/es/components/pricing-table.js +2 -3
  8. package/es/components/table.js +1 -1
  9. package/es/index.d.ts +2 -1
  10. package/es/index.js +3 -1
  11. package/es/libs/util.d.ts +1 -0
  12. package/es/libs/util.js +10 -1
  13. package/es/payment/amount.js +1 -1
  14. package/es/payment/form/index.js +14 -12
  15. package/es/payment/form/stripe/form.js +20 -5
  16. package/es/payment/index.js +0 -1
  17. package/es/payment/product-card.js +2 -2
  18. package/es/payment/product-item.js +1 -1
  19. package/es/payment/product-skeleton.js +2 -2
  20. package/es/payment/skeleton/donation.js +1 -1
  21. package/es/payment/skeleton/overview.js +1 -1
  22. package/es/payment/skeleton/payment.js +1 -1
  23. package/es/payment/summary.js +2 -2
  24. package/es/theme/index.js +5 -3
  25. package/es/theme/typography.js +8 -8
  26. package/lib/checkout/donate.d.ts +29 -4
  27. package/lib/checkout/donate.js +197 -136
  28. package/lib/components/livemode.js +1 -1
  29. package/lib/components/loading-button.d.ts +10 -0
  30. package/lib/components/loading-button.js +86 -0
  31. package/lib/components/pricing-table.js +3 -4
  32. package/lib/components/table.js +1 -1
  33. package/lib/index.d.ts +2 -1
  34. package/lib/index.js +8 -0
  35. package/lib/libs/util.d.ts +1 -0
  36. package/lib/libs/util.js +7 -0
  37. package/lib/payment/amount.js +1 -1
  38. package/lib/payment/form/index.js +14 -15
  39. package/lib/payment/form/stripe/form.js +25 -6
  40. package/lib/payment/index.js +0 -1
  41. package/lib/payment/product-card.js +2 -2
  42. package/lib/payment/product-item.js +1 -1
  43. package/lib/payment/product-skeleton.js +2 -2
  44. package/lib/payment/skeleton/donation.js +1 -1
  45. package/lib/payment/skeleton/overview.js +1 -1
  46. package/lib/payment/skeleton/payment.js +1 -1
  47. package/lib/payment/summary.js +4 -4
  48. package/lib/theme/index.js +5 -3
  49. package/lib/theme/typography.js +8 -8
  50. package/package.json +8 -8
  51. package/src/checkout/donate.tsx +209 -128
  52. package/src/components/livemode.tsx +1 -1
  53. package/src/components/loading-button.tsx +100 -0
  54. package/src/components/pricing-table.tsx +3 -3
  55. package/src/components/table.tsx +1 -1
  56. package/src/index.ts +2 -0
  57. package/src/libs/util.ts +11 -1
  58. package/src/payment/amount.tsx +1 -1
  59. package/src/payment/form/index.tsx +65 -60
  60. package/src/payment/form/stripe/form.tsx +21 -6
  61. package/src/payment/index.tsx +0 -1
  62. package/src/payment/product-card.tsx +2 -2
  63. package/src/payment/product-item.tsx +1 -1
  64. package/src/payment/product-skeleton.tsx +2 -2
  65. package/src/payment/skeleton/donation.tsx +1 -1
  66. package/src/payment/skeleton/overview.tsx +1 -1
  67. package/src/payment/skeleton/payment.tsx +1 -1
  68. package/src/payment/summary.tsx +2 -2
  69. package/src/theme/index.tsx +3 -1
  70. package/src/theme/typography.ts +8 -8
@@ -1,9 +1,11 @@
1
+ /* eslint-disable react/no-unused-prop-types */
1
2
  /* eslint-disable react/require-default-props */
2
3
  /* eslint-disable @typescript-eslint/indent */
3
4
  import Dialog from '@arcblock/ux/lib/Dialog';
4
5
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
6
  import type {
6
7
  DonationSettings,
8
+ PaymentBeneficiary,
7
9
  PaymentDetails,
8
10
  TCheckoutSessionExpanded,
9
11
  TPaymentCurrency,
@@ -12,20 +14,14 @@ import type {
12
14
  TSetting,
13
15
  } from '@blocklet/payment-types';
14
16
  import {
15
- Alert,
16
17
  Avatar,
17
18
  AvatarGroup,
18
19
  Box,
19
20
  Button,
20
21
  CircularProgress,
21
- Hidden,
22
22
  IconButton,
23
23
  Popover,
24
24
  Stack,
25
- Table,
26
- TableBody,
27
- TableCell,
28
- TableRow,
29
25
  Typography,
30
26
  Tooltip,
31
27
  type ButtonProps as MUIButtonProps,
@@ -36,14 +32,13 @@ import uniqBy from 'lodash/unionBy';
36
32
  import { useEffect, useRef, useState } from 'react';
37
33
  import { Settings } from '@mui/icons-material';
38
34
 
39
- import TxLink from '../components/blockchain/tx';
40
35
  import api from '../libs/api';
41
36
  import {
42
37
  formatAmount,
43
38
  formatBNStr,
44
- formatDateTime,
45
- formatError,
46
39
  getCustomerAvatar,
40
+ getTxLink,
41
+ getUserProfileLink,
47
42
  lazyLoad,
48
43
  openDonationSettings,
49
44
  } from '../libs/util';
@@ -59,22 +54,43 @@ export type DonateHistory = {
59
54
  supporters: TCheckoutSessionExpanded[];
60
55
  currency: TPaymentCurrency;
61
56
  method: TPaymentMethod;
62
- // total?: number;
57
+ total?: number;
63
58
  totalAmount: string;
64
59
  };
65
- export type RequiredDonationSettings = Pick<
66
- DonationSettings,
67
- 'target' | 'title' | 'description' | 'reference' | 'beneficiaries'
68
- >;
69
- type OptionalDonationSettings = Partial<Omit<DonationSettings, keyof RequiredDonationSettings>>;
70
60
 
61
+ export type CheckoutDonateSettings = {
62
+ target: string;
63
+ title: string;
64
+ description: string;
65
+ reference: string;
66
+ beneficiaries: PaymentBeneficiary[];
67
+ amount?: {
68
+ presets?: string[];
69
+ preset?: string;
70
+ minimum?: string;
71
+ maximum?: string;
72
+ custom?: boolean;
73
+ };
74
+ appearance?: {
75
+ button?: {
76
+ text?: any;
77
+ icon?: any;
78
+ size?: string;
79
+ color?: string;
80
+ variant?: string;
81
+ };
82
+ history?: {
83
+ variant?: string;
84
+ };
85
+ };
86
+ };
71
87
  export interface ButtonType extends Omit<MUIButtonProps, 'text' | 'icon'> {
72
88
  text?: string | React.ReactNode;
73
89
  icon: React.ReactNode;
74
90
  }
75
91
 
76
92
  export type DonateProps = Pick<CheckoutProps, 'onPaid' | 'onError'> & {
77
- settings: RequiredDonationSettings & OptionalDonationSettings;
93
+ settings: CheckoutDonateSettings;
78
94
  livemode?: boolean;
79
95
  timeout?: number;
80
96
  mode?: 'inline' | 'default' | 'custom';
@@ -129,124 +145,174 @@ const emojiFont = {
129
145
  'Avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
130
146
  };
131
147
 
148
+ function DonateDetails({ supporters = [], currency, method }: DonateHistory) {
149
+ const { locale } = useLocaleContext();
150
+ return (
151
+ <Stack
152
+ sx={{
153
+ width: '100%',
154
+ minWidth: '256px',
155
+ maxWidth: 'calc(100vw - 32px)',
156
+ maxHeight: '300px',
157
+ overflowX: 'hidden',
158
+ overflowY: 'auto',
159
+ margin: '0 auto',
160
+ }}>
161
+ {supporters.map((x) => (
162
+ <Box
163
+ key={x.id}
164
+ sx={{
165
+ padding: '6px',
166
+ '&:hover': {
167
+ backgroundColor: 'var(--backgrounds-bg-highlight, #eff6ff)',
168
+ transition: 'background-color 200ms linear',
169
+ cursor: 'pointer',
170
+ },
171
+ borderBottom: '1px solid var(--stroke-border-base, #EFF1F5)',
172
+ display: 'flex',
173
+ justifyContent: 'space-between',
174
+ alignItems: 'center',
175
+ }}
176
+ onClick={() => {
177
+ const { link, text } = getTxLink(method, x.payment_details as PaymentDetails);
178
+ if (link && text) {
179
+ window.open(link, '_blank');
180
+ }
181
+ }}>
182
+ <Stack
183
+ direction="row"
184
+ alignItems="center"
185
+ spacing={0.5}
186
+ sx={{
187
+ flex: 3,
188
+ overflow: 'hidden',
189
+ }}>
190
+ <Avatar
191
+ key={x.id}
192
+ src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 20)}
193
+ alt={x.customer?.name}
194
+ variant="circular"
195
+ sx={{ width: 20, height: 20 }}
196
+ onClick={(e) => {
197
+ e.stopPropagation();
198
+ if (x.customer?.did) {
199
+ window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
200
+ }
201
+ }}
202
+ />
203
+ <Typography
204
+ sx={{
205
+ ml: '8px !important',
206
+ fontSize: '0.875rem',
207
+ fontWeight: '500',
208
+ overflow: 'hidden',
209
+ whiteSpace: 'nowrap',
210
+ textOverflow: 'ellipsis',
211
+ }}
212
+ onClick={(e) => {
213
+ e.stopPropagation();
214
+ if (x.customer?.did) {
215
+ window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
216
+ }
217
+ }}>
218
+ {x.customer?.name}
219
+ </Typography>
220
+ </Stack>
221
+ <Stack direction="row" alignItems="center" justifyContent="flex-end" spacing={0.5} sx={{ flex: 1 }}>
222
+ <Avatar
223
+ key={x.id}
224
+ src={currency?.logo}
225
+ alt={currency?.symbol}
226
+ variant="circular"
227
+ sx={{ width: 16, height: 16 }}
228
+ />
229
+ <Typography sx={{ color: 'text.secondary' }}>{formatBNStr(x.amount_total, currency.decimal)}</Typography>
230
+ <Typography sx={{ color: 'text.secondary' }}>{currency.symbol}</Typography>
231
+ </Stack>
232
+ </Box>
233
+ ))}
234
+ </Stack>
235
+ );
236
+ }
237
+
132
238
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
133
- function SupporterAvatar({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
134
- const { t } = useLocaleContext();
239
+ function SupporterAvatar({
240
+ supporters = [],
241
+ totalAmount = '0',
242
+ currency,
243
+ method,
244
+ showDonateDetails = false,
245
+ }: DonateHistory & { showDonateDetails?: boolean }) {
246
+ const [open, setOpen] = useState(false);
135
247
  const customers = uniqBy(supporters, 'customer_did');
136
248
  const customersNum = customers.length;
249
+ if (customersNum === 0) return null;
137
250
  return (
138
- <Box
139
- display="flex"
140
- flexDirection="column"
141
- alignItems="center"
142
- sx={{
143
- '.MuiAvatar-root': {
144
- width: '32px',
145
- height: '32px',
146
- },
147
- }}
148
- gap={{
149
- xs: 0.5,
150
- sm: 1,
151
- }}>
152
- <Typography component="p" color="text.secondary">
153
- {customersNum === 0 ? (
154
- <span style={emojiFont}>{t('payment.checkout.donation.empty')}</span>
155
- ) : (
156
- t('payment.checkout.donation.summary', {
157
- total: customersNum,
158
- symbol: currency.symbol,
159
- totalAmount: formatAmount(totalAmount || '0', currency.decimal),
160
- })
161
- )}
162
- </Typography>
163
- <AvatarGroup total={customersNum} max={20}>
164
- {customers.map((x) => (
251
+ <Stack flexDirection="row" justifyContent="center" alignItems="center">
252
+ <AvatarGroup max={5}>
253
+ {customers.slice(0, 5).map((supporter) => (
165
254
  <Avatar
166
- key={x.id}
167
- title={x.customer?.name}
168
- alt={x.customer?.name}
169
- src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 48)}
170
- variant="circular"
171
- sx={{ width: 32, height: 32 }}
255
+ src={getCustomerAvatar(
256
+ supporter.customer?.did,
257
+ supporter?.updated_at ? new Date(supporter.updated_at).toISOString() : '',
258
+ 24
259
+ )}
260
+ alt={supporter.customer?.name}
261
+ key={supporter.customer?.id}
262
+ sx={{
263
+ width: '24px',
264
+ height: '24px',
265
+ }}
172
266
  />
173
267
  ))}
174
268
  </AvatarGroup>
175
- </Box>
269
+ <Box
270
+ sx={{
271
+ fontSize: '14px',
272
+ color: 'text.secondary',
273
+ pl: 1.5,
274
+ pr: 1,
275
+ ml: -1,
276
+ borderRadius: '8px',
277
+ backgroundColor: '#f4f4f5',
278
+ height: '24px',
279
+ ...(showDonateDetails
280
+ ? {
281
+ cursor: 'pointer',
282
+ '&:hover': {
283
+ backgroundColor: '#e5e7eb',
284
+ },
285
+ }
286
+ : {}),
287
+ }}
288
+ onClick={() => showDonateDetails && setOpen(true)}>
289
+ {`${customersNum} supporter${customersNum > 1 ? 's' : ''} (${formatAmount(totalAmount || '0', currency?.decimal)} ${currency.symbol})`}
290
+ </Box>
291
+ <Dialog
292
+ open={open}
293
+ onClose={() => setOpen(false)}
294
+ sx={{
295
+ '.MuiDialogContent-root': {
296
+ width: '450px',
297
+ padding: '8px',
298
+ },
299
+ }}
300
+ title={`${customersNum} supporter${customersNum > 1 ? 's' : ''}`}>
301
+ <DonateDetails supporters={supporters} currency={currency} method={method} totalAmount={totalAmount} />
302
+ </Dialog>
303
+ </Stack>
176
304
  );
177
305
  }
178
306
 
179
307
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
180
308
  function SupporterTable({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
181
- const { t } = useLocaleContext();
182
309
  const customers = uniqBy(supporters, 'customer_did');
183
310
  const customersNum = customers.length;
311
+ if (customersNum === 0) return null;
184
312
  return (
185
313
  <Box display="flex" flexDirection="column" alignItems="center" gap={{ xs: 0.5, sm: 1 }}>
186
- <Typography component="p" color="text.secondary">
187
- {customersNum === 0 ? (
188
- <span style={emojiFont}>{t('payment.checkout.donation.empty')}</span>
189
- ) : (
190
- t('payment.checkout.donation.summary', {
191
- total: customersNum,
192
- symbol: currency.symbol,
193
- totalAmount: formatAmount(totalAmount || '0', currency.decimal),
194
- })
195
- )}
196
- </Typography>
197
- <Table size="small" sx={{ width: '100%', overflow: 'hidden' }}>
198
- <TableBody>
199
- {supporters.map((x) => (
200
- <TableRow
201
- key={x.id}
202
- sx={{
203
- '> td': {
204
- padding: '8px 16px 8px 0',
205
- borderTop: '1px solid #e0e0e0',
206
- borderBottom: '1px solid #e0e0e0',
207
- },
208
- '> td:last-of-type': {
209
- paddingRight: '0',
210
- },
211
- }}>
212
- <TableCell>
213
- <Stack direction="row" alignItems="center" spacing={0.5}>
214
- <Avatar
215
- key={x.id}
216
- src={getCustomerAvatar(
217
- x.customer?.did,
218
- x?.updated_at ? new Date(x.updated_at).toISOString() : '',
219
- 48
220
- )}
221
- alt={x.customer?.name}
222
- variant="circular"
223
- sx={{ width: 24, height: 24 }}
224
- />
225
- <Hidden smDown>
226
- <Typography>{x.customer?.name}</Typography>
227
- </Hidden>
228
- </Stack>
229
- </TableCell>
230
- <TableCell align="right">
231
- <Stack direction="row" alignItems="center" justifyContent="flex-end" spacing={0.5}>
232
- <Typography fontWeight={500} component="strong">
233
- {formatBNStr(x.amount_total, currency.decimal)}
234
- </Typography>
235
- <Typography component="span">{currency.symbol}</Typography>
236
- </Stack>
237
- </TableCell>
238
- <Hidden smDown>
239
- <TableCell align="right">
240
- <Typography>{formatDateTime(x.created_at)}</Typography>
241
- </TableCell>
242
- </Hidden>
243
- <TableCell align="right">
244
- <TxLink method={method} details={x.payment_details as PaymentDetails} mode="customer" align="right" />
245
- </TableCell>
246
- </TableRow>
247
- ))}
248
- </TableBody>
249
- </Table>
314
+ <SupporterAvatar supporters={supporters} totalAmount={totalAmount} currency={currency} method={method} />
315
+ <DonateDetails supporters={supporters} totalAmount={totalAmount} currency={currency} method={method} />
250
316
  </Box>
251
317
  );
252
318
  }
@@ -300,11 +366,7 @@ const defaultDonateAmount = {
300
366
  maximum: '100',
301
367
  custom: true,
302
368
  };
303
- function useDonation(
304
- settings: RequiredDonationSettings & OptionalDonationSettings,
305
- livemode: boolean,
306
- mode = 'default'
307
- ) {
369
+ function useDonation(settings: CheckoutDonateSettings, livemode: boolean, mode = 'default') {
308
370
  const [state, setState] = useSetState({
309
371
  open: false,
310
372
  supporterLoaded: false,
@@ -425,7 +487,7 @@ function CheckoutDonateInner({
425
487
  };
426
488
 
427
489
  if (donation.error) {
428
- return <Alert severity="error">{formatError(donation.error)}</Alert>;
490
+ return null;
429
491
  }
430
492
 
431
493
  const handlePopoverOpen = (event: any) => {
@@ -523,11 +585,29 @@ function CheckoutDonateInner({
523
585
  <Button
524
586
  size={(donateSettings.appearance?.button?.size || 'medium') as any}
525
587
  color={(donateSettings.appearance?.button?.color || 'primary') as any}
526
- variant={(donateSettings.appearance?.button?.variant || 'contained') as any}
588
+ variant={(donateSettings.appearance?.button?.variant || 'outlined') as any}
589
+ sx={{
590
+ ...(!donateSettings.appearance?.button?.variant
591
+ ? {
592
+ color: 'var(--foregrounds-fg-base, #010714)',
593
+ borderColor: 'var(--stroke-button-secondary-border, #E5E7EB)',
594
+ '&:hover': {
595
+ backgroundColor: 'var(--buttons-button-neutral-hover, #F3F4F6)',
596
+ borderColor: 'var(--stroke-button-secondary-border, #E5E7EB)',
597
+ },
598
+ }
599
+ : {}),
600
+ // @ts-ignore
601
+ ...(donateSettings.appearance?.button?.sx || {}),
602
+ }}
527
603
  {...donateSettings.appearance?.button}
528
604
  onClick={() => startDonate()}>
529
605
  <Stack direction="row" alignItems="center" spacing={0.5}>
530
- {donateSettings.appearance.button.icon}
606
+ {donateSettings.appearance.button.icon && (
607
+ <Typography sx={{ mr: 0.5, display: 'inline-flex', alignItems: 'center' }}>
608
+ {donateSettings.appearance.button.icon}
609
+ </Typography>
610
+ )}
531
611
  {typeof donateSettings.appearance.button.text === 'string' ? (
532
612
  <Typography>{donateSettings.appearance.button.text}</Typography>
533
613
  ) : (
@@ -536,7 +616,7 @@ function CheckoutDonateInner({
536
616
  </Stack>
537
617
  </Button>
538
618
  {supporters.data && donateSettings.appearance.history.variant === 'avatar' && (
539
- <SupporterAvatar {...(supporters.data as DonateHistory)} />
619
+ <SupporterAvatar {...(supporters.data as DonateHistory)} showDonateDetails />
540
620
  )}
541
621
  {supporters.data && donateSettings.appearance.history.variant === 'table' && (
542
622
  <SupporterTable {...(supporters.data as DonateHistory)} />
@@ -555,7 +635,7 @@ function CheckoutDonateInner({
555
635
  `${formatAmount(
556
636
  (supporters.data as DonateHistory)?.totalAmount || '0',
557
637
  (supporters.data as DonateHistory)?.currency?.decimal
558
- )} ${(supporters.data as DonateHistory)?.currency?.symbol}`,
638
+ )} ${(supporters.data as DonateHistory)?.currency?.symbol || ''}`,
559
639
  (supporters.data as DonateHistory) || {},
560
640
  !!supporters.loading,
561
641
  donateSettings
@@ -563,7 +643,8 @@ function CheckoutDonateInner({
563
643
  </>
564
644
  ) : (
565
645
  <Typography>
566
- Please provide a valid render function <pre>{'(openDonate, donateTotalAmount, supporters) => ReactNode'}</pre>
646
+ Please provide a valid render function{' '}
647
+ <pre>{'(openDonate, donateTotalAmount, supporters, loading, donateSettings) => ReactNode'}</pre>
567
648
  </Typography>
568
649
  );
569
650
  }
@@ -19,7 +19,7 @@ export default function Livemode({ color, backgroundColor, sx }: Props) {
19
19
  height: 18,
20
20
  lineHeight: 1.2,
21
21
  textTransform: 'uppercase',
22
- fontSize: '0.8rem',
22
+ fontSize: '0.7rem',
23
23
  fontWeight: 'bold',
24
24
  borderRadius: '4px',
25
25
  backgroundColor,
@@ -0,0 +1,100 @@
1
+ import {
2
+ Button,
3
+ type ButtonProps,
4
+ CircularProgress,
5
+ type CircularProgressProps,
6
+ SxProps,
7
+ Theme,
8
+ Typography,
9
+ } from '@mui/material';
10
+ import { forwardRef } from 'react';
11
+
12
+ export interface LoadingButtonProps extends ButtonProps {
13
+ loading?: boolean;
14
+ loadingIndicator?: React.ReactNode;
15
+ loadingPosition?: 'start' | 'center' | 'end';
16
+ loadingProps?: Partial<CircularProgressProps>;
17
+ loadingOnly?: boolean;
18
+ }
19
+
20
+ const LoadingButton = forwardRef<HTMLButtonElement, LoadingButtonProps>(
21
+ (
22
+ {
23
+ children,
24
+ loading,
25
+ loadingPosition = 'start',
26
+ loadingIndicator,
27
+ loadingProps = {},
28
+ onClick,
29
+ sx,
30
+ loadingOnly = false,
31
+ ...props
32
+ },
33
+ ref
34
+ ) => {
35
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
36
+ if (loading) {
37
+ return;
38
+ }
39
+ onClick?.(e);
40
+ };
41
+
42
+ const getPositionStyles = (position: string) => {
43
+ return {
44
+ color: 'inherit',
45
+ ...(position === 'start' && { mr: 1 }),
46
+ ...(position === 'end' && { ml: 1 }),
47
+ ...(position === 'center' && {
48
+ position: 'absolute',
49
+ left: '50%',
50
+ transform: 'translateY(-50%) translateX(-50%)',
51
+ top: '50%',
52
+ }),
53
+ display: 'inline-flex',
54
+ alignItems: 'center',
55
+ } as const;
56
+ };
57
+
58
+ const defaultIndicator = (
59
+ <CircularProgress size={16} {...loadingProps} sx={{ color: 'inherit', ...(loadingProps?.sx || {}) }} />
60
+ );
61
+
62
+ const indicator = (
63
+ <Typography sx={getPositionStyles(loadingPosition) as SxProps<Theme>}>
64
+ {loadingIndicator || defaultIndicator}
65
+ </Typography>
66
+ );
67
+
68
+ return (
69
+ <Button
70
+ ref={ref}
71
+ disabled={props.disabled}
72
+ onClick={handleClick}
73
+ sx={{
74
+ position: 'relative',
75
+ display: 'inline-flex',
76
+ alignItems: 'center',
77
+ justifyContent: 'center',
78
+ ...sx,
79
+ }}
80
+ {...props}>
81
+ {loading && loadingPosition === 'start' && indicator}
82
+ <Typography sx={{ visibility: loading && loadingOnly ? 'hidden' : 'visible' }}>{children}</Typography>
83
+ {loading && loadingPosition === 'center' && indicator}
84
+ {loading && loadingPosition === 'end' && indicator}
85
+ </Button>
86
+ );
87
+ }
88
+ );
89
+
90
+ LoadingButton.displayName = 'LoadingButton';
91
+
92
+ LoadingButton.defaultProps = {
93
+ loading: false,
94
+ loadingIndicator: undefined,
95
+ loadingPosition: 'start',
96
+ loadingProps: {},
97
+ loadingOnly: false,
98
+ };
99
+
100
+ export default LoadingButton;
@@ -3,7 +3,6 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
3
  import Toast from '@arcblock/ux/lib/Toast';
4
4
  import type { PriceCurrency, PriceRecurring, TPricingTableExpanded, TPricingTableItem } from '@blocklet/payment-types';
5
5
  import { CheckOutlined } from '@mui/icons-material';
6
- import { LoadingButton } from '@mui/lab';
7
6
  import {
8
7
  Avatar,
9
8
  Box,
@@ -36,6 +35,7 @@ import {
36
35
  } from '../libs/util';
37
36
  import { useMobile } from '../hooks/mobile';
38
37
  import TruncatedText from './truncated-text';
38
+ import LoadingButton from './loading-button';
39
39
 
40
40
  type SortOrder = { [key: string]: number };
41
41
 
@@ -322,7 +322,6 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
322
322
  justifyContent={alignItems === 'center' ? 'center' : 'flex-start'}
323
323
  sx={{
324
324
  flex: '0 1 auto',
325
- overflow: 'auto',
326
325
  pb: 2.5,
327
326
  }}
328
327
  className="price-table-wrap">
@@ -354,7 +353,8 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
354
353
  '0px 0px 0px 1px rgba(3, 7, 18, 0.08), 0px 1px 2px -1px rgba(3, 7, 18, 0.08), 0px 2px 4px rgba(3, 7, 18, 0.04)',
355
354
  '&:hover': {
356
355
  borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#ddd',
357
- boxShadow: '0 8px 16px rgba(0, 0, 0, 20%)',
356
+ boxShadow:
357
+ '0px 0px 0px 1px var(--shadows-card-hover-1, rgba(2, 7, 19, 0.08)),0px 1px 2px -1px var(--shadows-card-hover-2, rgba(2, 7, 19, 0.08)),0px 2px 8px 0px var(--shadows-card-hover-3, rgba(2, 7, 19, 0.10))',
358
358
  },
359
359
  width: {
360
360
  xs: '100%',
@@ -71,7 +71,7 @@ const Wrapped = styled(Datatable)`
71
71
  ${(props: any) =>
72
72
  props?.hasRowLink
73
73
  ? `.MuiTableCell-root {
74
- font-size: 1rem !important;
74
+ font-size: 0.875rem !important;
75
75
  }`
76
76
  : ''}
77
77
  .MuiPaper-root {
package/src/index.ts CHANGED
@@ -30,6 +30,7 @@ import Link from './components/link';
30
30
  import { createLazyComponent } from './components/lazy-loader';
31
31
  import OverdueInvoicePayment from './components/over-due-invoice-payment';
32
32
  import PaymentBeneficiaries from './components/payment-beneficiaries';
33
+ import LoadingButton from './components/loading-button';
33
34
 
34
35
  export { PaymentThemeProvider } from './theme';
35
36
 
@@ -79,4 +80,5 @@ export {
79
80
  Link,
80
81
  OverdueInvoicePayment,
81
82
  PaymentBeneficiaries,
83
+ LoadingButton,
82
84
  };
package/src/libs/util.ts CHANGED
@@ -22,7 +22,7 @@ import numbro from 'numbro';
22
22
  // eslint-disable-next-line import/no-extraneous-dependencies
23
23
  import stringWidth from 'string-width';
24
24
  import { defaultCountries } from 'react-international-phone';
25
- import { joinURL } from 'ufo';
25
+ import { joinURL, withQuery } from 'ufo';
26
26
 
27
27
  import { t } from '../locales';
28
28
  import dayjs from './dayjs';
@@ -1184,3 +1184,13 @@ export function openDonationSettings(openInNewTab: boolean = false) {
1184
1184
  window.open(`${window.location.origin}${mountPoint}/integrations/donations`, openInNewTab ? '_blank' : '_self');
1185
1185
  }
1186
1186
  }
1187
+
1188
+ export function getUserProfileLink(userDid: string, locale = 'en') {
1189
+ return joinURL(
1190
+ window.location.origin,
1191
+ withQuery('.well-known/service/user', {
1192
+ locale,
1193
+ did: userDid,
1194
+ })
1195
+ );
1196
+ }
@@ -10,7 +10,7 @@ export default function PaymentAmount({ amount, sx }: Props) {
10
10
  sx={{
11
11
  my: 0.5,
12
12
  fontWeight: 600,
13
- fontSize: '2.5rem',
13
+ fontSize: '2.1875rem',
14
14
  letterSpacing: '-0.03rem',
15
15
  fontVariantNumeric: 'tabular-nums',
16
16
  ...sx,