payment-kit 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 (79) hide show
  1. package/blocklet.yml +1 -1
  2. package/package.json +19 -19
  3. package/src/app.tsx +13 -12
  4. package/src/components/balance-list.tsx +12 -2
  5. package/src/components/copyable.tsx +3 -2
  6. package/src/components/customer/edit.tsx +25 -21
  7. package/src/components/customer/form.tsx +18 -28
  8. package/src/components/customer/link.tsx +1 -2
  9. package/src/components/date-range-picker.tsx +21 -0
  10. package/src/components/drawer-form.tsx +27 -4
  11. package/src/components/event/list.tsx +3 -2
  12. package/src/components/filter-toolbar.tsx +11 -4
  13. package/src/components/info-card.tsx +4 -2
  14. package/src/components/info-metric.tsx +2 -2
  15. package/src/components/info-row.tsx +33 -26
  16. package/src/components/invoice/list.tsx +2 -2
  17. package/src/components/invoice/table.tsx +148 -85
  18. package/src/components/invoice-pdf/pdf.tsx +5 -1
  19. package/src/components/layout/admin.tsx +8 -2
  20. package/src/components/metadata/editor.tsx +25 -18
  21. package/src/components/metadata/form.tsx +83 -25
  22. package/src/components/metadata/list.tsx +22 -6
  23. package/src/components/payment-intent/list.tsx +3 -3
  24. package/src/components/payment-link/preview.tsx +42 -24
  25. package/src/components/payouts/list.tsx +2 -3
  26. package/src/components/price/form.tsx +27 -12
  27. package/src/components/price/upsell.tsx +1 -4
  28. package/src/components/pricing-table/preview.tsx +42 -23
  29. package/src/components/product/cross-sell-select.tsx +1 -1
  30. package/src/components/product/cross-sell.tsx +3 -4
  31. package/src/components/product/edit-price.tsx +0 -1
  32. package/src/components/refund/list.tsx +9 -4
  33. package/src/components/section/header.tsx +11 -4
  34. package/src/components/subscription/description.tsx +10 -6
  35. package/src/components/subscription/items/index.tsx +28 -6
  36. package/src/components/subscription/list.tsx +2 -2
  37. package/src/components/subscription/metrics.tsx +10 -8
  38. package/src/components/subscription/portal/actions.tsx +37 -11
  39. package/src/components/subscription/portal/list.tsx +131 -70
  40. package/src/components/subscription/status.tsx +9 -3
  41. package/src/global.css +1 -1
  42. package/src/hooks/mobile.ts +3 -3
  43. package/src/libs/util.ts +6 -2
  44. package/src/locales/en.tsx +37 -1
  45. package/src/locales/zh.tsx +37 -1
  46. package/src/pages/admin/billing/index.tsx +24 -4
  47. package/src/pages/admin/billing/invoices/detail.tsx +302 -147
  48. package/src/pages/admin/billing/subscriptions/detail.tsx +259 -134
  49. package/src/pages/admin/customers/customers/detail.tsx +358 -175
  50. package/src/pages/admin/customers/customers/index.tsx +8 -5
  51. package/src/pages/admin/customers/index.tsx +22 -5
  52. package/src/pages/admin/developers/webhooks/index.tsx +2 -2
  53. package/src/pages/admin/index.tsx +24 -10
  54. package/src/pages/admin/overview.tsx +1 -1
  55. package/src/pages/admin/payments/index.tsx +22 -7
  56. package/src/pages/admin/payments/intents/detail.tsx +263 -121
  57. package/src/pages/admin/payments/payouts/detail.tsx +235 -102
  58. package/src/pages/admin/payments/refunds/detail.tsx +286 -133
  59. package/src/pages/admin/products/index.tsx +28 -12
  60. package/src/pages/admin/products/links/create.tsx +16 -6
  61. package/src/pages/admin/products/links/detail.tsx +280 -176
  62. package/src/pages/admin/products/links/index.tsx +4 -7
  63. package/src/pages/admin/products/passports/index.tsx +6 -3
  64. package/src/pages/admin/products/prices/detail.tsx +260 -139
  65. package/src/pages/admin/products/prices/list.tsx +7 -3
  66. package/src/pages/admin/products/pricing-tables/create.tsx +17 -5
  67. package/src/pages/admin/products/pricing-tables/detail.tsx +221 -121
  68. package/src/pages/admin/products/pricing-tables/index.tsx +1 -2
  69. package/src/pages/admin/products/products/detail.tsx +262 -119
  70. package/src/pages/admin/products/products/index.tsx +1 -2
  71. package/src/pages/admin/settings/index.tsx +27 -7
  72. package/src/pages/customer/index.tsx +431 -143
  73. package/src/pages/customer/invoice/detail.tsx +138 -26
  74. package/src/pages/customer/refund/list.tsx +193 -4
  75. package/src/pages/customer/subscription/change-payment.tsx +20 -20
  76. package/src/pages/customer/subscription/detail.tsx +168 -34
  77. package/src/pages/customer/subscription/embed.tsx +22 -19
  78. package/src/pages/home.tsx +7 -1
  79. package/src/components/table.tsx +0 -93
