payment-kit 1.18.16 → 1.18.18
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.
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +32 -14
- package/api/src/libs/session.ts +9 -1
- package/api/src/libs/util.ts +12 -4
- package/api/src/routes/checkout-sessions.ts +286 -120
- package/api/src/routes/connect/pay.ts +1 -1
- package/api/src/routes/connect/shared.ts +65 -6
- package/api/src/routes/customers.ts +1 -1
- package/api/src/routes/donations.ts +1 -1
- package/api/src/routes/invoices.ts +1 -1
- package/blocklet.yml +2 -1
- package/package.json +16 -16
- package/src/components/info-card.tsx +3 -1
- package/src/locales/en.tsx +1 -1
- package/src/pages/admin/payments/payouts/detail.tsx +16 -5
- package/src/pages/customer/index.tsx +71 -24
- package/src/pages/customer/invoice/past-due.tsx +1 -0
- package/src/pages/customer/payout/detail.tsx +16 -5
- package/src/pages/customer/recharge/account.tsx +204 -206
- package/src/pages/customer/recharge/subscription.tsx +11 -8
|
@@ -13,7 +13,7 @@ import { encodeApproveItx } from '../../integrations/ethereum/token';
|
|
|
13
13
|
import { blocklet, ethWallet, wallet } from '../../libs/auth';
|
|
14
14
|
import logger from '../../libs/logger';
|
|
15
15
|
import { getGasPayerExtra, getTokenLimitsForDelegation } from '../../libs/payment';
|
|
16
|
-
import { getFastCheckoutAmount, getStatementDescriptor } from '../../libs/session';
|
|
16
|
+
import { getFastCheckoutAmount, getStatementDescriptor, isDonationCheckoutSession } from '../../libs/session';
|
|
17
17
|
import {
|
|
18
18
|
expandSubscriptionItems,
|
|
19
19
|
getSubscriptionCreateSetup,
|
|
@@ -59,7 +59,7 @@ export async function ensureCheckoutSession(checkoutSessionId: string) {
|
|
|
59
59
|
return checkoutSession;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: string): Promise<Result> {
|
|
62
|
+
export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: string, skipCustomer?: boolean): Promise<Result> {
|
|
63
63
|
const checkoutSession = await ensureCheckoutSession(checkoutSessionId);
|
|
64
64
|
|
|
65
65
|
let paymentCurrencyId;
|
|
@@ -98,12 +98,69 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
|
|
|
98
98
|
paymentCurrencyId = subscription.currency_id;
|
|
99
99
|
paymentMethodId = subscription.default_payment_method_id;
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
let customer = null;
|
|
102
|
+
if (!skipCustomer) {
|
|
103
|
+
// 检查是否为打赏场景
|
|
104
|
+
const isDonation = isDonationCheckoutSession(checkoutSession);
|
|
105
|
+
|
|
106
|
+
// if donation, create customer if not exists
|
|
107
|
+
if (isDonation && !checkoutSession.customer_id && userDid) {
|
|
108
|
+
customer = await Customer.findByPkOrDid(userDid);
|
|
109
|
+
if (!customer) {
|
|
110
|
+
const { user } = await blocklet.getUser(userDid);
|
|
111
|
+
if (user) {
|
|
112
|
+
customer = await Customer.create({
|
|
113
|
+
did: userDid,
|
|
114
|
+
email: user.email,
|
|
115
|
+
name: user.fullName || userDid,
|
|
116
|
+
description: user.remark,
|
|
117
|
+
metadata: { fromDonation: true },
|
|
118
|
+
livemode: checkoutSession.livemode,
|
|
119
|
+
phone: user.phone,
|
|
120
|
+
delinquent: false,
|
|
121
|
+
balance: '0',
|
|
122
|
+
next_invoice_sequence: 1,
|
|
123
|
+
invoice_prefix: Customer.getInvoicePrefix(),
|
|
124
|
+
});
|
|
125
|
+
logger.info('Customer created for donation', { userDid, customerId: customer.id });
|
|
126
|
+
} else {
|
|
127
|
+
customer = await Customer.create({
|
|
128
|
+
did: userDid,
|
|
129
|
+
email: '',
|
|
130
|
+
name: 'anonymous',
|
|
131
|
+
description: 'Anonymous customer',
|
|
132
|
+
metadata: { fromDonation: true, anonymous: true },
|
|
133
|
+
livemode: checkoutSession.livemode,
|
|
134
|
+
phone:'',
|
|
135
|
+
delinquent: false,
|
|
136
|
+
balance: '0',
|
|
137
|
+
next_invoice_sequence: 1,
|
|
138
|
+
invoice_prefix: Customer.getInvoicePrefix(),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (customer) {
|
|
144
|
+
await checkoutSession.update({ customer_id: customer.id, customer_did: customer.did });
|
|
145
|
+
if (paymentIntent) {
|
|
146
|
+
await paymentIntent.update({ customer_id: customer.id });
|
|
147
|
+
}
|
|
148
|
+
logger.info('Customer associated with donation', {
|
|
149
|
+
userDid,
|
|
150
|
+
customerId: customer.id,
|
|
151
|
+
checkoutSessionId: checkoutSession.id,
|
|
152
|
+
paymentIntentId: paymentIntent?.id
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
// 非打赏场景或已有客户ID的情况
|
|
157
|
+
customer = await Customer.findByPk(checkoutSession.customer_id);
|
|
158
|
+
}
|
|
103
159
|
if (!customer) {
|
|
104
160
|
throw new Error('Customer not found');
|
|
105
161
|
}
|
|
106
|
-
|
|
162
|
+
|
|
163
|
+
if (userDid && !isDonation) {
|
|
107
164
|
const { user } = await blocklet.getUser(userDid, { enableConnectedAccount: true });
|
|
108
165
|
if (!user) {
|
|
109
166
|
throw new Error('Seems you have not connected to this app before');
|
|
@@ -113,6 +170,8 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
|
|
|
113
170
|
throw new Error('This is not your payment intent');
|
|
114
171
|
}
|
|
115
172
|
}
|
|
173
|
+
}
|
|
174
|
+
|
|
116
175
|
|
|
117
176
|
const [paymentMethod, paymentCurrency] = await Promise.all([
|
|
118
177
|
PaymentMethod.findByPk(paymentMethodId),
|
|
@@ -134,7 +193,7 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
|
|
|
134
193
|
return {
|
|
135
194
|
checkoutSession,
|
|
136
195
|
paymentIntent,
|
|
137
|
-
customer,
|
|
196
|
+
customer: customer as Customer,
|
|
138
197
|
subscription,
|
|
139
198
|
paymentMethod,
|
|
140
199
|
paymentCurrency,
|
|
@@ -145,7 +145,7 @@ router.get('/', async (req, res) => {
|
|
|
145
145
|
],
|
|
146
146
|
order: [['created_at', 'DESC']],
|
|
147
147
|
offset: (page - 1) * pageSize,
|
|
148
|
-
include: [{ model: Customer, as: 'customer', attributes: ['id', 'did', 'name'] }],
|
|
148
|
+
include: [{ model: Customer, as: 'customer', attributes: ['id', 'did', 'name', 'metadata'] }],
|
|
149
149
|
limit: pageSize,
|
|
150
150
|
});
|
|
151
151
|
|
|
@@ -143,7 +143,7 @@ router.get('/', authMine, async (req, res) => {
|
|
|
143
143
|
{ model: PaymentCurrency, as: 'paymentCurrency' },
|
|
144
144
|
{ model: PaymentMethod, as: 'paymentMethod' },
|
|
145
145
|
// { model: PaymentIntent, as: 'paymentIntent' },
|
|
146
|
-
|
|
146
|
+
{ model: Subscription, as: 'subscription', attributes: ['id', 'description'] },
|
|
147
147
|
{ model: Customer, as: 'customer' },
|
|
148
148
|
],
|
|
149
149
|
});
|
package/blocklet.yml
CHANGED
|
@@ -14,7 +14,7 @@ repository:
|
|
|
14
14
|
type: git
|
|
15
15
|
url: git+https://github.com/blocklet/payment-kit.git
|
|
16
16
|
specVersion: 1.2.8
|
|
17
|
-
version: 1.18.
|
|
17
|
+
version: 1.18.18
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -48,6 +48,7 @@ interfaces:
|
|
|
48
48
|
- /methods/**
|
|
49
49
|
- /currencies/**
|
|
50
50
|
blockUnauthorized: false
|
|
51
|
+
proxyBehavior: service
|
|
51
52
|
community: ''
|
|
52
53
|
documentation: ''
|
|
53
54
|
homepage: ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.18",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -43,21 +43,21 @@
|
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@abtnode/cron": "^1.16.
|
|
46
|
+
"@abtnode/cron": "^1.16.40",
|
|
47
47
|
"@arcblock/did": "^1.19.15",
|
|
48
48
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
49
|
-
"@arcblock/did-connect": "^2.12.
|
|
49
|
+
"@arcblock/did-connect": "^2.12.26",
|
|
50
50
|
"@arcblock/did-util": "^1.19.15",
|
|
51
51
|
"@arcblock/jwt": "^1.19.15",
|
|
52
|
-
"@arcblock/ux": "^2.12.
|
|
52
|
+
"@arcblock/ux": "^2.12.26",
|
|
53
53
|
"@arcblock/validator": "^1.19.15",
|
|
54
|
-
"@blocklet/js-sdk": "^1.16.
|
|
55
|
-
"@blocklet/logger": "^1.16.
|
|
56
|
-
"@blocklet/payment-react": "1.18.
|
|
57
|
-
"@blocklet/sdk": "^1.16.
|
|
58
|
-
"@blocklet/ui-react": "^2.12.
|
|
59
|
-
"@blocklet/uploader": "^0.1.
|
|
60
|
-
"@blocklet/xss": "^0.1.
|
|
54
|
+
"@blocklet/js-sdk": "^1.16.40",
|
|
55
|
+
"@blocklet/logger": "^1.16.40",
|
|
56
|
+
"@blocklet/payment-react": "1.18.18",
|
|
57
|
+
"@blocklet/sdk": "^1.16.40",
|
|
58
|
+
"@blocklet/ui-react": "^2.12.26",
|
|
59
|
+
"@blocklet/uploader": "^0.1.78",
|
|
60
|
+
"@blocklet/xss": "^0.1.30",
|
|
61
61
|
"@mui/icons-material": "^5.16.6",
|
|
62
62
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
63
63
|
"@mui/material": "^5.16.6",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"google-libphonenumber": "^3.2.38",
|
|
90
90
|
"html2canvas": "^1.4.1",
|
|
91
91
|
"iframe-resizer-react": "^1.1.1",
|
|
92
|
-
"joi": "^17.
|
|
92
|
+
"joi": "^17.12.2",
|
|
93
93
|
"json-stable-stringify": "^1.1.1",
|
|
94
94
|
"jspdf": "^2.5.2",
|
|
95
95
|
"lodash": "^4.17.21",
|
|
@@ -119,9 +119,9 @@
|
|
|
119
119
|
"web3": "^4.16.0"
|
|
120
120
|
},
|
|
121
121
|
"devDependencies": {
|
|
122
|
-
"@abtnode/types": "^1.16.
|
|
122
|
+
"@abtnode/types": "^1.16.40",
|
|
123
123
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
124
|
-
"@blocklet/payment-types": "1.18.
|
|
124
|
+
"@blocklet/payment-types": "1.18.18",
|
|
125
125
|
"@types/cookie-parser": "^1.4.7",
|
|
126
126
|
"@types/cors": "^2.8.17",
|
|
127
127
|
"@types/debug": "^4.1.12",
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
"vite": "^5.3.5",
|
|
152
152
|
"vite-node": "^2.0.4",
|
|
153
153
|
"vite-plugin-babel-import": "^2.0.5",
|
|
154
|
-
"vite-plugin-blocklet": "^0.9.
|
|
154
|
+
"vite-plugin-blocklet": "^0.9.25",
|
|
155
155
|
"vite-plugin-node-polyfills": "^0.21.0",
|
|
156
156
|
"vite-plugin-svgr": "^4.2.0",
|
|
157
157
|
"vite-tsconfig-paths": "^4.3.2",
|
|
@@ -167,5 +167,5 @@
|
|
|
167
167
|
"parser": "typescript"
|
|
168
168
|
}
|
|
169
169
|
},
|
|
170
|
-
"gitHead": "
|
|
170
|
+
"gitHead": "511a531693837c4e0784d4961f8755e5818a27d5"
|
|
171
171
|
}
|
|
@@ -10,6 +10,7 @@ type Props = {
|
|
|
10
10
|
variant?: LiteralUnion<'square' | 'rounded' | 'circular', string>;
|
|
11
11
|
sx?: SxProps;
|
|
12
12
|
className?: string;
|
|
13
|
+
logoName?: string;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export default function InfoCard(props: Props) {
|
|
@@ -18,7 +19,7 @@ export default function InfoCard(props: Props) {
|
|
|
18
19
|
return (
|
|
19
20
|
<Stack direction="row" alignItems="center" spacing={1} className={`info-card-wrapper ${props.className}`}>
|
|
20
21
|
{props.logo ? (
|
|
21
|
-
<Avatar src={props.logo} alt={avatarName} variant={props.variant as any} sx={dimensions} />
|
|
22
|
+
<Avatar src={props.logo} alt={props.logoName ?? avatarName} variant={props.variant as any} sx={dimensions} />
|
|
22
23
|
) : (
|
|
23
24
|
<Avatar variant={props.variant as any} sx={dimensions}>
|
|
24
25
|
{avatarName?.slice(0, 1)}
|
|
@@ -47,4 +48,5 @@ InfoCard.defaultProps = {
|
|
|
47
48
|
variant: 'rounded',
|
|
48
49
|
sx: {},
|
|
49
50
|
className: '',
|
|
51
|
+
logoName: '',
|
|
50
52
|
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -797,7 +797,7 @@ export default flat({
|
|
|
797
797
|
intervals: 'intervals',
|
|
798
798
|
history: 'Fund History',
|
|
799
799
|
relatedSubscriptions: 'Related Subscriptions',
|
|
800
|
-
rechargeTooltip: 'Click to
|
|
800
|
+
rechargeTooltip: 'Click to add funds',
|
|
801
801
|
},
|
|
802
802
|
delegation: {
|
|
803
803
|
title:
|
|
@@ -112,6 +112,8 @@ export default function PayoutDetail(props: { id: string }) {
|
|
|
112
112
|
return data.destination;
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
+
const isAnonymousPayer = paymentIntent?.customer?.metadata?.anonymous;
|
|
116
|
+
|
|
115
117
|
return (
|
|
116
118
|
<Root direction="column" spacing={2.5} mb={4}>
|
|
117
119
|
<Box>
|
|
@@ -206,23 +208,32 @@ export default function PayoutDetail(props: { id: string }) {
|
|
|
206
208
|
: '',
|
|
207
209
|
48
|
|
208
210
|
)}
|
|
211
|
+
logoName={paymentIntent?.customer?.metadata?.anonymous ? '' : paymentIntent?.customer?.name}
|
|
209
212
|
name={
|
|
210
213
|
<Typography
|
|
211
214
|
variant="subtitle2"
|
|
212
215
|
sx={{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
...(isAnonymousPayer
|
|
217
|
+
? {}
|
|
218
|
+
: {
|
|
219
|
+
cursor: 'pointer',
|
|
220
|
+
'&:hover': {
|
|
221
|
+
color: 'text.link',
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
217
224
|
}}
|
|
218
225
|
onClick={() => {
|
|
226
|
+
if (isAnonymousPayer) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
219
229
|
const url = getCustomerProfileUrl({
|
|
220
230
|
userDid: paymentIntent?.customer?.did,
|
|
221
231
|
locale: 'zh',
|
|
222
232
|
});
|
|
223
233
|
window.open(url, '_blank');
|
|
224
234
|
}}>
|
|
225
|
-
{paymentIntent?.customer?.name}
|
|
235
|
+
{paymentIntent?.customer?.name}
|
|
236
|
+
{paymentIntent?.customer?.email ? ` (${paymentIntent?.customer?.email})` : ''}
|
|
226
237
|
</Typography>
|
|
227
238
|
}
|
|
228
239
|
description={
|
|
@@ -8,7 +8,15 @@ import {
|
|
|
8
8
|
OverdueInvoicePayment,
|
|
9
9
|
} from '@blocklet/payment-react';
|
|
10
10
|
import type { GroupedBN, TCustomerExpanded } from '@blocklet/payment-types';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
ExpandMore,
|
|
13
|
+
AccountBalanceWalletOutlined,
|
|
14
|
+
AddOutlined,
|
|
15
|
+
CreditCardOutlined,
|
|
16
|
+
AccountBalanceOutlined,
|
|
17
|
+
InfoOutlined,
|
|
18
|
+
AssignmentReturnOutlined,
|
|
19
|
+
} from '@mui/icons-material';
|
|
12
20
|
import {
|
|
13
21
|
Avatar,
|
|
14
22
|
Box,
|
|
@@ -23,7 +31,7 @@ import {
|
|
|
23
31
|
Alert,
|
|
24
32
|
} from '@mui/material';
|
|
25
33
|
import type { SelectChangeEvent } from '@mui/material/Select';
|
|
26
|
-
import { styled
|
|
34
|
+
import { styled } from '@mui/system';
|
|
27
35
|
import { useRequest, useSetState } from 'ahooks';
|
|
28
36
|
import { flatten, isEmpty } from 'lodash';
|
|
29
37
|
import { memo, useEffect, useState } from 'react';
|
|
@@ -49,19 +57,20 @@ const CurrencyCard = memo(
|
|
|
49
57
|
label,
|
|
50
58
|
data,
|
|
51
59
|
currency,
|
|
52
|
-
sx,
|
|
53
60
|
type,
|
|
61
|
+
icon,
|
|
54
62
|
}: {
|
|
55
63
|
label: string;
|
|
56
64
|
data: {
|
|
57
65
|
[key: string]: string;
|
|
58
66
|
};
|
|
67
|
+
icon: any;
|
|
59
68
|
currency: {
|
|
60
69
|
id: string;
|
|
61
70
|
decimal: number;
|
|
62
71
|
payment_method_id: string;
|
|
72
|
+
symbol: string;
|
|
63
73
|
};
|
|
64
|
-
sx: SxProps;
|
|
65
74
|
type: 'balance' | 'spent' | 'stake' | 'refund' | 'due';
|
|
66
75
|
}) => {
|
|
67
76
|
const navigate = useNavigate();
|
|
@@ -84,17 +93,19 @@ const CurrencyCard = memo(
|
|
|
84
93
|
return (
|
|
85
94
|
<Box
|
|
86
95
|
sx={{
|
|
87
|
-
padding: '12px 16px',
|
|
88
|
-
borderRadius: 'var(--radius-m, 8px)',
|
|
89
96
|
transition: 'all 0.2s ease-in-out',
|
|
90
97
|
position: 'relative',
|
|
91
|
-
|
|
98
|
+
borderRight: '1px solid var(--stroke-border-base, #EFF1F5)',
|
|
92
99
|
}}>
|
|
93
|
-
<Typography
|
|
100
|
+
<Typography
|
|
101
|
+
variant="body1"
|
|
102
|
+
gutterBottom
|
|
103
|
+
sx={{ color: 'text.secondary', display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
104
|
+
{icon}
|
|
94
105
|
{label}
|
|
95
106
|
</Typography>
|
|
96
|
-
<Typography variant="h3" gutterBottom>
|
|
97
|
-
{value}
|
|
107
|
+
<Typography variant="h3" gutterBottom sx={{ color: 'text.primary', whiteSpace: 'nowrap' }}>
|
|
108
|
+
{value} {currency.symbol}
|
|
98
109
|
</Typography>
|
|
99
110
|
{type === 'balance' && method?.type === 'arcblock' && (
|
|
100
111
|
<Tooltip title={t('customer.recharge.rechargeTooltip')} arrow placement="top">
|
|
@@ -102,7 +113,7 @@ const CurrencyCard = memo(
|
|
|
102
113
|
onClick={handleCardClick}
|
|
103
114
|
sx={{
|
|
104
115
|
position: 'absolute',
|
|
105
|
-
top:
|
|
116
|
+
top: 0,
|
|
106
117
|
right: '12px',
|
|
107
118
|
display: 'flex',
|
|
108
119
|
alignItems: 'center',
|
|
@@ -111,8 +122,12 @@ const CurrencyCard = memo(
|
|
|
111
122
|
padding: '4px',
|
|
112
123
|
zIndex: 1,
|
|
113
124
|
cursor: 'pointer',
|
|
125
|
+
color: 'text.secondary',
|
|
126
|
+
'&:hover': {
|
|
127
|
+
color: 'text.link',
|
|
128
|
+
},
|
|
114
129
|
}}>
|
|
115
|
-
<
|
|
130
|
+
<AddOutlined fontSize="small" />
|
|
116
131
|
</Box>
|
|
117
132
|
</Tooltip>
|
|
118
133
|
)}
|
|
@@ -165,7 +180,7 @@ export default function CustomerHome() {
|
|
|
165
180
|
});
|
|
166
181
|
const navigate = useNavigate();
|
|
167
182
|
const [subscriptionStatus, setSubscriptionStatus] = useState(false);
|
|
168
|
-
const [hasSubscriptions, setHasSubscriptions] = useState(
|
|
183
|
+
const [hasSubscriptions, setHasSubscriptions] = useState(false);
|
|
169
184
|
const { startTransition } = useTransitionContext();
|
|
170
185
|
const {
|
|
171
186
|
data,
|
|
@@ -174,6 +189,24 @@ export default function CustomerHome() {
|
|
|
174
189
|
loading = true,
|
|
175
190
|
} = useRequest(fetchData, {
|
|
176
191
|
manual: true,
|
|
192
|
+
onSuccess: async (res) => {
|
|
193
|
+
if (!hasSubscriptions) {
|
|
194
|
+
const search = new URLSearchParams();
|
|
195
|
+
const searchParams = {
|
|
196
|
+
page: 1,
|
|
197
|
+
pageSize: 5,
|
|
198
|
+
showTotalCount: true,
|
|
199
|
+
customer_id: res.id,
|
|
200
|
+
};
|
|
201
|
+
Object.entries(searchParams).forEach(([key, value]) => {
|
|
202
|
+
search.set(key, String(value));
|
|
203
|
+
});
|
|
204
|
+
const { data: subscriptions } = await api.get(`/api/subscriptions?${search.toString()}`);
|
|
205
|
+
if (subscriptions.totalCount > 0 || subscriptions.count > 0) {
|
|
206
|
+
setHasSubscriptions(true);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
177
210
|
});
|
|
178
211
|
|
|
179
212
|
const loadingCard = loading || !data;
|
|
@@ -322,50 +355,64 @@ export default function CustomerHome() {
|
|
|
322
355
|
className="section-body"
|
|
323
356
|
flexDirection="row"
|
|
324
357
|
sx={{
|
|
325
|
-
gap:
|
|
358
|
+
gap: 3,
|
|
326
359
|
mt: 1.5,
|
|
327
360
|
flexWrap: 'wrap',
|
|
361
|
+
position: 'relative',
|
|
328
362
|
'>div': {
|
|
329
|
-
flex: 1,
|
|
363
|
+
flex: '1',
|
|
364
|
+
'@media (max-width: 1100px)': {
|
|
365
|
+
flex: '0 0 calc(50% - 12px)',
|
|
366
|
+
maxWidth: 'calc(50% - 12px)',
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
'&::after': {
|
|
370
|
+
content: '""',
|
|
371
|
+
position: 'absolute',
|
|
372
|
+
right: 0,
|
|
373
|
+
top: 0,
|
|
374
|
+
bottom: 0,
|
|
375
|
+
width: '1px',
|
|
376
|
+
backgroundColor: 'background.paper',
|
|
377
|
+
zIndex: 1,
|
|
330
378
|
},
|
|
331
379
|
}}>
|
|
332
380
|
<CurrencyCard
|
|
333
381
|
label={t('admin.customer.summary.balance')}
|
|
334
382
|
data={data?.summary?.token || emptyObject}
|
|
335
383
|
currency={currency}
|
|
336
|
-
sx={{
|
|
337
|
-
background: 'var(--tags-tag-orange-bg, #B7FEE3)',
|
|
338
|
-
color: 'var(--tags-tag-orange-text, #007C52)',
|
|
339
|
-
}}
|
|
340
384
|
type="balance"
|
|
385
|
+
icon={<AccountBalanceWalletOutlined color="success" fontSize="small" />}
|
|
341
386
|
/>
|
|
342
387
|
<CurrencyCard
|
|
343
388
|
label={t('admin.customer.summary.spent')}
|
|
344
389
|
data={data?.summary?.paid || emptyObject}
|
|
345
390
|
currency={currency}
|
|
346
|
-
sx={{ background: 'var(--tags-tag-green-bg, #B7FEE3)', color: 'var(--tags-tag-green-text, #007C52)' }}
|
|
347
391
|
type="spent"
|
|
392
|
+
icon={<CreditCardOutlined color="warning" fontSize="small" />}
|
|
348
393
|
/>
|
|
349
394
|
<CurrencyCard
|
|
350
395
|
label={t('admin.customer.summary.stake')}
|
|
351
396
|
data={data?.summary?.stake || emptyObject}
|
|
352
397
|
currency={currency}
|
|
353
|
-
sx={{ background: 'var(--tags-tag-blue-bg, #D2ECFF)', color: 'var(--tags-tag-blue-text, #0051E9)' }}
|
|
354
398
|
type="stake"
|
|
399
|
+
icon={<AccountBalanceOutlined fontSize="small" color="info" />}
|
|
355
400
|
/>
|
|
356
401
|
<CurrencyCard
|
|
357
402
|
label={t('admin.customer.summary.refund')}
|
|
358
403
|
data={data?.summary?.refund || emptyObject}
|
|
359
404
|
currency={currency}
|
|
360
|
-
sx={{ background: 'var(--tags-tag-purple-bg, #EFE9FF)', color: 'var(--tags-tag-purple-text, #007C52)' }}
|
|
361
405
|
type="refund"
|
|
406
|
+
icon={
|
|
407
|
+
<AssignmentReturnOutlined fontSize="small" sx={{ color: 'var(--tags-tag-purple-icon, #7c3aed)' }} />
|
|
408
|
+
}
|
|
362
409
|
/>
|
|
363
410
|
<CurrencyCard
|
|
364
411
|
label={t('admin.customer.summary.due')}
|
|
365
412
|
data={data?.summary?.due || emptyObject}
|
|
366
413
|
currency={currency}
|
|
367
|
-
sx={{ background: 'var(--tags-tag-red-bg, #FFE2E6)', color: 'var(--tags-tag-red-text, #E40031)' }}
|
|
368
414
|
type="due"
|
|
415
|
+
icon={<InfoOutlined fontSize="small" color="error" />}
|
|
369
416
|
/>
|
|
370
417
|
</Stack>
|
|
371
418
|
</>
|
|
@@ -396,7 +443,7 @@ export default function CustomerHome() {
|
|
|
396
443
|
)}
|
|
397
444
|
</Box>
|
|
398
445
|
<Box className="section-body">
|
|
399
|
-
<CustomerInvoiceList customer_id={data?.id} type="table" include_staking />
|
|
446
|
+
<CustomerInvoiceList customer_id={data?.id} type="table" include_staking relatedSubscription />
|
|
400
447
|
</Box>
|
|
401
448
|
</Box>
|
|
402
449
|
);
|
|
@@ -59,6 +59,8 @@ export default function PayoutDetail() {
|
|
|
59
59
|
const currency = data.paymentCurrency;
|
|
60
60
|
const total = [formatBNStr(data?.amount, currency.decimal), currency.symbol].join(' ');
|
|
61
61
|
const { paymentIntent, paymentLink } = data || {};
|
|
62
|
+
|
|
63
|
+
const isAnonymousPayer = paymentIntent?.customer?.metadata?.anonymous;
|
|
62
64
|
return (
|
|
63
65
|
<Root direction="column" spacing={2.5} mb={4}>
|
|
64
66
|
<Box>
|
|
@@ -160,23 +162,32 @@ export default function PayoutDetail() {
|
|
|
160
162
|
: '',
|
|
161
163
|
48
|
|
162
164
|
)}
|
|
165
|
+
logoName={paymentIntent?.customer?.metadata?.anonymous ? '' : paymentIntent?.customer?.name}
|
|
163
166
|
name={
|
|
164
167
|
<Typography
|
|
165
168
|
variant="subtitle2"
|
|
166
169
|
sx={{
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
...(isAnonymousPayer
|
|
171
|
+
? {}
|
|
172
|
+
: {
|
|
173
|
+
cursor: 'pointer',
|
|
174
|
+
'&:hover': {
|
|
175
|
+
color: 'text.link',
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
171
178
|
}}
|
|
172
179
|
onClick={() => {
|
|
180
|
+
if (isAnonymousPayer) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
173
183
|
const url = getCustomerProfileUrl({
|
|
174
184
|
userDid: paymentIntent?.customer?.did,
|
|
175
185
|
locale: 'zh',
|
|
176
186
|
});
|
|
177
187
|
window.open(url, '_blank');
|
|
178
188
|
}}>
|
|
179
|
-
{paymentIntent?.customer?.name}
|
|
189
|
+
{paymentIntent?.customer?.name}
|
|
190
|
+
{paymentIntent?.customer?.email ? ` (${paymentIntent?.customer?.email})` : ''}
|
|
180
191
|
</Typography>
|
|
181
192
|
}
|
|
182
193
|
description={
|