@blocklet/payment-react 1.18.11 → 1.18.13
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/es/components/link.js +1 -0
- package/es/components/over-due-invoice-payment.d.ts +3 -1
- package/es/components/over-due-invoice-payment.js +14 -3
- package/es/history/invoice/list.js +42 -32
- package/es/libs/navigation.d.ts +33 -0
- package/es/libs/navigation.js +45 -0
- package/es/locales/en.js +2 -2
- package/es/locales/zh.js +2 -2
- package/lib/components/link.js +1 -0
- package/lib/components/over-due-invoice-payment.d.ts +3 -1
- package/lib/components/over-due-invoice-payment.js +18 -3
- package/lib/history/invoice/list.js +53 -42
- package/lib/libs/navigation.d.ts +33 -0
- package/lib/libs/navigation.js +59 -0
- package/lib/locales/en.js +2 -2
- package/lib/locales/zh.js +2 -2
- package/package.json +5 -5
- package/src/components/link.tsx +1 -0
- package/src/components/over-due-invoice-payment.tsx +14 -1
- package/src/history/invoice/list.tsx +46 -35
- package/src/libs/navigation.ts +89 -0
- package/src/locales/en.tsx +2 -2
- package/src/locales/zh.tsx +2 -2
|
@@ -12,7 +12,8 @@ import { Box, Button, CircularProgress, Hidden, Stack, Typography } from '@mui/m
|
|
|
12
12
|
import { styled } from '@mui/system';
|
|
13
13
|
import { useInfiniteScroll, useRequest, useSetState } from 'ahooks';
|
|
14
14
|
import React, { useEffect, useRef, useState } from 'react';
|
|
15
|
-
|
|
15
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
16
|
+
import { useNavigate } from 'react-router-dom';
|
|
16
17
|
|
|
17
18
|
import debounce from 'lodash/debounce';
|
|
18
19
|
import Status from '../../components/status';
|
|
@@ -26,10 +27,10 @@ import {
|
|
|
26
27
|
formatToDatetime,
|
|
27
28
|
getInvoiceDescriptionAndReason,
|
|
28
29
|
getInvoiceStatusColor,
|
|
29
|
-
getPrefix,
|
|
30
30
|
getTxLink,
|
|
31
31
|
} from '../../libs/util';
|
|
32
32
|
import Table from '../../components/table';
|
|
33
|
+
import { createLink, handleNavigation, LinkInfo } from '../../libs/navigation';
|
|
33
34
|
|
|
34
35
|
type Result = Paginated<TInvoiceExpanded> & { subscription: TSubscription };
|
|
35
36
|
|
|
@@ -72,23 +73,23 @@ type Props = {
|
|
|
72
73
|
|
|
73
74
|
const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
|
|
74
75
|
if (invoice.id.startsWith('in_')) {
|
|
76
|
+
const path = `/customer/invoice/${invoice.id}${invoice.status === 'uncollectible' && action ? `?action=${action}` : ''}`;
|
|
75
77
|
return {
|
|
76
|
-
external: false,
|
|
77
78
|
connect: invoice.status === 'uncollectible',
|
|
78
|
-
|
|
79
|
-
getPrefix(),
|
|
80
|
-
`/customer/invoice/${invoice.id}?action=${invoice.status === 'uncollectible' ? action : ''}`
|
|
81
|
-
),
|
|
79
|
+
link: createLink(path),
|
|
82
80
|
};
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
return {
|
|
86
|
-
external: true,
|
|
87
84
|
connect: false,
|
|
88
|
-
|
|
85
|
+
link: createLink(getTxLink(invoice.paymentMethod, invoice.metadata?.payment_details).link, true),
|
|
89
86
|
};
|
|
90
87
|
};
|
|
91
88
|
|
|
89
|
+
const linkStyle = {
|
|
90
|
+
cursor: 'pointer',
|
|
91
|
+
};
|
|
92
|
+
|
|
92
93
|
const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) => void }) => {
|
|
93
94
|
const {
|
|
94
95
|
pageSize,
|
|
@@ -106,6 +107,7 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
106
107
|
} = props;
|
|
107
108
|
const listKey = 'invoice-table';
|
|
108
109
|
const { t, locale } = useLocaleContext();
|
|
110
|
+
const navigate = useNavigate();
|
|
109
111
|
|
|
110
112
|
const [search, setSearch] = useState<{ pageSize: number; page: number }>({
|
|
111
113
|
pageSize: pageSize || 10,
|
|
@@ -170,6 +172,11 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
170
172
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
171
173
|
}, [subscription]);
|
|
172
174
|
|
|
175
|
+
const handleLinkClick = (e: React.MouseEvent, invoice: TInvoiceExpanded) => {
|
|
176
|
+
const { link } = getInvoiceLink(invoice, action);
|
|
177
|
+
handleNavigation(e, link, navigate, { target: link.external ? '_blank' : target });
|
|
178
|
+
};
|
|
179
|
+
|
|
173
180
|
const columns = [
|
|
174
181
|
{
|
|
175
182
|
label: t('common.amount'),
|
|
@@ -179,14 +186,13 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
179
186
|
options: {
|
|
180
187
|
customBodyRenderLite: (_: string, index: number) => {
|
|
181
188
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
182
|
-
const link = getInvoiceLink(invoice, action);
|
|
183
189
|
return (
|
|
184
|
-
<
|
|
190
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
185
191
|
<Typography>
|
|
186
192
|
{formatBNStr(invoice.total, invoice.paymentCurrency.decimal)}
|
|
187
193
|
{invoice.paymentCurrency.symbol}
|
|
188
194
|
</Typography>
|
|
189
|
-
</
|
|
195
|
+
</Box>
|
|
190
196
|
);
|
|
191
197
|
},
|
|
192
198
|
},
|
|
@@ -197,11 +203,10 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
197
203
|
options: {
|
|
198
204
|
customBodyRenderLite: (_: string, index: number) => {
|
|
199
205
|
const invoice = data.list[index] as TInvoiceExpanded;
|
|
200
|
-
const link = getInvoiceLink(invoice, action);
|
|
201
206
|
return (
|
|
202
|
-
<
|
|
207
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
203
208
|
<Status label={getInvoiceDescriptionAndReason(invoice, locale)?.type} />
|
|
204
|
-
</
|
|
209
|
+
</Box>
|
|
205
210
|
);
|
|
206
211
|
},
|
|
207
212
|
},
|
|
@@ -212,11 +217,10 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
212
217
|
options: {
|
|
213
218
|
customBodyRenderLite: (_: string, index: number) => {
|
|
214
219
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
215
|
-
const link = getInvoiceLink(invoice, action);
|
|
216
220
|
return (
|
|
217
|
-
<
|
|
221
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
218
222
|
{invoice?.number}
|
|
219
|
-
</
|
|
223
|
+
</Box>
|
|
220
224
|
);
|
|
221
225
|
},
|
|
222
226
|
},
|
|
@@ -227,11 +231,11 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
227
231
|
options: {
|
|
228
232
|
customBodyRenderLite: (val: string, index: number) => {
|
|
229
233
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
230
|
-
|
|
234
|
+
|
|
231
235
|
return (
|
|
232
|
-
<
|
|
236
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
233
237
|
{formatToDate(invoice.created_at, locale, 'YYYY-MM-DD HH:mm:ss')}
|
|
234
|
-
</
|
|
238
|
+
</Box>
|
|
235
239
|
);
|
|
236
240
|
},
|
|
237
241
|
},
|
|
@@ -243,11 +247,11 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
243
247
|
sort: false,
|
|
244
248
|
customBodyRenderLite: (val: string, index: number) => {
|
|
245
249
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
246
|
-
|
|
250
|
+
|
|
247
251
|
return (
|
|
248
|
-
<
|
|
252
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
249
253
|
{getInvoiceDescriptionAndReason(invoice, locale)?.description || invoice.id}
|
|
250
|
-
</
|
|
254
|
+
</Box>
|
|
251
255
|
);
|
|
252
256
|
},
|
|
253
257
|
},
|
|
@@ -258,10 +262,10 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
258
262
|
options: {
|
|
259
263
|
customBodyRenderLite: (val: string, index: number) => {
|
|
260
264
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
261
|
-
const link = getInvoiceLink(invoice, action);
|
|
262
265
|
const hidePay = invoice.billing_reason === 'overdraft-protection';
|
|
266
|
+
const { connect } = getInvoiceLink(invoice, action);
|
|
263
267
|
if (action && !hidePay) {
|
|
264
|
-
return
|
|
268
|
+
return connect ? (
|
|
265
269
|
<Button variant="text" size="small" onClick={() => onPay(invoice.id)} sx={{ color: 'text.link' }}>
|
|
266
270
|
{t('payment.customer.invoice.pay')}
|
|
267
271
|
</Button>
|
|
@@ -270,8 +274,7 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
270
274
|
component="a"
|
|
271
275
|
variant="text"
|
|
272
276
|
size="small"
|
|
273
|
-
|
|
274
|
-
target={link.external ? '_blank' : target}
|
|
277
|
+
onClick={(e) => handleLinkClick(e, invoice)}
|
|
275
278
|
sx={{ color: 'var(--foregrounds-fg-interactive, #0086FF) !important' }}
|
|
276
279
|
rel="noreferrer">
|
|
277
280
|
{t('payment.customer.invoice.pay')}
|
|
@@ -279,9 +282,9 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
279
282
|
);
|
|
280
283
|
}
|
|
281
284
|
return (
|
|
282
|
-
<
|
|
285
|
+
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
283
286
|
<Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
|
|
284
|
-
</
|
|
287
|
+
</Box>
|
|
285
288
|
);
|
|
286
289
|
},
|
|
287
290
|
},
|
|
@@ -354,6 +357,7 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
354
357
|
|
|
355
358
|
const subscription = useSubscription('events');
|
|
356
359
|
const { t, locale } = useLocaleContext();
|
|
360
|
+
const navigate = useNavigate();
|
|
357
361
|
|
|
358
362
|
const { data, loadMore, loadingMore, loading, reloadAsync } = useInfiniteScroll<Result>(
|
|
359
363
|
(d) => {
|
|
@@ -433,13 +437,17 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
433
437
|
|
|
434
438
|
const grouped = groupByDate(data.list as any);
|
|
435
439
|
|
|
440
|
+
const handleLinkClick = (e: React.MouseEvent, link: LinkInfo) => {
|
|
441
|
+
handleNavigation(e, link, navigate, { target: link.external ? '_blank' : target });
|
|
442
|
+
};
|
|
443
|
+
|
|
436
444
|
return (
|
|
437
445
|
<Root direction="column" gap={1} sx={{ mt: 1 }}>
|
|
438
446
|
{Object.entries(grouped).map(([date, invoices]) => (
|
|
439
447
|
<Box key={date}>
|
|
440
448
|
<Typography sx={{ fontWeight: 'bold', color: 'text.secondary', mt: 2, mb: 1 }}>{date}</Typography>
|
|
441
449
|
{invoices.map((invoice) => {
|
|
442
|
-
const link = getInvoiceLink(invoice, action);
|
|
450
|
+
const { link, connect } = getInvoiceLink(invoice, action);
|
|
443
451
|
return (
|
|
444
452
|
<Stack
|
|
445
453
|
key={invoice.id}
|
|
@@ -453,7 +461,11 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
453
461
|
alignItems="center"
|
|
454
462
|
flexWrap="nowrap">
|
|
455
463
|
<Box flex={2}>
|
|
456
|
-
<a
|
|
464
|
+
<a
|
|
465
|
+
href={link.url}
|
|
466
|
+
target={link.external ? '_blank' : target}
|
|
467
|
+
rel="noreferrer"
|
|
468
|
+
onClick={(e) => handleLinkClick(e, link)}>
|
|
457
469
|
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
458
470
|
<Typography component="span">{invoice.number}</Typography>
|
|
459
471
|
{link.external && (
|
|
@@ -482,7 +494,7 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
482
494
|
)}
|
|
483
495
|
<Box flex={1} textAlign="right">
|
|
484
496
|
{action ? (
|
|
485
|
-
|
|
497
|
+
connect ? (
|
|
486
498
|
<Button
|
|
487
499
|
variant="contained"
|
|
488
500
|
color="primary"
|
|
@@ -496,8 +508,7 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
496
508
|
component="a"
|
|
497
509
|
variant="contained"
|
|
498
510
|
size="small"
|
|
499
|
-
|
|
500
|
-
target={link.external ? '_blank' : target}
|
|
511
|
+
onClick={(e) => handleLinkClick(e, link)}
|
|
501
512
|
sx={{ whiteSpace: 'nowrap' }}
|
|
502
513
|
rel="noreferrer">
|
|
503
514
|
{t('payment.customer.invoice.pay')}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
import { NavigateFunction } from 'react-router-dom';
|
|
3
|
+
import { joinURL } from 'ufo';
|
|
4
|
+
import { getPrefix, PAYMENT_KIT_DID } from './util';
|
|
5
|
+
|
|
6
|
+
export interface LinkInfo {
|
|
7
|
+
// Full URL for href attribute
|
|
8
|
+
url: string;
|
|
9
|
+
// Whether this is an external link
|
|
10
|
+
external: boolean;
|
|
11
|
+
// Original path (used for React Router)
|
|
12
|
+
path: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if currently running inside Payment Kit
|
|
17
|
+
*/
|
|
18
|
+
export function isInPaymentKit(): boolean {
|
|
19
|
+
const componentId = (window.blocklet?.componentId || '').split('/').pop();
|
|
20
|
+
return componentId === PAYMENT_KIT_DID;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create link information object
|
|
25
|
+
* @param path Path or URL
|
|
26
|
+
* @param external Force external link behavior
|
|
27
|
+
*/
|
|
28
|
+
export function createLink(path: string, external = false): LinkInfo {
|
|
29
|
+
const isAbsoluteUrl = /^https?:\/\//.test(path);
|
|
30
|
+
const isExternal = external || isAbsoluteUrl;
|
|
31
|
+
const url = isExternal ? path : joinURL(getPrefix(), path);
|
|
32
|
+
return {
|
|
33
|
+
url,
|
|
34
|
+
external: isExternal,
|
|
35
|
+
path,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get HTML attributes for a link
|
|
41
|
+
* @param link Link information
|
|
42
|
+
* @param target Link target (default: _self)
|
|
43
|
+
*/
|
|
44
|
+
export function getLinkProps(link: LinkInfo, target = '_self'): Record<string, any> {
|
|
45
|
+
const props: Record<string, any> = {
|
|
46
|
+
href: link.url,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (link.external) {
|
|
50
|
+
props.target = target;
|
|
51
|
+
props.rel = target === '_blank' ? 'noopener noreferrer' : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return props;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Handle link navigation
|
|
59
|
+
* @param e Click event
|
|
60
|
+
* @param link Link information
|
|
61
|
+
* @param navigate React Router navigate function
|
|
62
|
+
* @param options Navigation options
|
|
63
|
+
*/
|
|
64
|
+
export function handleNavigation(
|
|
65
|
+
e: React.MouseEvent,
|
|
66
|
+
link: LinkInfo,
|
|
67
|
+
navigate?: NavigateFunction,
|
|
68
|
+
options: { replace?: boolean; target?: string } = {}
|
|
69
|
+
): void {
|
|
70
|
+
if (e) {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
}
|
|
73
|
+
const { replace = false, target = '_self' } = options;
|
|
74
|
+
if (link.external || target === '_blank') {
|
|
75
|
+
window.open(link.url, target);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isInPaymentKit() && navigate) {
|
|
80
|
+
navigate(link.path, { replace });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (replace) {
|
|
85
|
+
window.location.replace(link.url);
|
|
86
|
+
} else {
|
|
87
|
+
window.location.href = link.url;
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/locales/en.tsx
CHANGED
|
@@ -254,8 +254,8 @@ export default flat({
|
|
|
254
254
|
},
|
|
255
255
|
},
|
|
256
256
|
recover: {
|
|
257
|
-
button: '
|
|
258
|
-
title: '
|
|
257
|
+
button: 'Resume Subscription',
|
|
258
|
+
title: 'Resume Your Subscription',
|
|
259
259
|
description:
|
|
260
260
|
'Your subscription will not be canceled and will be automatically renewed on {date}, please confirm to continue',
|
|
261
261
|
},
|