@@ -3,25 +3,27 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
3
  import { CustomerInvoiceList, TxLink, api, formatTime } from '@blocklet/payment-react';
4
4
  import type { TSubscriptionExpanded } from '@blocklet/payment-types';
5
5
  import { ArrowBackOutlined } from '@mui/icons-material';
6
- import { Alert, Box, Button, CircularProgress, Stack, Typography } from '@mui/material';
6
+ import { Alert, Box, Button, CircularProgress, Divider, Stack, Typography } from '@mui/material';
7
7
  import { useRequest } from 'ahooks';
8
8
  import { Link, useParams } from 'react-router-dom';
9
9
 
10
+ import { styled } from '@mui/system';
10
11
  import Currency from '../../../components/currency';
11
12
  import CustomerLink from '../../../components/customer/link';
12
13
  import InfoRow from '../../../components/info-row';
13
- import SectionHeader from '../../../components/section/header';
14
14
  import SubscriptionDescription from '../../../components/subscription/description';
15
15
  import SubscriptionItemList from '../../../components/subscription/items';
16
16
  import SubscriptionMetrics from '../../../components/subscription/metrics';
17
17
  import SubscriptionActions from '../../../components/subscription/portal/actions';
18
- import SubscriptionStatus from '../../../components/subscription/status';
19
18
  import { canChangePaymentMethod, goBackOrFallback } from '../../../libs/util';
20
19
 
21
20
  const fetchData = (id: string | undefined): Promise<TSubscriptionExpanded> => {
22
21
  return api.get(`/api/subscriptions/${id}`).then((res) => res.data);
23
22
  };
24
23
 
