payment-kit 1.17.12 → 1.18.1

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 (41) hide show
  1. package/api/src/integrations/arcblock/stake.ts +0 -5
  2. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +254 -0
  3. package/api/src/libs/notification/template/customer-reward-succeeded.ts +12 -11
  4. package/api/src/libs/payment.ts +47 -2
  5. package/api/src/libs/payout.ts +24 -0
  6. package/api/src/libs/util.ts +83 -1
  7. package/api/src/locales/en.ts +16 -1
  8. package/api/src/locales/zh.ts +28 -12
  9. package/api/src/queues/notification.ts +23 -1
  10. package/api/src/routes/invoices.ts +42 -5
  11. package/api/src/routes/payment-intents.ts +14 -1
  12. package/api/src/routes/payment-links.ts +17 -0
  13. package/api/src/routes/payment-methods.ts +28 -1
  14. package/api/src/routes/payouts.ts +103 -8
  15. package/api/src/store/migrations/20250206-update-donation-products.ts +56 -0
  16. package/api/src/store/models/payout.ts +6 -2
  17. package/api/src/store/models/types.ts +2 -0
  18. package/blocklet.yml +1 -1
  19. package/package.json +4 -4
  20. package/public/methods/default.png +0 -0
  21. package/src/app.tsx +10 -0
  22. package/src/components/customer/link.tsx +11 -2
  23. package/src/components/customer/overdraft-protection.tsx +2 -2
  24. package/src/components/info-card.tsx +6 -5
  25. package/src/components/invoice/table.tsx +4 -0
  26. package/src/components/payment-method/form.tsx +4 -4
  27. package/src/components/payouts/list.tsx +17 -2
  28. package/src/components/payouts/portal/list.tsx +192 -0
  29. package/src/components/subscription/items/actions.tsx +1 -2
  30. package/src/components/uploader.tsx +1 -1
  31. package/src/libs/util.ts +42 -1
  32. package/src/locales/en.tsx +10 -0
  33. package/src/locales/zh.tsx +10 -0
  34. package/src/pages/admin/billing/invoices/detail.tsx +21 -0
  35. package/src/pages/admin/payments/payouts/detail.tsx +65 -4
  36. package/src/pages/admin/settings/payment-methods/edit.tsx +12 -1
  37. package/src/pages/customer/index.tsx +12 -25
  38. package/src/pages/customer/invoice/detail.tsx +27 -3
  39. package/src/pages/customer/payout/detail.tsx +264 -0
  40. package/src/pages/customer/recharge.tsx +2 -2
  41. package/vite.config.ts +1 -0
