payment-kit 1.13.165 → 1.13.166
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/blocklet.yml +1 -1
- package/package.json +4 -4
- package/src/app.tsx +79 -76
- package/src/components/event/list.tsx +5 -1
- package/src/components/filter-toolbar.tsx +14 -10
- package/src/components/invoice/list.tsx +3 -1
- package/src/components/payment-intent/list.tsx +5 -1
- package/src/components/progress-bar.tsx +56 -0
- package/src/components/refund/list.tsx +5 -2
- package/src/components/subscription/list.tsx +5 -1
- package/src/pages/admin/billing/index.tsx +4 -1
- package/src/pages/admin/customers/customers/index.tsx +5 -1
- package/src/pages/admin/customers/index.tsx +4 -1
- package/src/pages/admin/developers/index.tsx +4 -1
- package/src/pages/admin/developers/webhooks/index.tsx +5 -1
- package/src/pages/admin/index.tsx +5 -4
- package/src/pages/admin/payments/index.tsx +4 -1
- package/src/pages/admin/payments/links/index.tsx +5 -1
- package/src/pages/admin/products/index.tsx +4 -1
- package/src/pages/admin/products/pricing-tables/index.tsx +5 -1
- package/src/pages/admin/products/products/index.tsx +7 -3
- package/src/pages/admin/settings/index.tsx +4 -1
- package/src/pages/customer/index.tsx +112 -105
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.166",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@arcblock/jwt": "^1.18.110",
|
|
51
51
|
"@arcblock/ux": "^2.9.39",
|
|
52
52
|
"@blocklet/logger": "1.16.23",
|
|
53
|
-
"@blocklet/payment-react": "1.13.
|
|
53
|
+
"@blocklet/payment-react": "1.13.166",
|
|
54
54
|
"@blocklet/sdk": "1.16.23",
|
|
55
55
|
"@blocklet/ui-react": "^2.9.39",
|
|
56
56
|
"@blocklet/uploader": "^0.0.74",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@abtnode/types": "1.16.23",
|
|
112
112
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
113
|
-
"@blocklet/payment-types": "1.13.
|
|
113
|
+
"@blocklet/payment-types": "1.13.166",
|
|
114
114
|
"@types/cookie-parser": "^1.4.6",
|
|
115
115
|
"@types/cors": "^2.8.17",
|
|
116
116
|
"@types/dotenv-flow": "^3.3.3",
|
|
@@ -149,5 +149,5 @@
|
|
|
149
149
|
"parser": "typescript"
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "70ee269e307cbab0ecb58fb4f287b749df0f2277"
|
|
153
153
|
}
|
package/src/app.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import { joinURL } from 'ufo';
|
|
|
13
13
|
|
|
14
14
|
import ErrorFallback from './components/error-fallback';
|
|
15
15
|
import Layout from './components/layout/admin';
|
|
16
|
+
import { TransitionProvider } from './components/progress-bar';
|
|
16
17
|
import { SessionProvider } from './contexts/session';
|
|
17
18
|
import { translations } from './locales';
|
|
18
19
|
|
|
@@ -38,82 +39,84 @@ const theme = createTheme({
|
|
|
38
39
|
function App() {
|
|
39
40
|
return (
|
|
40
41
|
<ThemeProvider theme={theme}>
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
42
|
+
<TransitionProvider>
|
|
43
|
+
<LocaleProvider translations={translations} fallbackLocale="en">
|
|
44
|
+
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={window.location.reload}>
|
|
45
|
+
<Suspense
|
|
46
|
+
fallback={
|
|
47
|
+
<Center>
|
|
48
|
+
<CircularProgress />
|
|
49
|
+
</Center>
|
|
50
|
+
}>
|
|
51
|
+
<Routes>
|
|
52
|
+
<Route path="/" element={<HomePage />} />
|
|
53
|
+
<Route path="/checkout/:action/:id" element={<CheckoutPage />} />
|
|
54
|
+
<Route key="admin-index" path="/admin" element={<AdminPage />} />,
|
|
55
|
+
<Route key="admin-tabs" path="/admin/:group" element={<AdminPage />} />,
|
|
56
|
+
<Route key="admin-sub" path="/admin/:group/:page" element={<AdminPage />} />,
|
|
57
|
+
<Route key="admin-fallback" path="/admin/*" element={<AdminPage />} />,
|
|
58
|
+
<Route
|
|
59
|
+
key="customer-home"
|
|
60
|
+
path="/customer"
|
|
61
|
+
element={
|
|
62
|
+
<Layout>
|
|
63
|
+
<CustomerHome />
|
|
64
|
+
</Layout>
|
|
65
|
+
}
|
|
66
|
+
/>
|
|
67
|
+
<Route
|
|
68
|
+
key="customer-subscription"
|
|
69
|
+
path="/customer/subscription/:id"
|
|
70
|
+
element={
|
|
71
|
+
<Layout>
|
|
72
|
+
<CustomerSubscriptionDetail />
|
|
73
|
+
</Layout>
|
|
74
|
+
}
|
|
75
|
+
/>
|
|
76
|
+
<Route
|
|
77
|
+
key="customer-subscription-change-plan"
|
|
78
|
+
path="/customer/subscription/:id/change-plan"
|
|
79
|
+
element={
|
|
80
|
+
<Layout>
|
|
81
|
+
<CustomerSubscriptionChangePlan />
|
|
82
|
+
</Layout>
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
<Route
|
|
86
|
+
key="customer-subscription-change-payment"
|
|
87
|
+
path="/customer/subscription/:id/change-payment"
|
|
88
|
+
element={
|
|
89
|
+
<Layout>
|
|
90
|
+
<CustomerSubscriptionChangePayment />
|
|
91
|
+
</Layout>
|
|
92
|
+
}
|
|
93
|
+
/>
|
|
94
|
+
<Route key="subscription-embed" path="/customer/embed/subscription" element={<MiniInvoiceList />} />,
|
|
95
|
+
<Route
|
|
96
|
+
key="customer-due"
|
|
97
|
+
path="/customer/invoice/past-due"
|
|
98
|
+
element={
|
|
99
|
+
<Layout>
|
|
100
|
+
<CustomerInvoicePastDue />
|
|
101
|
+
</Layout>
|
|
102
|
+
}
|
|
103
|
+
/>
|
|
104
|
+
<Route
|
|
105
|
+
key="customer-invoice"
|
|
106
|
+
path="/customer/invoice/:id"
|
|
107
|
+
element={
|
|
108
|
+
<Layout>
|
|
109
|
+
<CustomerInvoiceDetail />
|
|
110
|
+
</Layout>
|
|
111
|
+
}
|
|
112
|
+
/>
|
|
113
|
+
<Route key="customer-fallback" path="/customer/*" element={<Navigate to="/customer" />} />,
|
|
114
|
+
<Route path="*" element={<Navigate to="/" />} />
|
|
115
|
+
</Routes>
|
|
116
|
+
</Suspense>
|
|
117
|
+
</ErrorBoundary>
|
|
118
|
+
</LocaleProvider>
|
|
119
|
+
</TransitionProvider>
|
|
117
120
|
</ThemeProvider>
|
|
118
121
|
);
|
|
119
122
|
}
|
|
@@ -8,6 +8,7 @@ import { useRequest } from 'ahooks';
|
|
|
8
8
|
import { useEffect, useState } from 'react';
|
|
9
9
|
import { useNavigate } from 'react-router-dom';
|
|
10
10
|
|
|
11
|
+
import { useTransitionContext } from '../progress-bar';
|
|
11
12
|
import Table from '../table';
|
|
12
13
|
|
|
13
14
|
const fetchData = (params: Record<string, any> = {}): Promise<{ list: TEventExpanded[]; count: number }> => {
|
|
@@ -141,6 +142,7 @@ export default function EventList({ type, object_id, features }: ListProps) {
|
|
|
141
142
|
pageSize: persisted.rowsPerPage || 50,
|
|
142
143
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
143
144
|
});
|
|
145
|
+
const { startTransition } = useTransitionContext();
|
|
144
146
|
|
|
145
147
|
const { loading, error, data, refresh } = useRequest(() => fetchData(search));
|
|
146
148
|
useEffect(() => {
|
|
@@ -207,7 +209,9 @@ export default function EventList({ type, object_id, features }: ListProps) {
|
|
|
207
209
|
rowsPerPage: search.pageSize,
|
|
208
210
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
209
211
|
const item = data.list[dataIndex] as TEventExpanded;
|
|
210
|
-
|
|
212
|
+
startTransition(() => {
|
|
213
|
+
navigate(`/admin/developers/${item.id}`);
|
|
214
|
+
});
|
|
211
215
|
},
|
|
212
216
|
}}
|
|
213
217
|
toolbar={features?.toolbar}
|
|
@@ -2,7 +2,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
|
2
2
|
import { api, usePaymentContext } from '@blocklet/payment-react';
|
|
3
3
|
import type { TCustomer } from '@blocklet/payment-types';
|
|
4
4
|
import { Add, Close } from '@mui/icons-material';
|
|
5
|
-
import { ClickAwayListener, Menu, MenuItem } from '@mui/material';
|
|
5
|
+
import { Button, ClickAwayListener, Menu, MenuItem } from '@mui/material';
|
|
6
6
|
import { Box, styled } from '@mui/system';
|
|
7
7
|
import { useEffect, useState } from 'react';
|
|
8
8
|
|
|
@@ -86,7 +86,7 @@ function SearchStatus({ status = [], setSearch }: Pick<Props, 'status' | 'setSea
|
|
|
86
86
|
onClick={(e) => {
|
|
87
87
|
setShow(e.currentTarget as any);
|
|
88
88
|
}}>
|
|
89
|
-
<
|
|
89
|
+
<Button className="option-btn" variant="text">
|
|
90
90
|
{display ? (
|
|
91
91
|
<Close
|
|
92
92
|
sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }}
|
|
@@ -104,7 +104,7 @@ function SearchStatus({ status = [], setSearch }: Pick<Props, 'status' | 'setSea
|
|
|
104
104
|
)}
|
|
105
105
|
{t('common.status')}
|
|
106
106
|
<span>{display}</span>
|
|
107
|
-
</
|
|
107
|
+
</Button>
|
|
108
108
|
<Menu
|
|
109
109
|
anchorEl={show}
|
|
110
110
|
open={Boolean(show)}
|
|
@@ -155,7 +155,7 @@ function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
155
155
|
onClick={(e) => {
|
|
156
156
|
setShow(e.currentTarget as any);
|
|
157
157
|
}}>
|
|
158
|
-
<
|
|
158
|
+
<Button className="option-btn" variant="text">
|
|
159
159
|
{display ? (
|
|
160
160
|
<Close
|
|
161
161
|
sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }}
|
|
@@ -173,7 +173,7 @@ function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
173
173
|
)}
|
|
174
174
|
{t('common.currency')}
|
|
175
175
|
<span>{display}</span>
|
|
176
|
-
</
|
|
176
|
+
</Button>
|
|
177
177
|
<Menu
|
|
178
178
|
anchorEl={show}
|
|
179
179
|
open={Boolean(show)}
|
|
@@ -226,7 +226,7 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
226
226
|
|
|
227
227
|
return (
|
|
228
228
|
<section onClick={(e: any) => setShow(e.currentTarget)}>
|
|
229
|
-
<
|
|
229
|
+
<Button className="option-btn" variant="text">
|
|
230
230
|
{display ? (
|
|
231
231
|
<Close
|
|
232
232
|
sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }}
|
|
@@ -244,7 +244,7 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
244
244
|
)}
|
|
245
245
|
{t('common.customer')}
|
|
246
246
|
<span>{display}</span>
|
|
247
|
-
</
|
|
247
|
+
</Button>
|
|
248
248
|
|
|
249
249
|
<Menu
|
|
250
250
|
anchorEl={show}
|
|
@@ -327,7 +327,7 @@ function SearchProducts({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
327
327
|
setShow(false);
|
|
328
328
|
}}>
|
|
329
329
|
<section onClick={() => setShow(!show)}>
|
|
330
|
-
<
|
|
330
|
+
<Button className="option-btn" variant="text">
|
|
331
331
|
{display ? (
|
|
332
332
|
<Close
|
|
333
333
|
sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }}
|
|
@@ -345,7 +345,7 @@ function SearchProducts({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
345
345
|
)}
|
|
346
346
|
{t('admin.subscription.product')}
|
|
347
347
|
<span>{display}</span>
|
|
348
|
-
</
|
|
348
|
+
</Button>
|
|
349
349
|
|
|
350
350
|
<ul
|
|
351
351
|
className="status-options"
|
|
@@ -388,7 +388,11 @@ const Root = styled(Box)`
|
|
|
388
388
|
align-items: center;
|
|
389
389
|
border-radius: 25px;
|
|
390
390
|
background: #f6f6f6;
|
|
391
|
-
padding:
|
|
391
|
+
padding: 5px 10px;
|
|
392
|
+
color: #555;
|
|
393
|
+
font-size: 14px;
|
|
394
|
+
line-height: 14px;
|
|
395
|
+
overflow: hidden;
|
|
392
396
|
}
|
|
393
397
|
|
|
394
398
|
.option-btn span {
|
|
@@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom';
|
|
|
10
10
|
|
|
11
11
|
import CustomerLink from '../customer/link';
|
|
12
12
|
import FilterToolbar from '../filter-toolbar';
|
|
13
|
+
import { useTransitionContext } from '../progress-bar';
|
|
13
14
|
import Table from '../table';
|
|
14
15
|
import InvoiceActions from './action';
|
|
15
16
|
|
|
@@ -93,6 +94,7 @@ export default function InvoiceList({ customer_id, subscription_id, features, st
|
|
|
93
94
|
pageSize: persisted.rowsPerPage || 20,
|
|
94
95
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
95
96
|
});
|
|
97
|
+
const { startTransition } = useTransitionContext();
|
|
96
98
|
|
|
97
99
|
const [data, setData] = useState({}) as any;
|
|
98
100
|
|
|
@@ -228,7 +230,7 @@ export default function InvoiceList({ customer_id, subscription_id, features, st
|
|
|
228
230
|
if (invoiceProps?.onClick) {
|
|
229
231
|
await invoiceProps.onClick(item);
|
|
230
232
|
} else {
|
|
231
|
-
navigate(`/admin/billing/${item.id}`);
|
|
233
|
+
startTransition(() => navigate(`/admin/billing/${item.id}`));
|
|
232
234
|
}
|
|
233
235
|
},
|
|
234
236
|
onColumnSortChange(_: any, order: any) {
|
|
@@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
|
|
|
11
11
|
import { debounce } from '../../libs/util';
|
|
12
12
|
import CustomerLink from '../customer/link';
|
|
13
13
|
import FilterToolbar from '../filter-toolbar';
|
|
14
|
+
import { useTransitionContext } from '../progress-bar';
|
|
14
15
|
import Table from '../table';
|
|
15
16
|
import PaymentIntentActions from './actions';
|
|
16
17
|
|
|
@@ -84,6 +85,7 @@ export default function PaymentList({ customer_id, invoice_id, features }: ListP
|
|
|
84
85
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
85
86
|
});
|
|
86
87
|
|
|
88
|
+
const { startTransition } = useTransitionContext();
|
|
87
89
|
const [data, setData] = useState({}) as any;
|
|
88
90
|
|
|
89
91
|
useEffect(() => {
|
|
@@ -239,7 +241,9 @@ export default function PaymentList({ customer_id, invoice_id, features }: ListP
|
|
|
239
241
|
},
|
|
240
242
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
241
243
|
const item = data.list[dataIndex] as TPaymentIntentExpanded;
|
|
242
|
-
|
|
244
|
+
startTransition(() => {
|
|
245
|
+
navigate(`/admin/payments/${item.id}`);
|
|
246
|
+
});
|
|
243
247
|
},
|
|
244
248
|
}}
|
|
245
249
|
toolbar={features?.toolbar}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import Box from '@mui/material/Box';
|
|
2
|
+
import LinearProgress from '@mui/material/LinearProgress';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
pending: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function ProgressBar({ pending = true }: Props) {
|
|
10
|
+
const [progress, setProgress] = React.useState(0);
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
const timer = setInterval(
|
|
13
|
+
() => {
|
|
14
|
+
setProgress((oldProgress) => {
|
|
15
|
+
if (oldProgress === 100) {
|
|
16
|
+
if (timer) {
|
|
17
|
+
clearInterval(timer);
|
|
18
|
+
}
|
|
19
|
+
return -1;
|
|
20
|
+
}
|
|
21
|
+
const diff = Math.random() * 10;
|
|
22
|
+
return Math.min(oldProgress + diff, 100);
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
pending ? 500 : 30
|
|
26
|
+
); // 如果已完成,就加速
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
clearInterval(timer);
|
|
30
|
+
};
|
|
31
|
+
}, [pending]);
|
|
32
|
+
return (
|
|
33
|
+
<Box sx={{ width: '100%', height: '4px', position: 'fixed', top: 0, left: 0, zIndex: '999999' }}>
|
|
34
|
+
<LinearProgress
|
|
35
|
+
variant="determinate"
|
|
36
|
+
value={progress}
|
|
37
|
+
sx={{ opacity: progress === -1 ? 0 : 1, transition: '0.3s' }}
|
|
38
|
+
/>
|
|
39
|
+
</Box>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const Transition = React.createContext({
|
|
44
|
+
startTransition: null,
|
|
45
|
+
} as any);
|
|
46
|
+
|
|
47
|
+
export function TransitionProvider({ children }: { children: React.ReactNode }) {
|
|
48
|
+
const [isPending, startTransition] = React.useTransition();
|
|
49
|
+
|
|
50
|
+
const memoObj = React.useMemo(() => ({ isPending, startTransition }), [isPending]);
|
|
51
|
+
return <Transition.Provider value={memoObj}>{children}</Transition.Provider>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function useTransitionContext() {
|
|
55
|
+
return React.useContext(Transition);
|
|
56
|
+
}
|
|
@@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom';
|
|
|
10
10
|
|
|
11
11
|
import CustomerLink from '../customer/link';
|
|
12
12
|
import FilterToolbar from '../filter-toolbar';
|
|
13
|
+
import { useTransitionContext } from '../progress-bar';
|
|
13
14
|
import Table from '../table';
|
|
14
15
|
import RefundActions from './actions';
|
|
15
16
|
|
|
@@ -74,7 +75,7 @@ RefundList.defaultProps = {
|
|
|
74
75
|
export default function RefundList({ customer_id, invoice_id, subscription_id, features }: ListProps) {
|
|
75
76
|
const { t } = useLocaleContext();
|
|
76
77
|
const navigate = useNavigate();
|
|
77
|
-
|
|
78
|
+
const { startTransition } = useTransitionContext();
|
|
78
79
|
const listKey = getListKey({ customer_id, invoice_id });
|
|
79
80
|
|
|
80
81
|
const persisted = getDurableData(listKey);
|
|
@@ -199,7 +200,9 @@ export default function RefundList({ customer_id, invoice_id, subscription_id, f
|
|
|
199
200
|
rowsPerPage: search.pageSize,
|
|
200
201
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
201
202
|
const item = data.list[dataIndex] as TRefundExpanded;
|
|
202
|
-
|
|
203
|
+
startTransition(() => {
|
|
204
|
+
navigate(`/admin/payments/${item.id}`);
|
|
205
|
+
});
|
|
203
206
|
},
|
|
204
207
|
onColumnSortChange(_: any, order: any) {
|
|
205
208
|
setSearch({
|
|
@@ -9,6 +9,7 @@ import { useNavigate } from 'react-router-dom';
|
|
|
9
9
|
|
|
10
10
|
import CustomerLink from '../customer/link';
|
|
11
11
|
import FilterToolbar from '../filter-toolbar';
|
|
12
|
+
import { useTransitionContext } from '../progress-bar';
|
|
12
13
|
import Table from '../table';
|
|
13
14
|
import SubscriptionActions from './actions';
|
|
14
15
|
import SubscriptionDescription from './description';
|
|
@@ -71,6 +72,7 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
71
72
|
|
|
72
73
|
const { t } = useLocaleContext();
|
|
73
74
|
const navigate = useNavigate();
|
|
75
|
+
const { startTransition } = useTransitionContext();
|
|
74
76
|
const [search, setSearch] = useState<SearchProps>({
|
|
75
77
|
status: status as string,
|
|
76
78
|
customer_id,
|
|
@@ -192,7 +194,9 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
192
194
|
rowsPerPage: search.pageSize,
|
|
193
195
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
194
196
|
const item = data.list[dataIndex] as TSubscriptionExpanded;
|
|
195
|
-
|
|
197
|
+
startTransition(() => {
|
|
198
|
+
navigate(`/admin/billing/${item.id}`);
|
|
199
|
+
});
|
|
196
200
|
},
|
|
197
201
|
onColumnSortChange(_: any, order: any) {
|
|
198
202
|
setSearch({
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
|
-
import React, { isValidElement
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const SubscriptionDetail = React.lazy(() => import('./subscriptions/detail'));
|
|
8
10
|
const InvoiceDetail = React.lazy(() => import('./invoices/detail'));
|
|
9
11
|
|
|
@@ -16,6 +18,7 @@ export default function BillingIndex() {
|
|
|
16
18
|
const navigate = useNavigate();
|
|
17
19
|
const { t } = useLocaleContext();
|
|
18
20
|
const { page = 'invoices' } = useParams();
|
|
21
|
+
const { startTransition } = useTransitionContext();
|
|
19
22
|
|
|
20
23
|
if (page.startsWith('sub_')) {
|
|
21
24
|
return <SubscriptionDetail id={page} />;
|
|
@@ -8,6 +8,7 @@ import { Avatar, CircularProgress, Stack, Typography } from '@mui/material';
|
|
|
8
8
|
import { useEffect, useState } from 'react';
|
|
9
9
|
import { useNavigate } from 'react-router-dom';
|
|
10
10
|
|
|
11
|
+
import { useTransitionContext } from '../../../../components/progress-bar';
|
|
11
12
|
import Table from '../../../../components/table';
|
|
12
13
|
|
|
13
14
|
const fetchData = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
|
|
@@ -30,6 +31,7 @@ export default function CustomersList() {
|
|
|
30
31
|
|
|
31
32
|
const { t } = useLocaleContext();
|
|
32
33
|
const navigate = useNavigate();
|
|
34
|
+
const { startTransition } = useTransitionContext();
|
|
33
35
|
const [search, setSearch] = useState<{ active?: string; pageSize: number; page: number; q?: any; o?: string }>({
|
|
34
36
|
active: '',
|
|
35
37
|
o: 'desc',
|
|
@@ -118,7 +120,9 @@ export default function CustomersList() {
|
|
|
118
120
|
rowsPerPage: search.pageSize,
|
|
119
121
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
120
122
|
const item = data.list[dataIndex] as TCustomer;
|
|
121
|
-
|
|
123
|
+
startTransition(() => {
|
|
124
|
+
navigate(`/admin/customers/${item.id}`);
|
|
125
|
+
});
|
|
122
126
|
},
|
|
123
127
|
onColumnSortChange(_: any, order: any) {
|
|
124
128
|
setSearch({
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
|
-
import React, { isValidElement
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const CustomerDetail = React.lazy(() => import('./customers/detail'));
|
|
8
10
|
|
|
9
11
|
const pages = {
|
|
@@ -14,6 +16,7 @@ export default function CustomerIndex() {
|
|
|
14
16
|
const navigate = useNavigate();
|
|
15
17
|
const { t } = useLocaleContext();
|
|
16
18
|
const { page = 'overview' } = useParams();
|
|
19
|
+
const { startTransition } = useTransitionContext();
|
|
17
20
|
|
|
18
21
|
if (page.startsWith('cus_')) {
|
|
19
22
|
return <CustomerDetail id={page} />;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
|
-
import React, { isValidElement
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const EventDetail = React.lazy(() => import('./events/detail'));
|
|
8
10
|
const WebhookDetail = React.lazy(() => import('./webhooks/detail'));
|
|
9
11
|
|
|
@@ -18,6 +20,7 @@ export default function DevelopersIndex() {
|
|
|
18
20
|
const navigate = useNavigate();
|
|
19
21
|
const { t } = useLocaleContext();
|
|
20
22
|
const { page = 'overview' } = useParams();
|
|
23
|
+
const { startTransition } = useTransitionContext();
|
|
21
24
|
|
|
22
25
|
if (page.startsWith('evt_')) {
|
|
23
26
|
return <EventDetail id={page} />;
|
|
@@ -8,6 +8,7 @@ import { useRequest } from 'ahooks';
|
|
|
8
8
|
import { useEffect, useState } from 'react';
|
|
9
9
|
import { useNavigate } from 'react-router-dom';
|
|
10
10
|
|
|
11
|
+
import { useTransitionContext } from '../../../../components/progress-bar';
|
|
11
12
|
import Table from '../../../../components/table';
|
|
12
13
|
import { getWebhookStatusColor } from '../../../../libs/util';
|
|
13
14
|
|
|
@@ -25,6 +26,7 @@ export default function WebhooksList() {
|
|
|
25
26
|
|
|
26
27
|
const { t } = useLocaleContext();
|
|
27
28
|
const navigate = useNavigate();
|
|
29
|
+
const { startTransition } = useTransitionContext();
|
|
28
30
|
const [search, setSearch] = useState<{ active: string; pageSize: number; page: number }>({
|
|
29
31
|
active: '',
|
|
30
32
|
pageSize: persisted.rowsPerPage || 20,
|
|
@@ -90,7 +92,9 @@ export default function WebhooksList() {
|
|
|
90
92
|
rowsPerPage: search.pageSize,
|
|
91
93
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
92
94
|
const item = data.list[dataIndex] as TWebhookEndpoint;
|
|
93
|
-
|
|
95
|
+
startTransition(() => {
|
|
96
|
+
navigate(`/admin/developers/${item.id}`);
|
|
97
|
+
});
|
|
94
98
|
},
|
|
95
99
|
}}
|
|
96
100
|
loading={loading}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import { PaymentProvider, Switch, usePaymentContext } from '@blocklet/payment-react';
|
|
3
3
|
import { Box, Chip, Stack } from '@mui/material';
|
|
4
|
-
import React, {
|
|
4
|
+
import React, { isValidElement, useEffect } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
7
|
import Layout from '../../components/layout/admin';
|
|
8
|
+
import ProgressBar, { useTransitionContext } from '../../components/progress-bar';
|
|
8
9
|
import { useSessionContext } from '../../contexts/session';
|
|
9
10
|
|
|
10
11
|
const groups = {
|
|
@@ -43,6 +44,7 @@ function Admin() {
|
|
|
43
44
|
const { t } = useLocaleContext();
|
|
44
45
|
const settings = usePaymentContext();
|
|
45
46
|
const { group = 'overview' } = useParams();
|
|
47
|
+
const { isPending, startTransition } = useTransitionContext();
|
|
46
48
|
|
|
47
49
|
const onLivemodeChange = (e: any) => {
|
|
48
50
|
settings.setLivemode(!e.target.checked);
|
|
@@ -71,6 +73,7 @@ function Admin() {
|
|
|
71
73
|
|
|
72
74
|
return (
|
|
73
75
|
<Layout>
|
|
76
|
+
<ProgressBar pending={isPending} />
|
|
74
77
|
<Stack
|
|
75
78
|
direction="row"
|
|
76
79
|
alignItems="center"
|
|
@@ -99,9 +102,7 @@ function Admin() {
|
|
|
99
102
|
</label>
|
|
100
103
|
</Stack>
|
|
101
104
|
</Stack>
|
|
102
|
-
<
|
|
103
|
-
<div className="page-content">{isValidElement(TabComponent) ? TabComponent : <TabComponent />}</div>
|
|
104
|
-
</Suspense>
|
|
105
|
+
<div className="page-content">{isValidElement(TabComponent) ? TabComponent : <TabComponent />}</div>
|
|
105
106
|
</Layout>
|
|
106
107
|
);
|
|
107
108
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
3
|
import { Stack, Typography } from '@mui/material';
|
|
4
|
-
import React, { isValidElement
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const PaymentLinkCreate = React.lazy(() => import('./links/create'));
|
|
8
10
|
const PaymentLinkDetail = React.lazy(() => import('./links/detail'));
|
|
9
11
|
const PaymentIntentDetail = React.lazy(() => import('./intents/detail'));
|
|
@@ -19,6 +21,7 @@ export default function PaymentIndex() {
|
|
|
19
21
|
const navigate = useNavigate();
|
|
20
22
|
const { t } = useLocaleContext();
|
|
21
23
|
const { page = 'intents' } = useParams();
|
|
24
|
+
const { startTransition } = useTransitionContext();
|
|
22
25
|
|
|
23
26
|
if (page.startsWith('pi_')) {
|
|
24
27
|
return <PaymentIntentDetail id={page} />;
|
|
@@ -12,6 +12,7 @@ import useBus from 'use-bus';
|
|
|
12
12
|
|
|
13
13
|
import Copyable from '../../../../components/copyable';
|
|
14
14
|
import PaymentLinkActions from '../../../../components/payment-link/actions';
|
|
15
|
+
import { useTransitionContext } from '../../../../components/progress-bar';
|
|
15
16
|
import Table from '../../../../components/table';
|
|
16
17
|
import { ProductsProvider } from '../../../../contexts/products';
|
|
17
18
|
import { formatPaymentLinkPricing } from '../../../../libs/util';
|
|
@@ -29,6 +30,7 @@ function PaymentLinks() {
|
|
|
29
30
|
const { t } = useLocaleContext();
|
|
30
31
|
const { settings } = usePaymentContext();
|
|
31
32
|
const navigate = useNavigate();
|
|
33
|
+
const { startTransition } = useTransitionContext();
|
|
32
34
|
|
|
33
35
|
const persisted = getDurableData(listKey);
|
|
34
36
|
const [search, setSearch] = useState<{ active: string; pageSize: number; page: number }>({
|
|
@@ -148,7 +150,9 @@ function PaymentLinks() {
|
|
|
148
150
|
rowsPerPage: search.pageSize,
|
|
149
151
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
150
152
|
const item = data.list[dataIndex] as TPaymentLinkExpanded;
|
|
151
|
-
|
|
153
|
+
startTransition(() => {
|
|
154
|
+
navigate(`/admin/payments/${item.id}`);
|
|
155
|
+
});
|
|
152
156
|
},
|
|
153
157
|
}}
|
|
154
158
|
loading={loading}
|
|
@@ -4,6 +4,8 @@ import { Stack, Typography } from '@mui/material';
|
|
|
4
4
|
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const ProductCreate = React.lazy(() => import('./products/create'));
|
|
8
10
|
const ProductDetail = React.lazy(() => import('./products/detail'));
|
|
9
11
|
const PriceDetail = React.lazy(() => import('./prices/detail'));
|
|
@@ -21,6 +23,7 @@ export default function Products() {
|
|
|
21
23
|
const navigate = useNavigate();
|
|
22
24
|
const { t } = useLocaleContext();
|
|
23
25
|
const { page = 'products' } = useParams();
|
|
26
|
+
const { startTransition } = useTransitionContext();
|
|
24
27
|
|
|
25
28
|
if (page.startsWith('prod_')) {
|
|
26
29
|
return <ProductDetail id={page} />;
|
|
@@ -61,7 +64,7 @@ export default function Products() {
|
|
|
61
64
|
<Tabs
|
|
62
65
|
tabs={tabs}
|
|
63
66
|
current={page}
|
|
64
|
-
onChange={(newTab: string) => navigate(`/admin/products/${newTab}`)}
|
|
67
|
+
onChange={(newTab: string) => startTransition(() => navigate(`/admin/products/${newTab}`))}
|
|
65
68
|
scrollButtons="auto"
|
|
66
69
|
/>
|
|
67
70
|
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
@@ -12,6 +12,7 @@ import useBus from 'use-bus';
|
|
|
12
12
|
|
|
13
13
|
import Copyable from '../../../../components/copyable';
|
|
14
14
|
import PricingTableActions from '../../../../components/pricing-table/actions';
|
|
15
|
+
import { useTransitionContext } from '../../../../components/progress-bar';
|
|
15
16
|
import Table from '../../../../components/table';
|
|
16
17
|
import { ProductsProvider } from '../../../../contexts/products';
|
|
17
18
|
|
|
@@ -27,6 +28,7 @@ function PricingTables() {
|
|
|
27
28
|
const listKey = 'pricing-tables';
|
|
28
29
|
const { t } = useLocaleContext();
|
|
29
30
|
const navigate = useNavigate();
|
|
31
|
+
const { startTransition } = useTransitionContext();
|
|
30
32
|
|
|
31
33
|
const persisted = getDurableData(listKey);
|
|
32
34
|
const [search, setSearch] = useState<{ active: string; pageSize: number; page: number }>({
|
|
@@ -135,7 +137,9 @@ function PricingTables() {
|
|
|
135
137
|
rowsPerPage: search.pageSize,
|
|
136
138
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
137
139
|
const item = data.list[dataIndex] as TPricingTableExpanded;
|
|
138
|
-
|
|
140
|
+
startTransition(() => {
|
|
141
|
+
navigate(`/admin/products/${item.id}`);
|
|
142
|
+
});
|
|
139
143
|
},
|
|
140
144
|
}}
|
|
141
145
|
loading={loading}
|
|
@@ -7,9 +7,10 @@ import { CircularProgress } from '@mui/material';
|
|
|
7
7
|
import { useEffect, useState } from 'react';
|
|
8
8
|
import { useNavigate } from 'react-router-dom';
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import FilterToolbar from '../../../../components/filter-toolbar';
|
|
11
11
|
import InfoCard from '../../../../components/info-card';
|
|
12
12
|
import ProductActions from '../../../../components/product/actions';
|
|
13
|
+
import { useTransitionContext } from '../../../../components/progress-bar';
|
|
13
14
|
import Table from '../../../../components/table';
|
|
14
15
|
import { formatProductPrice } from '../../../../libs/util';
|
|
15
16
|
|
|
@@ -33,6 +34,7 @@ export default function ProductsList() {
|
|
|
33
34
|
|
|
34
35
|
const { t, locale } = useLocaleContext();
|
|
35
36
|
const navigate = useNavigate();
|
|
37
|
+
const { startTransition } = useTransitionContext();
|
|
36
38
|
const { settings } = usePaymentContext();
|
|
37
39
|
const [search, setSearch] = useState<{ active: string; pageSize: number; page: any; q?: any; o?: any }>({
|
|
38
40
|
active: '',
|
|
@@ -130,7 +132,7 @@ export default function ProductsList() {
|
|
|
130
132
|
<Table
|
|
131
133
|
durable={listKey}
|
|
132
134
|
durableKeys={['page', 'rowsPerPage']}
|
|
133
|
-
title={<
|
|
135
|
+
title={<FilterToolbar setSearch={setSearch} search={search} status={['active', 'archived']} />}
|
|
134
136
|
data={data.list}
|
|
135
137
|
columns={columns}
|
|
136
138
|
options={{
|
|
@@ -165,7 +167,9 @@ export default function ProductsList() {
|
|
|
165
167
|
},
|
|
166
168
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
167
169
|
const item = data.list[dataIndex] as TProductExpanded;
|
|
168
|
-
|
|
170
|
+
startTransition(() => {
|
|
171
|
+
navigate(`/admin/products/${item.id}`);
|
|
172
|
+
});
|
|
169
173
|
},
|
|
170
174
|
}}
|
|
171
175
|
loading={!data.list}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
3
|
import { Stack, Typography } from '@mui/material';
|
|
4
|
-
import React, { isValidElement
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import { useTransitionContext } from '../../../components/progress-bar';
|
|
8
|
+
|
|
7
9
|
const PaymentMethodCreate = React.lazy(() => import('./payment-methods/create'));
|
|
8
10
|
|
|
9
11
|
const pages = {
|
|
@@ -16,6 +18,7 @@ export default function SettingsIndex() {
|
|
|
16
18
|
const navigate = useNavigate();
|
|
17
19
|
const { t } = useLocaleContext();
|
|
18
20
|
const { page = 'payment-methods' } = useParams();
|
|
21
|
+
const { startTransition } = useTransitionContext();
|
|
19
22
|
|
|
20
23
|
const onTabChange = (newTab: string) => {
|
|
21
24
|
startTransition(() => {
|
|
@@ -17,6 +17,7 @@ import BalanceList from '../../components/balance-list';
|
|
|
17
17
|
import EditCustomer from '../../components/customer/edit';
|
|
18
18
|
import InfoMetric from '../../components/info-metric';
|
|
19
19
|
import InfoRow from '../../components/info-row';
|
|
20
|
+
import ProgressBar, { useTransitionContext } from '../../components/progress-bar';
|
|
20
21
|
import SectionHeader from '../../components/section/header';
|
|
21
22
|
import CurrentSubscriptions from '../../components/subscription/portal/list';
|
|
22
23
|
import { useSessionContext } from '../../contexts/session';
|
|
@@ -31,6 +32,7 @@ export default function CustomerHome() {
|
|
|
31
32
|
const { events, session, connectApi } = useSessionContext();
|
|
32
33
|
const [state, setState] = useSetState({ editing: false, loading: false });
|
|
33
34
|
const navigate = useNavigate();
|
|
35
|
+
const { isPending, startTransition } = useTransitionContext();
|
|
34
36
|
|
|
35
37
|
const { loading, error, data, runAsync } = useRequest(fetchData);
|
|
36
38
|
|
|
@@ -71,115 +73,120 @@ export default function CustomerHome() {
|
|
|
71
73
|
};
|
|
72
74
|
|
|
73
75
|
return (
|
|
74
|
-
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<Box className="section
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
76
|
+
<>
|
|
77
|
+
<ProgressBar pending={isPending} />
|
|
78
|
+
<Grid container spacing={5}>
|
|
79
|
+
<Grid item xs={12} md={8}>
|
|
80
|
+
<Root direction="column" spacing={3} sx={{ my: 2 }}>
|
|
81
|
+
<Box className="section">
|
|
82
|
+
<SectionHeader title={t('payment.customer.subscriptions.current')} mb={0} />
|
|
83
|
+
<Box className="section-body">
|
|
84
|
+
<CurrentSubscriptions
|
|
85
|
+
id={data.id}
|
|
86
|
+
onChange={runAsync}
|
|
87
|
+
style={{
|
|
88
|
+
cursor: 'pointer',
|
|
89
|
+
}}
|
|
90
|
+
onClickSubscription={(subscription) => {
|
|
91
|
+
startTransition(() => {
|
|
92
|
+
navigate(`/customer/subscription/${subscription.id}`);
|
|
93
|
+
});
|
|
94
|
+
}}
|
|
95
|
+
/>
|
|
96
|
+
</Box>
|
|
90
97
|
</Box>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
</
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
98
|
+
<Box className="section">
|
|
99
|
+
<SectionHeader title={t('payment.customer.invoices')} mb={0}>
|
|
100
|
+
{isEmpty(data.summary.due) === false && (
|
|
101
|
+
<Tooltip title={t('payment.customer.pastDue.warning')}>
|
|
102
|
+
<Button
|
|
103
|
+
variant="contained"
|
|
104
|
+
color="error"
|
|
105
|
+
component="a"
|
|
106
|
+
size="small"
|
|
107
|
+
href={joinURL(window.location.origin, getPrefix(), '/customer/invoice/past-due')}
|
|
108
|
+
target="_blank"
|
|
109
|
+
rel="noreferrer"
|
|
110
|
+
style={{ textDecoration: 'none' }}>
|
|
111
|
+
{t('payment.customer.pastDue.invoices')}
|
|
112
|
+
</Button>
|
|
113
|
+
</Tooltip>
|
|
114
|
+
)}
|
|
115
|
+
</SectionHeader>
|
|
116
|
+
<Box className="section-body">
|
|
117
|
+
<CustomerInvoiceList customer_id={data.id} />
|
|
118
|
+
</Box>
|
|
112
119
|
</Box>
|
|
113
|
-
</
|
|
114
|
-
</
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
</
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
/>
|
|
155
|
-
</Stack>
|
|
156
|
-
{state.editing && (
|
|
157
|
-
<EditCustomer
|
|
158
|
-
data={data}
|
|
159
|
-
loading={state.loading}
|
|
160
|
-
onSave={onUpdateInfo}
|
|
161
|
-
onCancel={() => setState({ editing: false })}
|
|
162
|
-
/>
|
|
163
|
-
)}
|
|
164
|
-
</Box>
|
|
165
|
-
<Box className="section">
|
|
166
|
-
<SectionHeader title={t('payment.customer.summary')} />
|
|
167
|
-
<PaymentProvider session={session} connect={connectApi}>
|
|
168
|
-
<Stack
|
|
169
|
-
className="section-body"
|
|
170
|
-
direction="column"
|
|
171
|
-
spacing={2}
|
|
172
|
-
justifyContent="flex-start"
|
|
173
|
-
sx={{ width: '100%' }}>
|
|
174
|
-
<InfoMetric label={t('admin.customer.spent')} value={<BalanceList data={data.summary.paid} />} />
|
|
175
|
-
<InfoMetric label={t('admin.customer.due')} value={<BalanceList data={data.summary.due} />} />
|
|
176
|
-
<InfoMetric label={t('admin.customer.refund')} value={<BalanceList data={data.summary.refunded} />} />
|
|
120
|
+
</Root>
|
|
121
|
+
</Grid>
|
|
122
|
+
<Grid item xs={12} md={4}>
|
|
123
|
+
<Root direction="column" spacing={4} sx={{ my: 2 }}>
|
|
124
|
+
<Box className="section">
|
|
125
|
+
<SectionHeader title={t('payment.customer.details')}>
|
|
126
|
+
<Button
|
|
127
|
+
variant="outlined"
|
|
128
|
+
color="inherit"
|
|
129
|
+
size="small"
|
|
130
|
+
disabled={state.editing || state.loading}
|
|
131
|
+
onClick={() => setState({ editing: true })}>
|
|
132
|
+
<Edit fontSize="small" sx={{ mr: 0.5 }} />
|
|
133
|
+
{t('payment.customer.update')}
|
|
134
|
+
</Button>
|
|
135
|
+
</SectionHeader>
|
|
136
|
+
<Stack>
|
|
137
|
+
<InfoRow sizes={[1, 2]} label={t('common.did')} value={<DID copyable>{data.did}</DID>} />
|
|
138
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.name')} value={data.name} />
|
|
139
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.phone')} value={data.phone} />
|
|
140
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.email')} value={data.email} />
|
|
141
|
+
<InfoRow
|
|
142
|
+
sizes={[1, 2]}
|
|
143
|
+
label={t('admin.customer.address.country')}
|
|
144
|
+
value={
|
|
145
|
+
data.address?.country ? (
|
|
146
|
+
<FlagEmoji iso2={data.address?.country} style={{ display: 'flex', width: 24 }} />
|
|
147
|
+
) : (
|
|
148
|
+
''
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
/>
|
|
152
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.address.state')} value={data.address?.state} />
|
|
153
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.address.city')} value={data.address?.city} />
|
|
154
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.address.line1')} value={data.address?.line1} />
|
|
155
|
+
<InfoRow sizes={[1, 2]} label={t('admin.customer.address.line2')} value={data.address?.line2} />
|
|
156
|
+
<InfoRow
|
|
157
|
+
sizes={[1, 2]}
|
|
158
|
+
label={t('admin.customer.address.postal_code')}
|
|
159
|
+
value={data.address?.postal_code}
|
|
160
|
+
/>
|
|
177
161
|
</Stack>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
162
|
+
{state.editing && (
|
|
163
|
+
<EditCustomer
|
|
164
|
+
data={data}
|
|
165
|
+
loading={state.loading}
|
|
166
|
+
onSave={onUpdateInfo}
|
|
167
|
+
onCancel={() => setState({ editing: false })}
|
|
168
|
+
/>
|
|
169
|
+
)}
|
|
170
|
+
</Box>
|
|
171
|
+
<Box className="section">
|
|
172
|
+
<SectionHeader title={t('payment.customer.summary')} />
|
|
173
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
174
|
+
<Stack
|
|
175
|
+
className="section-body"
|
|
176
|
+
direction="column"
|
|
177
|
+
spacing={2}
|
|
178
|
+
justifyContent="flex-start"
|
|
179
|
+
sx={{ width: '100%' }}>
|
|
180
|
+
<InfoMetric label={t('admin.customer.spent')} value={<BalanceList data={data.summary.paid} />} />
|
|
181
|
+
<InfoMetric label={t('admin.customer.due')} value={<BalanceList data={data.summary.due} />} />
|
|
182
|
+
<InfoMetric label={t('admin.customer.refund')} value={<BalanceList data={data.summary.refunded} />} />
|
|
183
|
+
</Stack>
|
|
184
|
+
</PaymentProvider>
|
|
185
|
+
</Box>
|
|
186
|
+
</Root>
|
|
187
|
+
</Grid>
|
|
181
188
|
</Grid>
|
|
182
|
-
|
|
189
|
+
</>
|
|
183
190
|
);
|
|
184
191
|
}
|
|
185
192
|
|