24
+ const InfoDirection = 'column';
25
+ const InfoAlignItems = 'flex-start';
26
+
25
27
  export default function CustomerSubscriptionDetail() {
26
28
  const { id } = useParams() as { id: string };
27
29
  const { t } = useLocaleContext();
@@ -36,58 +38,140 @@ export default function CustomerSubscriptionDetail() {
36
38
  }
37
39
 
38
40
  return (
39
- <Stack direction="column" spacing={4} sx={{ mb: 4 }}>
41
+ <Root>
40
42
  <Box>
41
43
  <Stack
42
44
  className="page-header"
43
45
  direction="row"
44
46
  justifyContent="space-between"
45
47
  alignItems="center"
46
- sx={{ position: 'relative' }}>
48
+ sx={{ position: 'relative', mt: '16px' }}>
47
49
  <Stack
48
50
  direction="row"
49
51
  onClick={() => goBackOrFallback('/customer')}
50
52
  alignItems="center"
51
- sx={{ fontWeight: 'normal', mt: '16px', cursor: 'pointer' }}>
53
+ sx={{ fontWeight: 'normal', cursor: 'pointer' }}>
52
54
  <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
53
55
  <Typography variant="h6" sx={{ color: 'text.secondary', fontWeight: 'normal' }}>
54
56
  {t('payment.customer.subscriptions.title')}
55
57
  </Typography>
56
58
  </Stack>
59
+ <SubscriptionActions
60
+ subscription={data}
61
+ onChange={() => refresh()}
62
+ showExtra
63
+ actionProps={{
64
+ cancel: {
65
+ variant: 'outlined',
66
+ color: 'primary',
67
+ },
68
+ recover: {
69
+ variant: 'outlined',
70
+ color: 'info',
71
+ },
72
+ pastDue: {
73
+ variant: 'outlined',
74
+ color: 'primary',
75
+ },
76
+ }}
77
+ />
57
78
  </Stack>
58
- <Box mt={2}>
79
+ <Box
80
+ mt={4}
81
+ sx={{
82
+ display: 'flex',
83
+ gap: {
84
+ xs: 2,
85
+ sm: 2,
86
+ md: 5,
87
+ },
88
+ flexWrap: 'wrap',
89
+ flexDirection: {
90
+ xs: 'column',
91
+ sm: 'column',
92
+ md: 'row',
93
+ },
94
+ alignItems: {
95
+ xs: 'flex-start',
96
+ sm: 'flex-start',
97
+ md: 'center',
98
+ },
99
+ }}>
59
100
  <Stack direction="row" justifyContent="space-between" alignItems="center">
60
- <Stack direction="row" alignItems="center">
61
- <SubscriptionDescription subscription={data} variant="h5" />
62
- <SubscriptionStatus subscription={data} sx={{ ml: 1 }} />
101
+ <Stack direction="row" alignItems="center" flexWrap="wrap" gap={1}>
102
+ <SubscriptionDescription subscription={data} variant="h1" />
63
103
  </Stack>
64
- <SubscriptionActions subscription={data} onChange={() => refresh()} showExtra />
65
104
  </Stack>
66
105
  <Stack
67
106
  className="section-body"
68
- direction="row"
69
- spacing={3}
70
107
  justifyContent="flex-start"
71
108
  flexWrap="wrap"
72
- sx={{ pt: 2, mt: 2, borderTop: '1px solid #eee' }}>
109
+ sx={{
110
+ 'hr.MuiDivider-root:last-child': {
111
+ display: 'none',
112
+ },
113
+ flexDirection: {
114
+ xs: 'column',
115
+ sm: 'column',
116
+ md: 'row',
117
+ },
118
+ alignItems: {
119
+ xs: 'flex-start',
120
+ sm: 'flex-start',
121
+ md: 'center',
122
+ },
123
+ gap: {
124
+ xs: 1,
125
+ sm: 1,
126
+ md: 3,
127
+ },
128
+ }}>
73
129
  <SubscriptionMetrics subscription={data} />
74
130
  </Stack>
75
131
  </Box>
76
132
  </Box>
77
-
133
+ <Divider />
78
134
  <Box className="section">
79
- <SectionHeader title={t('admin.details')} />
80
- <Stack>
81
- <InfoRow label={t('common.customer')} value={<CustomerLink customer={data.customer} linked={false} />} />
82
- <InfoRow label={t('common.createdAt')} value={formatTime(data.created_at)} />
135
+ <Typography variant="h3" mb={3} className="section-header">
136
+ {t('admin.details')}
137
+ </Typography>
138
+ <Box
139
+ sx={{
140
+ display: 'grid',
141
+ gridTemplateColumns: {
142
+ xs: 'repeat(1, 1fr)',
143
+ sm: 'repeat(1, 1fr)',
144
+ md: 'repeat(2, 1fr)',
145
+ lg: 'repeat(3, 1fr)',
146
+ },
147
+ }}>
148
+ <InfoRow
149
+ label={t('common.customer')}
150
+ value={<CustomerLink customer={data.customer} linked={false} />}
151
+ direction={InfoDirection}
152
+ alignItems={InfoAlignItems}
153
+ />
154
+ <InfoRow
155
+ label={t('common.createdAt')}
156
+ value={formatTime(data.created_at)}
157
+ direction={InfoDirection}
158
+ alignItems={InfoAlignItems}
159
+ />
83
160
  {data.status === 'paused' && !!data.pause_collection?.resumes_at && (
84
- <InfoRow label={t('common.resumesAt')} value={formatTime(data.pause_collection.resumes_at * 1000)} />
161
+ <InfoRow
162
+ label={t('common.resumesAt')}
163
+ value={formatTime(data.pause_collection.resumes_at * 1000)}
164
+ direction={InfoDirection}
165
+ alignItems={InfoAlignItems}
166
+ />
85
167
  )}
86
168
  <InfoRow
87
169
  label={t('admin.subscription.currentPeriod')}
88
170
  value={[formatTime(data.current_period_start * 1000), formatTime(data.current_period_end * 1000)].join(
89
171
  ' ~ '
90
172
  )}
173
+ direction={InfoDirection}
174
+ alignItems={InfoAlignItems}
91
175
  />
92
176
  <InfoRow
93
177
  label={t('admin.subscription.trialingPeriod')}
@@ -96,12 +180,26 @@ export default function CustomerSubscriptionDetail() {
96
180
  ? [formatTime(data.trial_start * 1000), formatTime(data.trial_end * 1000)].join(' ~ ')
97
181
  : ''
98
182
  }
183
+ direction={InfoDirection}
184
+ alignItems={InfoAlignItems}
185
+ />
186
+ <InfoRow
187
+ label={t('admin.subscription.discount')}
188
+ value={data.discount_id ? data.discount_id : ''}
189
+ direction={InfoDirection}
190
+ alignItems={InfoAlignItems}
191
+ />
192
+ <InfoRow
193
+ label={t('admin.subscription.collectionMethod')}
194
+ value={data.collection_method}
195
+ direction={InfoDirection}
196
+ alignItems={InfoAlignItems}
99
197
  />
100
- <InfoRow label={t('admin.subscription.discount')} value={data.discount_id ? data.discount_id : ''} />
101
- <InfoRow label={t('admin.subscription.collectionMethod')} value={data.collection_method} />
102
198
  <InfoRow
103
199
  label={t('admin.paymentMethod._name')}
104
200
  value={<Currency logo={data.paymentMethod.logo} name={data.paymentMethod.name} />}
201
+ alignItems={InfoAlignItems}
202
+ direction={InfoDirection}
105
203
  />
106
204
  <InfoRow
107
205
  label={t('admin.paymentCurrency.name')}
@@ -110,8 +208,8 @@ export default function CustomerSubscriptionDetail() {
110
208
  <Currency logo={data.paymentCurrency.logo} name={data.paymentCurrency.symbol} />
111
209
  {canChangePaymentMethod(data) && (
112
210
  <Button
113
- color="primary"
114
- variant="outlined"
211
+ variant="text"
212
+ sx={{ color: 'text.link' }}
115
213
  size="small"
116
214
  component={Link}
117
215
  to={`/customer/subscription/${data.id}/change-payment`}>
@@ -120,22 +218,35 @@ export default function CustomerSubscriptionDetail() {
120
218
  )}
121
219
  </Stack>
122
220
  }
221
+ direction={InfoDirection}
222
+ alignItems={InfoAlignItems}
123
223
  />
124
224
  {(data.payment_details?.arcblock?.tx_hash || data.payment_details?.ethereum?.tx_hash) && (
125
225
  <InfoRow
126
226
  label={t('common.delegateTxHash')}
127
227
  value={<TxLink details={data.payment_details} method={data.paymentMethod} />}
228
+ direction={InfoDirection}
229
+ alignItems={InfoAlignItems}
128
230
  />
129
231
  )}
130
232
  {data.payment_details?.arcblock?.staking?.tx_hash && (
131
233
  <InfoRow
132
234
  label={t('common.stakeTxHash')}
133
235
  value={
134
- <TxLink
135
- details={{ arcblock: { tx_hash: data.payment_details?.arcblock?.staking?.tx_hash, payer: '' } }}
136
- method={data.paymentMethod}
137
- />
236
+ <Box
237
+ sx={{
238
+ '.MuiTypography-root': {
239
+ color: 'text.link',
240
+ },
241
+ }}>
242
+ <TxLink
243
+ details={{ arcblock: { tx_hash: data.payment_details?.arcblock?.staking?.tx_hash, payer: '' } }}
244
+ method={data.paymentMethod}
245
+ />
246
+ </Box>
138
247
  }
248
+ direction={InfoDirection}
249
+ alignItems={InfoAlignItems}
139
250
  />
140
251
  )}
141
252
  {!!data.recovered_from && (
@@ -146,23 +257,46 @@ export default function CustomerSubscriptionDetail() {
146
257
  {data.recovered_from}
147
258
  </Link>
148
259
  }
260
+ direction={InfoDirection}
261
+ alignItems={InfoAlignItems}
149
262
  />
150
263
  )}
151
- </Stack>
264
+ </Box>
152
265
  </Box>
153
-
266
+ <Divider />
154
267
  <Box className="section">
155
- <SectionHeader title={t('admin.products')} mb={0} />
268
+ <Typography variant="h3" mb={1.5} className="section-header">
269
+ {t('admin.products')}
270
+ </Typography>
156
271
  <Box className="section-body">
157
272
  <SubscriptionItemList data={data.items} currency={data.paymentCurrency} mode="customer" />
158
273
  </Box>
159
274
  </Box>
275
+ <Divider />
160
276
  <Box className="section">
161
- <SectionHeader title={t('admin.invoices')} mb={0} />
277
+ <Typography variant="h3" className="section-header">
278
+ {t('customer.invoiceHistory')}
279
+ </Typography>
162
280
  <Box className="section-body">
163
- <CustomerInvoiceList subscription_id={data.id} include_staking />
281
+ <CustomerInvoiceList subscription_id={data.id} include_staking type="table" />
164
282
  </Box>
165
283
  </Box>
166
- </Stack>
284
+ </Root>
167
285
  );
168
286
  }
287
+
288
+ const Root = styled(Stack)`
289
+ margin-bottom: 24px;
290
+ gap: 24px;
291
+ flex-direction: column;
292
+ @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
293
+ . {
294
+ border: none;
295
+ box-shadow: none;
296
+ padding: 0;
297
+ }
298
+ .section-header {
299
+ font-size: 18px;
300
+ }
301
+ }
302
+ `;
@@ -190,32 +190,34 @@ export default function SubscriptionEmbed() {
190
190
  </List>
191
191
  </Box>
192
192
  <Divider />
193
- <Box sx={{ marginTop: '12px', flex: 1 }}>
194
- <List sx={{ overflow: 'auto' }} className="mini-invoice-list">
193
+ <Box sx={{ marginTop: '12px', flex: 1, overflow: 'hidden' }}>
194
+ <List sx={{ height: '100%', display: 'flex', flexDirection: 'column' }} className="mini-invoice-list">
195
195
  <ListSubheader disableGutters sx={{ padding: 0 }}>
196
196
  <Typography component="h2" variant="h6" fontSize="16px">
197
197
  {t('payment.customer.invoices')}
198
198
  </Typography>
199
199
  </ListSubheader>
200
200
  {(invoices as any).length === 0 ? (
201
- <Typography color="text.secondary">{t('payment.customer.invoice.empty')}</Typography>
201
+ <Typography color="text.lighter">{t('payment.customer.invoice.empty')}</Typography>
202
202
  ) : (
203
- (invoices as any).map((item: any) => {
204
- return (
205
- <ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
206
- <Typography component="span" sx={{ flex: 3 }}>
207
- {formatToDate(item.created_at, locale, 'YYYY-MM-DD')}
208
- </Typography>
209
- <Typography component="span" sx={{ flex: 1, textAlign: 'right' }}>
210
- {formatBNStr(item.total, item.paymentCurrency.decimal)}&nbsp;
211
- {item.paymentCurrency.symbol}
212
- </Typography>
213
- <Typography component="span" sx={{ flex: 2, textAlign: 'right' }}>
214
- <Status label={item.status} color={getInvoiceStatusColor(item.status)} />
215
- </Typography>
216
- </ListItem>
217
- );
218
- })
203
+ <Box sx={{ flex: 1, overflow: 'auto' }}>
204
+ {(invoices as any).map((item: any) => {
205
+ return (
206
+ <ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
207
+ <Typography component="span" sx={{ flex: 3 }}>
208
+ {formatToDate(item.created_at, locale, 'YYYY-MM-DD')}
209
+ </Typography>
210
+ <Typography component="span" sx={{ flex: 1, textAlign: 'right' }}>
211
+ {formatBNStr(item.total, item.paymentCurrency.decimal)}&nbsp;
212
+ {item.paymentCurrency.symbol}
213
+ </Typography>
214
+ <Typography component="span" sx={{ flex: 2, textAlign: 'right' }}>
215
+ <Status label={item.status} color={getInvoiceStatusColor(item.status)} />
216
+ </Typography>
217
+ </ListItem>
218
+ );
219
+ })}
220
+ </Box>
219
221
  )}
220
222
  </List>
221
223
  </Box>
@@ -257,6 +259,7 @@ function Position({ children }: any) {
257
259
  maxWidth: '500px',
258
260
  background: '#fff',
259
261
  margin: '0 auto',
262
+ height: '100%',
260
263
  }}>
261
264
  {children}
262
265
  </Box>
@@ -34,7 +34,13 @@ function Home() {
34
34
  <Button variant="outlined" color="secondary" size="large" component={Link} to="/admin/overview">
35
35
  Admin Dashboard
36
36
  </Button>
37
- <Button variant="outlined" color="primary" size="large" component={Link} to="/customer">
37
+ <Button
38
+ variant="outlined"
39
+ color="primary"
40
+ size="large"
41
+ component={Link}
42
+ to="/customer"
43
+ sx={{ background: 'transparent' }}>
38
44
  Customer Portal
39
45
  </Button>
40
46
  </Stack>
@@ -1,93 +0,0 @@
1
- import Datatable from '@arcblock/ux/lib/Datatable';
2
- import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { styled } from '@mui/system';
4
-
5
- import useMobile from '../hooks/mobile';
6
-
7
- function EmptyStub() {
8
- return null;
9
- }
10
-
11
- export default function Table({ options, columns, toolbar = true, footer = true, hasRowLink = false, ...rest }: any) {
12
- const { isMobile } = useMobile();
13
- const { locale } = useLocaleContext();
14
-
15
- const defaultOptions = {
16
- print: false,
17
- download: false,
18
- filter: false,
19
- selectableRows: 'none',
20
- rowsPerPage: 10,
21
- rowsPerPageOptions: [10, 20, 50, 100],
22
- searchDebounceTime: 300,
23
- tableBodyHeight: '100%',
24
- loading: true,
25
- };
26
-
27
- const components: any = {};
28
- if (!toolbar) {
29
- components.TableToolbar = EmptyStub;
30
- }
31
- if (!footer) {
32
- components.TableFooter = EmptyStub;
33
- }
34
-
35
- // components.TableHead = EmptyStub2
36
-
37
- return (
38
- <Wrapped
39
- locale={locale}
40
- options={{ ...defaultOptions, ...options }}
41
- columns={columns.map((x: any) => {
42
- x.options = x.options || {};
43
- x.options.filter = x.options.filter || false;
44
- x.options.sort = x.options.sort || false;
45
- return x;
46
- })}
47
- {...rest}
48
- components={components}
49
- hasRowLink={hasRowLink}
50
- isMobile={isMobile}
51
- />
52
- );
53
- }
54
-
55
- const Wrapped = styled(Datatable)`
56
- ${(props) =>
57
- props.hasRowLink
58
- ? `.MuiTableCell-root {
59
- font-size: 1rem !important;
60
- padding: 0;
61
- }`
62
- : ''}
63
-
64
- th.MuiTableCell-head {
65
- padding: 8px 24px 8px 0;
66
- }
67
-
68
- tr.MuiTableRow-root:not(.MuiTableRow-footer) {
69
- border-bottom: 1px solid rgba(224, 224, 224, 0.4);
70
- }
71
-
72
- th.MuiTableCell-head {
73
- text-transform: inherit;
74
- }
75
-
76
- tr.MuiTableRow-root:not(.MuiTableRow-footer):hover {
77
- background: #f5f5f5;
78
- }
79
-
80
- th a,
81
- td a {
82
- text-decoration: none;
83
- display: block;
84
- color: inherit;
85
- padding-top: 8px;
86
- padding-bottom: 8px;
87
- padding-right: 24px;
88
- }
89
-
90
- > div {
91
- overflow: visible;
92
- }
93
- `;