@@ -0,0 +1,264 @@
1
+ /* eslint-disable react/no-unstable-nested-components */
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import {
4
+ Amount,
5
+ Status,
6
+ TxLink,
7
+ api,
8
+ formatBNStr,
9
+ formatTime,
10
+ getCustomerAvatar,
11
+ getPayoutStatusColor,
12
+ } from '@blocklet/payment-react';
13
+ import type { TCustomer, TPaymentLink, TPayoutExpanded } from '@blocklet/payment-types';
14
+ import { ArrowBackOutlined } from '@mui/icons-material';
15
+ import { Alert, Avatar, Box, Button, CircularProgress, Divider, Stack, Typography } from '@mui/material';
16
+ import { styled } from '@mui/system';
17
+ import { useRequest } from 'ahooks';
18
+
19
+ import { useParams } from 'react-router-dom';
20
+ import DID from '@arcblock/ux/lib/DID';
21
+ import InfoMetric from '../../../components/info-metric';
22
+ import InfoRow from '../../../components/info-row';
23
+ import SectionHeader from '../../../components/section/header';
24
+ import { getCustomerProfileUrl, goBackOrFallback } from '../../../libs/util';
25
+ import CustomerLink from '../../../components/customer/link';
26
+ import InfoCard from '../../../components/info-card';
27
+
28
+ const fetchData = (
29
+ id: string
30
+ ): Promise<
31
+ TPayoutExpanded & {
32
+ paymentIntent?: { customer: TCustomer };
33
+ paymentLink: TPaymentLink;
34
+ }
35
+ > => {
36
+ return api.get(`/api/payouts/${id}`).then((res) => res.data);
37
+ };
38
+
39
+ const InfoDirection = 'column';
40
+ const InfoAlignItems = 'flex-start';
41
+
42
+ export default function PayoutDetail() {
43
+ const { t } = useLocaleContext();
44
+ const params = useParams<{ id: string }>();
45
+ const { loading, error, data } = useRequest(() => fetchData(params.id!), {
46
+ ready: !!params.id,
47
+ });
48
+
49
+ if (error) {
50
+ return <Alert severity="error">{error.message}</Alert>;
51
+ }
52
+
53
+ if (loading || !data) {
54
+ return <CircularProgress />;
55
+ }
56
+
57
+ const currency = data.paymentCurrency;
58
+ const total = [formatBNStr(data?.amount, currency.decimal), currency.symbol].join(' ');
59
+ const { paymentIntent, paymentLink } = data || {};
60
+ return (
61
+ <Root direction="column" spacing={2.5} mb={4}>
62
+ <Box>
63
+ <Stack className="page-header" direction="row" justifyContent="space-between" alignItems="center" mt={2}>
64
+ <Stack
65
+ direction="row"
66
+ alignItems="center"
67
+ sx={{ fontWeight: 'normal', cursor: 'pointer' }}
68
+ onClick={() => goBackOrFallback('/customer/payouts')}>
69
+ <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
70
+ <Typography variant="h6" sx={{ color: 'text.secondary', fontWeight: 'normal' }}>
71
+ {t('common.previous')}
72
+ </Typography>
73
+ </Stack>
74
+ {paymentLink?.donation_settings?.reference && (
75
+ <Button
76
+ variant="outlined"
77
+ onClick={() => {
78
+ window.open(paymentLink?.donation_settings?.reference, '_blank');
79
+ }}>
80
+ {t('customer.payout.viewReference')}
81
+ </Button>
82
+ )}
83
+ </Stack>
84
+ <Box
85
+ mt={4}
86
+ mb={3}
87
+ sx={{
88
+ display: 'flex',
89
+ gap: {
90
+ xs: 2,
91
+ sm: 2,
92
+ md: 5,
93
+ },
94
+ flexWrap: 'wrap',
95
+ flexDirection: {
96
+ xs: 'column',
97
+ sm: 'column',
98
+ md: 'row',
99
+ },
100
+ alignItems: {
101
+ xs: 'flex-start',
102
+ sm: 'flex-start',
103
+ md: 'center',
104
+ },
105
+ }}>
106
+ <Stack direction="row" justifyContent="space-between" alignItems="center">
107
+ <Stack direction="row" alignItems="center">
108
+ <Stack direction="row" alignItems="center" spacing={1}>
109
+ <Avatar
110
+ src={data.paymentCurrency.logo}
111
+ alt={data.paymentCurrency.symbol}
112
+ variant="square"
113
+ sx={{ width: '52px', height: '52px', borderRadius: 'var(--radius-s, 4px)' }}
114
+ />
115
+ <Stack direction="column" alignItems="flex-start" justifyContent="space-around">
116
+ <Amount amount={total} sx={{ my: 0, fontSize: '2rem', lineHeight: '32px' }} />
117
+ </Stack>
118
+ </Stack>
119
+ </Stack>
120
+ </Stack>
121
+ <Stack
122
+ className="section-body"
123
+ justifyContent="flex-start"
124
+ flexWrap="wrap"
125
+ sx={{
126
+ 'hr.MuiDivider-root:last-child': {
127
+ display: 'none',
128
+ },
129
+ flexDirection: {
130
+ xs: 'column',
131
+ sm: 'column',
132
+ md: 'row',
133
+ },
134
+ alignItems: {
135
+ xs: 'flex-start',
136
+ sm: 'flex-start',
137
+ md: 'center',
138
+ },
139
+ gap: {
140
+ xs: 1,
141
+ sm: 1,
142
+ md: 3,
143
+ },
144
+ }}>
145
+ <InfoMetric
146
+ label={t('common.status')}
147
+ value={<Status label={data.status} color={getPayoutStatusColor(data.status)} />}
148
+ divider
149
+ />
150
+ <InfoMetric
151
+ label={t('customer.payout.payer')}
152
+ value={
153
+ <InfoCard
154
+ logo={getCustomerAvatar(
155
+ paymentIntent?.customer?.did,
156
+ paymentIntent?.customer?.updated_at
157
+ ? new Date(paymentIntent?.customer?.updated_at).toISOString()
158
+ : '',
159
+ 48
160
+ )}
161
+ name={
162
+ <Typography
163
+ variant="subtitle2"
164
+ sx={{
165
+ cursor: 'pointer',
166
+ '&:hover': {
167
+ color: 'text.link',
168
+ },
169
+ }}
170
+ onClick={() => {
171
+ const url = getCustomerProfileUrl({
172
+ userDid: paymentIntent?.customer?.did,
173
+ locale: 'zh',
174
+ });
175
+ window.open(url, '_blank');
176
+ }}>
177
+ {paymentIntent?.customer?.name} ({paymentIntent?.customer?.email})
178
+ </Typography>
179
+ }
180
+ description={<DID did={paymentIntent?.customer?.did} />}
181
+ size={40}
182
+ variant="rounded"
183
+ />
184
+ }
185
+ divider
186
+ />
187
+ </Stack>
188
+ </Box>
189
+ <Divider />
190
+ </Box>
191
+ <Stack
192
+ sx={{
193
+ flexDirection: {
194
+ xs: 'column',
195
+ lg: 'row',
196
+ },
197
+ gap: {
198
+ xs: 2.5,
199
+ md: 4,
200
+ },
201
+ '.payment-link-column-1': {
202
+ minWidth: {
203
+ xs: '100%',
204
+ lg: '600px',
205
+ },
206
+ },
207
+ '.payment-link-column-2': {
208
+ width: {
209
+ xs: '100%',
210
+ md: '100%',
211
+ lg: '320px',
212
+ },
213
+ maxWidth: {
214
+ xs: '100%',
215
+ md: '33%',
216
+ },
217
+ },
218
+ }}>
219
+ <Box flex={1} className="payment-link-column-1" sx={{ gap: 2.5, display: 'flex', flexDirection: 'column' }}>
220
+ <Box className="section">
221
+ <SectionHeader title={t('common.detail')} />
222
+ <Stack
223
+ sx={{
224
+ display: 'grid',
225
+ gridTemplateColumns: {
226
+ xs: 'repeat(1, 1fr)',
227
+ sm: 'repeat(1, 1fr)',
228
+ md: 'repeat(2, 1fr)',
229
+ lg: 'repeat(3, 1fr)',
230
+ },
231
+ gap: {
232
+ xs: 0,
233
+ md: 2,
234
+ },
235
+ }}>
236
+ <InfoRow
237
+ label={t('common.createdAt')}
238
+ value={formatTime(data.created_at)}
239
+ direction={InfoDirection}
240
+ alignItems={InfoAlignItems}
241
+ />
242
+ {paymentIntent && paymentIntent.payment_details && (
243
+ <InfoRow
244
+ label={t('customer.payout.payTxHash')}
245
+ value={<TxLink details={paymentIntent.payment_details} method={data.paymentMethod} mode="customer" />}
246
+ direction={InfoDirection}
247
+ alignItems={InfoAlignItems}
248
+ />
249
+ )}
250
+ <InfoRow
251
+ label={t('customer.payout.receiver')}
252
+ value={<CustomerLink customer={data.customer} linked={false} />}
253
+ direction={InfoDirection}
254
+ alignItems={InfoAlignItems}
255
+ />
256
+ </Stack>
257
+ </Box>
258
+ </Box>
259
+ </Stack>
260
+ </Root>
261
+ );
262
+ }
263
+
264
+ const Root = styled(Stack)``;
@@ -366,7 +366,7 @@ export default function RechargePage() {
366
366
  boxShadow: 3,
367
367
  },
