payment-kit 1.18.15 → 1.18.17
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/index.ts +2 -0
- package/api/src/libs/invoice.ts +5 -3
- 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/change-payment.ts +9 -1
- package/api/src/routes/connect/change-plan.ts +9 -1
- package/api/src/routes/connect/collect-batch.ts +7 -5
- package/api/src/routes/connect/pay.ts +1 -1
- package/api/src/routes/connect/recharge-account.ts +124 -0
- package/api/src/routes/connect/setup.ts +8 -1
- package/api/src/routes/connect/shared.ts +175 -54
- package/api/src/routes/connect/subscribe.ts +11 -1
- package/api/src/routes/customers.ts +150 -7
- package/api/src/routes/donations.ts +1 -1
- package/api/src/routes/invoices.ts +47 -1
- package/api/src/routes/subscriptions.ts +0 -3
- package/blocklet.yml +2 -1
- package/package.json +16 -16
- package/src/app.tsx +11 -3
- package/src/components/info-card.tsx +6 -2
- package/src/components/info-row.tsx +1 -0
- package/src/components/invoice/recharge.tsx +85 -56
- package/src/components/invoice/table.tsx +7 -1
- package/src/components/subscription/portal/actions.tsx +1 -1
- package/src/components/subscription/portal/list.tsx +6 -0
- package/src/locales/en.tsx +9 -0
- package/src/locales/zh.tsx +9 -0
- package/src/pages/admin/payments/payouts/detail.tsx +16 -5
- package/src/pages/customer/index.tsx +226 -284
- package/src/pages/customer/invoice/detail.tsx +24 -16
- package/src/pages/customer/invoice/past-due.tsx +46 -23
- package/src/pages/customer/payout/detail.tsx +16 -5
- package/src/pages/customer/recharge/account.tsx +513 -0
- package/src/pages/customer/{recharge.tsx → recharge/subscription.tsx} +22 -19
- package/src/pages/customer/subscription/embed.tsx +16 -1
|
@@ -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
|
});
|
|
@@ -180,6 +180,52 @@ router.get('/', authMine, async (req, res) => {
|
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
+
const rechargeSchema = createListParamSchema<{
|
|
184
|
+
status?: string;
|
|
185
|
+
customer_id?: string;
|
|
186
|
+
currency_id?: string;
|
|
187
|
+
}>({
|
|
188
|
+
status: Joi.string().empty(''),
|
|
189
|
+
customer_id: Joi.string().empty(''),
|
|
190
|
+
currency_id: Joi.string().empty(''),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
router.get('/recharge', authMine, async (req, res) => {
|
|
194
|
+
const { page, pageSize, ...query } = await rechargeSchema.validateAsync(req.query, {
|
|
195
|
+
stripUnknown: false,
|
|
196
|
+
allowUnknown: true,
|
|
197
|
+
});
|
|
198
|
+
const where = getWhereFromKvQuery(query.q);
|
|
199
|
+
if (query.customer_id) {
|
|
200
|
+
where.customer_id = query.customer_id;
|
|
201
|
+
}
|
|
202
|
+
if (query.currency_id) {
|
|
203
|
+
where.currency_id = query.currency_id;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
const { rows: invoices, count } = await Invoice.findAndCountAll({
|
|
208
|
+
where: {
|
|
209
|
+
billing_reason: 'recharge',
|
|
210
|
+
paid: true,
|
|
211
|
+
...where,
|
|
212
|
+
},
|
|
213
|
+
offset: (page - 1) * pageSize,
|
|
214
|
+
limit: pageSize,
|
|
215
|
+
order: [['created_at', 'DESC']],
|
|
216
|
+
include: [
|
|
217
|
+
{ model: PaymentCurrency, as: 'paymentCurrency' },
|
|
218
|
+
{ model: PaymentMethod, as: 'paymentMethod' },
|
|
219
|
+
],
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return res.json({ count, list: invoices, paging: { page, pageSize } });
|
|
223
|
+
} catch (err) {
|
|
224
|
+
logger.error(err);
|
|
225
|
+
return res.status(400).json({ error: err.message });
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
183
229
|
const searchSchema = createListParamSchema<{}>({});
|
|
184
230
|
router.get('/search', authMine, async (req, res) => {
|
|
185
231
|
const { page, pageSize, livemode, q, o } = await searchSchema.validateAsync(req.query, {
|
|
@@ -1972,9 +1972,6 @@ router.get('/:id/overdue/invoices', authPortal, async (req, res) => {
|
|
|
1972
1972
|
});
|
|
1973
1973
|
|
|
1974
1974
|
router.get('/:id/delegation', authPortal, async (req, res) => {
|
|
1975
|
-
if (!req.user) {
|
|
1976
|
-
return res.status(403).json({ error: 'Unauthorized' });
|
|
1977
|
-
}
|
|
1978
1975
|
try {
|
|
1979
1976
|
const subscription = (await Subscription.findByPk(req.params.id, {
|
|
1980
1977
|
include: [
|
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.17
|
|
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.17",
|
|
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.25",
|
|
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.25",
|
|
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.17",
|
|
57
|
+
"@blocklet/sdk": "^1.16.40",
|
|
58
|
+
"@blocklet/ui-react": "^2.12.25",
|
|
59
|
+
"@blocklet/uploader": "^0.1.76",
|
|
60
|
+
"@blocklet/xss": "^0.1.28",
|
|
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.17",
|
|
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": "9d43381dd3744506455547260f5e621c6ad88e8f"
|
|
171
171
|
}
|
package/src/app.tsx
CHANGED
|
@@ -28,9 +28,10 @@ const CustomerSubscriptionDetail = React.lazy(() => import('./pages/customer/sub
|
|
|
28
28
|
const CustomerSubscriptionEmbed = React.lazy(() => import('./pages/customer/subscription/embed'));
|
|
29
29
|
const CustomerSubscriptionChangePlan = React.lazy(() => import('./pages/customer/subscription/change-plan'));
|
|
30
30
|
const CustomerSubscriptionChangePayment = React.lazy(() => import('./pages/customer/subscription/change-payment'));
|
|
31
|
-
const CustomerRecharge = React.lazy(() => import('./pages/customer/recharge'));
|
|
31
|
+
const CustomerRecharge = React.lazy(() => import('./pages/customer/recharge/subscription'));
|
|
32
32
|
const CustomerPayoutDetail = React.lazy(() => import('./pages/customer/payout/detail'));
|
|
33
33
|
const IntegrationsPage = React.lazy(() => import('./pages/integrations'));
|
|
34
|
+
const CustomerBalanceRecharge = React.lazy(() => import('./pages/customer/recharge/account'));
|
|
34
35
|
|
|
35
36
|
// const theme = createTheme({
|
|
36
37
|
// typography: {
|
|
@@ -108,14 +109,21 @@ function App() {
|
|
|
108
109
|
</UserLayout>
|
|
109
110
|
}
|
|
110
111
|
/>
|
|
112
|
+
<Route
|
|
113
|
+
key="customer-balance-recharge"
|
|
114
|
+
path="/customer/recharge/:currencyId"
|
|
115
|
+
element={
|
|
116
|
+
<UserLayout>
|
|
117
|
+
<CustomerBalanceRecharge />
|
|
118
|
+
</UserLayout>
|
|
119
|
+
}
|
|
120
|
+
/>
|
|
111
121
|
<Route key="customer-embed" path="/customer/embed/subscription" element={<CustomerSubscriptionEmbed />} />
|
|
112
|
-
,
|
|
113
122
|
<Route
|
|
114
123
|
key="subscription-embed"
|
|
115
124
|
path="/embed/customer/subscription"
|
|
116
125
|
element={<CustomerSubscriptionEmbed />}
|
|
117
126
|
/>
|
|
118
|
-
,
|
|
119
127
|
<Route
|
|
120
128
|
key="customer-due"
|
|
121
129
|
path="/customer/invoice/past-due"
|
|
@@ -9,15 +9,17 @@ type Props = {
|
|
|
9
9
|
size?: number;
|
|
10
10
|
variant?: LiteralUnion<'square' | 'rounded' | 'circular', string>;
|
|
11
11
|
sx?: SxProps;
|
|
12
|
+
className?: string;
|
|
13
|
+
logoName?: string;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
export default function InfoCard(props: Props) {
|
|
15
17
|
const dimensions = { width: props.size, height: props.size, ...props.sx };
|
|
16
18
|
const avatarName = typeof props.name === 'string' ? props.name : props.logo;
|
|
17
19
|
return (
|
|
18
|
-
<Stack direction="row" alignItems="center" spacing={1}>
|
|
20
|
+
<Stack direction="row" alignItems="center" spacing={1} className={`info-card-wrapper ${props.className}`}>
|
|
19
21
|
{props.logo ? (
|
|
20
|
-
<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} />
|
|
21
23
|
) : (
|
|
22
24
|
<Avatar variant={props.variant as any} sx={dimensions}>
|
|
23
25
|
{avatarName?.slice(0, 1)}
|
|
@@ -45,4 +47,6 @@ InfoCard.defaultProps = {
|
|
|
45
47
|
size: 40,
|
|
46
48
|
variant: 'rounded',
|
|
47
49
|
sx: {},
|
|
50
|
+
className: '',
|
|
51
|
+
logoName: '',
|
|
48
52
|
};
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getInvoiceStatusColor,
|
|
8
8
|
Table,
|
|
9
9
|
useDefaultPageSize,
|
|
10
|
-
getInvoiceDescriptionAndReason,
|
|
11
10
|
getTxLink,
|
|
12
11
|
formatToDate,
|
|
13
12
|
} from '@blocklet/payment-react';
|
|
@@ -19,9 +18,12 @@ import { styled } from '@mui/system';
|
|
|
19
18
|
|
|
20
19
|
const fetchData = (
|
|
21
20
|
subscriptionId: string,
|
|
21
|
+
currencyId: string,
|
|
22
22
|
params: Record<string, any> = {}
|
|
23
23
|
): Promise<{ list: TInvoiceExpanded[]; count: number }> => {
|
|
24
24
|
const search = new URLSearchParams();
|
|
25
|
+
|
|
26
|
+
// 处理通用查询参数
|
|
25
27
|
Object.keys(params).forEach((key) => {
|
|
26
28
|
let v = params[key];
|
|
27
29
|
if (key === 'q') {
|
|
@@ -32,7 +34,16 @@ const fetchData = (
|
|
|
32
34
|
search.set(key, String(v));
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
if (subscriptionId) {
|
|
38
|
+
return api.get(`/api/subscriptions/${subscriptionId}/recharge?${search.toString()}`).then((res) => res.data);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (currencyId) {
|
|
42
|
+
search.set('currency_id', currencyId);
|
|
43
|
+
return api.get(`/api/invoices/recharge?${search.toString()}`).then((res) => res.data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Promise.resolve({ list: [], count: 0 });
|
|
36
47
|
};
|
|
37
48
|
|
|
38
49
|
type SearchProps = {
|
|
@@ -60,6 +71,9 @@ const getListKey = (props: ListProps) => {
|
|
|
60
71
|
if (props.subscription_id) {
|
|
61
72
|
return `subscription-recharge-${props.subscription_id}`;
|
|
62
73
|
}
|
|
74
|
+
if (props.currency_id) {
|
|
75
|
+
return `currency-recharge-${props.currency_id}`;
|
|
76
|
+
}
|
|
63
77
|
return 'invoices';
|
|
64
78
|
};
|
|
65
79
|
|
|
@@ -80,27 +94,32 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
80
94
|
const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
|
|
81
95
|
defaultValue: {
|
|
82
96
|
currency_id,
|
|
97
|
+
subscription_id,
|
|
83
98
|
pageSize: defaultPageSize,
|
|
84
99
|
page: 1,
|
|
85
100
|
},
|
|
86
101
|
});
|
|
87
102
|
|
|
88
|
-
const [data, setData] = useState({})
|
|
103
|
+
const [data, setData] = useState<{ list?: TInvoiceExpanded[]; count?: number }>({});
|
|
104
|
+
const [loading, setLoading] = useState(true);
|
|
89
105
|
|
|
90
|
-
const refresh = () =>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
const refresh = async () => {
|
|
107
|
+
setLoading(true);
|
|
108
|
+
try {
|
|
109
|
+
const res = await fetchData(subscription_id || '', currency_id || '', {
|
|
110
|
+
...search,
|
|
111
|
+
});
|
|
94
112
|
setData(res);
|
|
95
|
-
})
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Failed to fetch recharge records:', error);
|
|
115
|
+
} finally {
|
|
116
|
+
setLoading(false);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
96
119
|
|
|
97
120
|
useEffect(() => {
|
|
98
121
|
refresh();
|
|
99
|
-
}, [search]);
|
|
100
|
-
|
|
101
|
-
if (!data.list) {
|
|
102
|
-
return <CircularProgress />;
|
|
103
|
-
}
|
|
122
|
+
}, [search, currency_id, subscription_id]);
|
|
104
123
|
|
|
105
124
|
const getInvoiceLink = (invoice: TInvoiceExpanded) => {
|
|
106
125
|
return {
|
|
@@ -118,7 +137,9 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
118
137
|
align: 'right',
|
|
119
138
|
options: {
|
|
120
139
|
customBodyRenderLite: (_: string, index: number) => {
|
|
121
|
-
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
140
|
+
const invoice = data?.list?.[index] as TInvoiceExpanded;
|
|
141
|
+
if (!invoice) return null;
|
|
142
|
+
|
|
122
143
|
const link = getInvoiceLink(invoice);
|
|
123
144
|
return (
|
|
124
145
|
<a href={link.url} target="_blank" rel="noreferrer">
|
|
@@ -136,7 +157,9 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
136
157
|
name: 'number',
|
|
137
158
|
options: {
|
|
138
159
|
customBodyRenderLite: (_: string, index: number) => {
|
|
139
|
-
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
160
|
+
const invoice = data?.list?.[index] as TInvoiceExpanded;
|
|
161
|
+
if (!invoice) return null;
|
|
162
|
+
|
|
140
163
|
const link = getInvoiceLink(invoice);
|
|
141
164
|
return (
|
|
142
165
|
<a href={link.url} target="_blank" rel="noreferrer">
|
|
@@ -148,10 +171,12 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
148
171
|
},
|
|
149
172
|
{
|
|
150
173
|
label: t('common.rechargeTime'),
|
|
151
|
-
name: '
|
|
174
|
+
name: 'created_at',
|
|
152
175
|
options: {
|
|
153
176
|
customBodyRenderLite: (_: string, index: number) => {
|
|
154
|
-
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
177
|
+
const invoice = data?.list?.[index] as TInvoiceExpanded;
|
|
178
|
+
if (!invoice) return null;
|
|
179
|
+
|
|
155
180
|
const link = getInvoiceLink(invoice);
|
|
156
181
|
return (
|
|
157
182
|
<a href={link.url} target="_blank" rel="noreferrer">
|
|
@@ -161,28 +186,14 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
161
186
|
},
|
|
162
187
|
},
|
|
163
188
|
},
|
|
164
|
-
{
|
|
165
|
-
label: t('common.description'),
|
|
166
|
-
name: '',
|
|
167
|
-
options: {
|
|
168
|
-
sort: false,
|
|
169
|
-
customBodyRenderLite: (_: string, index: number) => {
|
|
170
|
-
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
171
|
-
const link = getInvoiceLink(invoice);
|
|
172
|
-
return (
|
|
173
|
-
<a href={link.url} target="_blank" rel="noreferrer">
|
|
174
|
-
{getInvoiceDescriptionAndReason(invoice, locale)?.description || invoice.id}
|
|
175
|
-
</a>
|
|
176
|
-
);
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
189
|
{
|
|
181
190
|
label: t('common.status'),
|
|
182
191
|
name: 'status',
|
|
183
192
|
options: {
|
|
184
193
|
customBodyRenderLite: (_: string, index: number) => {
|
|
185
|
-
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
194
|
+
const invoice = data?.list?.[index] as TInvoiceExpanded;
|
|
195
|
+
if (!invoice) return null;
|
|
196
|
+
|
|
186
197
|
const link = getInvoiceLink(invoice);
|
|
187
198
|
return (
|
|
188
199
|
<a href={link.url} target="_blank" rel="noreferrer">
|
|
@@ -196,34 +207,52 @@ export default function RechargeList({ currency_id, subscription_id, features }:
|
|
|
196
207
|
|
|
197
208
|
const onTableChange = ({ page, rowsPerPage }: any) => {
|
|
198
209
|
if (search!.pageSize !== rowsPerPage) {
|
|
199
|
-
setSearch((x) =>
|
|
210
|
+
setSearch((x) => {
|
|
211
|
+
const newState = { ...x };
|
|
212
|
+
if (newState) {
|
|
213
|
+
newState.pageSize = rowsPerPage;
|
|
214
|
+
newState.page = 1;
|
|
215
|
+
}
|
|
216
|
+
return newState as SearchProps;
|
|
217
|
+
});
|
|
200
218
|
} else if (search!.page !== page + 1) {
|
|
201
|
-
|
|
202
|
-
|
|
219
|
+
setSearch((x) => {
|
|
220
|
+
const newState = { ...x };
|
|
221
|
+
if (newState) {
|
|
222
|
+
newState.page = page + 1;
|
|
223
|
+
}
|
|
224
|
+
return newState as SearchProps;
|
|
225
|
+
});
|
|
203
226
|
}
|
|
204
227
|
};
|
|
205
228
|
|
|
206
229
|
return (
|
|
207
230
|
<InvoiceTableRoot>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
{loading ? (
|
|
232
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|
|
233
|
+
<CircularProgress />
|
|
234
|
+
</Box>
|
|
235
|
+
) : (
|
|
236
|
+
<Table
|
|
237
|
+
hasRowLink
|
|
238
|
+
data={data.list || []}
|
|
239
|
+
durable={`__${listKey}__`}
|
|
240
|
+
durableKeys={['searchText']}
|
|
241
|
+
columns={columns}
|
|
242
|
+
loading={loading}
|
|
243
|
+
onChange={onTableChange}
|
|
244
|
+
mobileTDFlexDirection="row"
|
|
245
|
+
options={{
|
|
246
|
+
count: data.count || 0,
|
|
247
|
+
page: search!.page - 1,
|
|
248
|
+
rowsPerPage: search!.pageSize,
|
|
249
|
+
}}
|
|
250
|
+
toolbar={false}
|
|
251
|
+
showMobile={false}
|
|
252
|
+
footer={features?.footer}
|
|
253
|
+
emptyNodeText={`${t('empty.invoices')}`}
|
|
254
|
+
/>
|
|
255
|
+
)}
|
|
227
256
|
</InvoiceTableRoot>
|
|
228
257
|
);
|
|
229
258
|
}
|
|
@@ -196,6 +196,12 @@ export default function InvoiceTable({ invoice, simple, emptyNodeText }: Props)
|
|
|
196
196
|
name: 'amount',
|
|
197
197
|
width: 200,
|
|
198
198
|
align: 'right',
|
|
199
|
+
options: {
|
|
200
|
+
customBodyRenderLite: (_: string, index: number) => {
|
|
201
|
+
const item = detail[index] as InvoiceDetailItem;
|
|
202
|
+
return <Typography component="span">{invoice.status === 'void' ? '0' : item.amount}</Typography>;
|
|
203
|
+
},
|
|
204
|
+
},
|
|
199
205
|
},
|
|
200
206
|
...(simple
|
|
201
207
|
? []
|
|
@@ -237,7 +243,7 @@ export default function InvoiceTable({ invoice, simple, emptyNodeText }: Props)
|
|
|
237
243
|
mobileTDFlexDirection="row"
|
|
238
244
|
emptyNodeText={emptyNodeText || t('payment.customer.invoice.emptyList')}
|
|
239
245
|
/>
|
|
240
|
-
{!isEmpty(detail) && (
|
|
246
|
+
{!isEmpty(detail) && invoice.status !== 'void' && (
|
|
241
247
|
<Stack
|
|
242
248
|
className="invoice-summary"
|
|
243
249
|
sx={{
|
|
@@ -521,7 +521,7 @@ export function SubscriptionActionsInner({
|
|
|
521
521
|
setState({ batchPay: false });
|
|
522
522
|
onChange?.('batch-pay');
|
|
523
523
|
}}
|
|
524
|
-
|
|
524
|
+
detailLinkOptions={{ enabled: false }}
|
|
525
525
|
dialogProps={{
|
|
526
526
|
open: state.batchPay,
|
|
527
527
|
onClose: () => setState({ batchPay: false }),
|
|
@@ -36,6 +36,7 @@ type Props = {
|
|
|
36
36
|
onlyActive?: boolean;
|
|
37
37
|
changeActive?: (active: boolean) => void;
|
|
38
38
|
setStatusState?: (state: boolean) => void;
|
|
39
|
+
setHasSubscriptions?: (state: boolean) => void;
|
|
39
40
|
} & Omit<StackProps, 'onChange'>;
|
|
40
41
|
|
|
41
42
|
const pageSize = 5;
|
|
@@ -48,6 +49,7 @@ export default function CurrentSubscriptions({
|
|
|
48
49
|
onlyActive,
|
|
49
50
|
changeActive = () => {},
|
|
50
51
|
setStatusState = () => {},
|
|
52
|
+
setHasSubscriptions = () => {},
|
|
51
53
|
...rest
|
|
52
54
|
}: Props) {
|
|
53
55
|
const { t } = useLocaleContext();
|
|
@@ -64,6 +66,9 @@ export default function CurrentSubscriptions({
|
|
|
64
66
|
onSuccess(res) {
|
|
65
67
|
if (res.totalCount > 0 || res.count > 0) {
|
|
66
68
|
setStatusState(true);
|
|
69
|
+
setHasSubscriptions(true);
|
|
70
|
+
} else {
|
|
71
|
+
setHasSubscriptions(false);
|
|
67
72
|
}
|
|
68
73
|
},
|
|
69
74
|
...(isMobile
|
|
@@ -279,4 +284,5 @@ CurrentSubscriptions.defaultProps = {
|
|
|
279
284
|
onlyActive: false,
|
|
280
285
|
changeActive: null,
|
|
281
286
|
setStatusState: null,
|
|
287
|
+
setHasSubscriptions: null,
|
|
282
288
|
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -796,6 +796,8 @@ export default flat({
|
|
|
796
796
|
estimatedDuration: '{duration} {unit} est.',
|
|
797
797
|
intervals: 'intervals',
|
|
798
798
|
history: 'Fund History',
|
|
799
|
+
relatedSubscriptions: 'Related Subscriptions',
|
|
800
|
+
rechargeTooltip: 'Click to add funds',
|
|
799
801
|
},
|
|
800
802
|
delegation: {
|
|
801
803
|
title:
|
|
@@ -855,6 +857,13 @@ export default flat({
|
|
|
855
857
|
viewReference: 'View Reference',
|
|
856
858
|
title: 'Revenue',
|
|
857
859
|
},
|
|
860
|
+
pastDue: {
|
|
861
|
+
warning: 'You have due invoices, please pay them to keep your services active',
|
|
862
|
+
invoices: 'Due Invoices',
|
|
863
|
+
payNow: 'Pay Now',
|
|
864
|
+
alert: 'You have due invoices. Please pay them promptly to avoid service interruption.',
|
|
865
|
+
title: 'Settle Due Invoices',
|
|
866
|
+
},
|
|
858
867
|
},
|
|
859
868
|
integrations: {
|
|
860
869
|
basicFeatures: 'Basic Features',
|
package/src/locales/zh.tsx
CHANGED
|
@@ -774,6 +774,8 @@ export default flat({
|
|
|
774
774
|
custom: '自定义',
|
|
775
775
|
intervals: '个周期',
|
|
776
776
|
history: '充值记录',
|
|
777
|
+
relatedSubscriptions: '关联订阅',
|
|
778
|
+
rechargeTooltip: '点击充值余额',
|
|
777
779
|
},
|
|
778
780
|
delegation: {
|
|
779
781
|
title: '检测到你未完成账户的授权,为了不影响订阅的扣费,请尽快完成授权',
|
|
@@ -828,6 +830,13 @@ export default flat({
|
|
|
828
830
|
viewReference: '查看打赏原文',
|
|
829
831
|
title: '收款记录',
|
|
830
832
|
},
|
|
833
|
+
pastDue: {
|
|
834
|
+
warning: '您有欠费账单,请及时付款以保持服务正常运行',
|
|
835
|
+
invoices: '欠费账单',
|
|
836
|
+
payNow: '立即付款',
|
|
837
|
+
alert: '您有欠费账单需要处理,请及时付款以避免服务中断',
|
|
838
|
+
title: '结清欠费账单',
|
|
839
|
+
},
|
|
831
840
|
},
|
|
832
841
|
integrations: {
|
|
833
842
|
basicFeatures: '基础功能',
|
|
@@ -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={
|