368
368
  ...(amount === presetAmount && !customAmount
369
- ? { borderColor: 'primary.main', borderWidth: 2 }
369
+ ? { borderColor: 'primary.main', borderWidth: 1 }
370
370
  : {}),
371
371
  }}>
372
372
  <CardActionArea onClick={() => handleSelect(presetAmount)} sx={{ height: '100%' }}>
@@ -401,7 +401,7 @@ export default function RechargePage() {
401
401
  transform: 'translateY(-4px)',
402
402
  boxShadow: 3,
403
403
  },
404
- ...(customAmount ? { borderColor: 'primary.main', borderWidth: 2 } : {}),
404
+ ...(customAmount ? { borderColor: 'primary.main', borderWidth: 1 } : {}),
405
405
  }}>
406
406
  <CardActionArea onClick={handleCustomSelect} sx={{ height: '100%' }}>
407
407
  <Stack direction="column" sx={{ p: 1 }} spacing={1} alignItems="center" justifyContent="center">
package/vite.config.ts CHANGED
@@ -57,6 +57,7 @@ export default defineConfig(({ mode }) => {
57
57
  mainFields: ['module', 'main'],
58
58
  resolveExtensions: ['.ts', '.tsx', '.js', '.jsx'],
59
59
  },
60
+ exclude: mode === 'development' ? ['@blocklet/payment-react', '@blocklet/payment-js'] : [],
60
61
  },
61
62
  ...(mode === 'development' && {
62
63
  resolve: {