payment-kit 1.13.15 → 1.13.16
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/routes/settings.ts +4 -2
- package/api/src/store/migrations/20230911-seeding.ts +40 -0
- package/blocklet.yml +1 -1
- package/package.json +4 -3
- package/src/app.tsx +22 -13
- package/src/locales/en.tsx +1 -0
- package/src/pages/admin/billing/index.tsx +3 -11
- package/src/pages/admin/customers/index.tsx +3 -11
- package/src/pages/admin/developers/index.tsx +3 -11
- package/src/pages/admin/index.tsx +3 -13
- package/src/pages/admin/payments/index.tsx +3 -11
- package/src/pages/admin/products/index.tsx +3 -11
- package/src/pages/admin/settings/index.tsx +3 -11
- package/src/pages/checkout/index.tsx +3 -11
- package/src/pages/customer/index.tsx +11 -1
- package/src/pages/home.tsx +33 -3
|
@@ -20,13 +20,15 @@ router.get('/', async (req, res) => {
|
|
|
20
20
|
|
|
21
21
|
methods.forEach((method) => {
|
|
22
22
|
// @ts-ignore
|
|
23
|
-
method.currencies = method.payment_currencies?.map((x) =>
|
|
23
|
+
method.currencies = method.payment_currencies?.map((x) =>
|
|
24
|
+
pick(x, ['id', 'name', 'symbol', 'decimal', 'logo', 'is_base_currency'])
|
|
25
|
+
);
|
|
24
26
|
});
|
|
25
27
|
|
|
26
28
|
res.json({
|
|
27
29
|
paymentMethods: methods.map((x) => pick(x, ['id', 'name', 'type', 'logo', 'currencies'])),
|
|
28
30
|
// @ts-ignore
|
|
29
|
-
baseCurrency: methods[0].currencies
|
|
31
|
+
baseCurrency: methods[0].currencies.find((x) => x.is_base_currency),
|
|
30
32
|
});
|
|
31
33
|
});
|
|
32
34
|
|
|
@@ -9,6 +9,8 @@ const genPaymentCurrencyId = createIdGenerator('pc', 12);
|
|
|
9
9
|
|
|
10
10
|
const abtId = genPaymentCurrencyId();
|
|
11
11
|
const tbaId = genPaymentCurrencyId();
|
|
12
|
+
const marsId = genPaymentCurrencyId();
|
|
13
|
+
const play3Id = genPaymentCurrencyId();
|
|
12
14
|
const mainId = genPaymentMethodId();
|
|
13
15
|
const betaId = genPaymentMethodId();
|
|
14
16
|
const now = new Date();
|
|
@@ -54,6 +56,44 @@ const paymentCurrencies = [
|
|
|
54
56
|
created_at: now,
|
|
55
57
|
updated_at: now,
|
|
56
58
|
},
|
|
59
|
+
{
|
|
60
|
+
id: marsId,
|
|
61
|
+
active: true,
|
|
62
|
+
livemode: false,
|
|
63
|
+
locked: true,
|
|
64
|
+
is_base_currency: false,
|
|
65
|
+
payment_method_id: betaId,
|
|
66
|
+
name: 'RollupTestToken',
|
|
67
|
+
description: 'Token to test rollup on staging',
|
|
68
|
+
logo,
|
|
69
|
+
symbol: 'MARS',
|
|
70
|
+
decimal: 18,
|
|
71
|
+
minimum_payment_amount: fromTokenToUnit(0.1, 18).toString(), // 0.1 token
|
|
72
|
+
maximum_payment_amount: fromTokenToUnit(100000000, 18).toString(), // 0.1 billion
|
|
73
|
+
contract: 'z35n4nCsnAEWa2zVSKNKZhDGXSszaJAogSc3A',
|
|
74
|
+
metadata: {},
|
|
75
|
+
created_at: now,
|
|
76
|
+
updated_at: now,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: play3Id,
|
|
80
|
+
active: true,
|
|
81
|
+
livemode: false,
|
|
82
|
+
locked: true,
|
|
83
|
+
is_base_currency: false,
|
|
84
|
+
payment_method_id: betaId,
|
|
85
|
+
name: 'Playground Token',
|
|
86
|
+
description: 'Test Token for OCAP Playground',
|
|
87
|
+
logo,
|
|
88
|
+
symbol: 'PLAY3',
|
|
89
|
+
decimal: 18,
|
|
90
|
+
minimum_payment_amount: fromTokenToUnit(0.1, 18).toString(), // 0.1 token
|
|
91
|
+
maximum_payment_amount: fromTokenToUnit(100000000, 18).toString(), // 0.1 billion
|
|
92
|
+
contract: 'z35n3WVTnN7KrR4gXn3szR6oneVefkBBx78Fc',
|
|
93
|
+
metadata: {},
|
|
94
|
+
created_at: now,
|
|
95
|
+
updated_at: now,
|
|
96
|
+
},
|
|
57
97
|
];
|
|
58
98
|
|
|
59
99
|
const paymentMethods = [
|
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.16",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"rimraf": "^3.0.2",
|
|
86
86
|
"sequelize": "^6.33.0",
|
|
87
87
|
"sqlite3": "^5.1.6",
|
|
88
|
+
"typewriter-effect": "^2.21.0",
|
|
88
89
|
"ufo": "^1.3.0",
|
|
89
90
|
"umzug": "^3.3.1",
|
|
90
91
|
"use-bus": "^2.5.2"
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
"devDependencies": {
|
|
93
94
|
"@arcblock/eslint-config": "^0.2.4",
|
|
94
95
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
95
|
-
"@did-pay/types": "1.13.
|
|
96
|
+
"@did-pay/types": "1.13.16",
|
|
96
97
|
"@types/cookie-parser": "^1.4.3",
|
|
97
98
|
"@types/cors": "^2.8.13",
|
|
98
99
|
"@types/dotenv-flow": "^3.2.0",
|
|
@@ -129,5 +130,5 @@
|
|
|
129
130
|
"parser": "typescript"
|
|
130
131
|
}
|
|
131
132
|
},
|
|
132
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "c373817d035b5af72e98e333f36922c296be0ea6"
|
|
133
134
|
}
|
package/src/app.tsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import './global.css';
|
|
2
2
|
|
|
3
|
+
import Center from '@arcblock/ux/lib/Center';
|
|
3
4
|
import { LocaleProvider } from '@arcblock/ux/lib/Locale/context';
|
|
4
5
|
import { ThemeProvider, createTheme } from '@arcblock/ux/lib/Theme';
|
|
5
6
|
import { ToastProvider } from '@arcblock/ux/lib/Toast';
|
|
6
|
-
import
|
|
7
|
+
import { CircularProgress } from '@mui/material';
|
|
8
|
+
import React, { Suspense } from 'react';
|
|
7
9
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
8
10
|
import { Navigate, Route, BrowserRouter as Router, Routes } from 'react-router-dom';
|
|
9
11
|
import { joinURL } from 'ufo';
|
|
@@ -32,18 +34,25 @@ function App() {
|
|
|
32
34
|
<ThemeProvider theme={theme}>
|
|
33
35
|
<LocaleProvider translations={translations} fallbackLocale="en">
|
|
34
36
|
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={window.location.reload}>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
<Suspense
|
|
38
|
+
fallback={
|
|
39
|
+
<Center relative="parent">
|
|
40
|
+
<CircularProgress />
|
|
41
|
+
</Center>
|
|
42
|
+
}>
|
|
43
|
+
<Routes>
|
|
44
|
+
<Route path="/" element={<HomePage />} />
|
|
45
|
+
<Route path="/checkout/:action/:id" element={<CheckoutPage />} />
|
|
46
|
+
<Route key="admin-index" path="/admin" element={<AdminPage />} />,
|
|
47
|
+
<Route key="admin-tabs" path="/admin/:group" element={<AdminPage />} />,
|
|
48
|
+
<Route key="admin-sub" path="/admin/:group/:page" element={<AdminPage />} />,
|
|
49
|
+
<Route key="admin-fallback" path="/admin/*" element={<AdminPage />} />,
|
|
50
|
+
<Route key="customer-home" path="/customer" element={<CustomerHome />} />,
|
|
51
|
+
<Route key="customer-invoice" path="/customer/invoice/:id" element={<CustomerInvoice />} />,
|
|
52
|
+
<Route key="customer-fallback" path="/customer/*" element={<Navigate to="/customer" />} />,
|
|
53
|
+
<Route path="*" element={<Navigate to="/" />} />
|
|
54
|
+
</Routes>
|
|
55
|
+
</Suspense>
|
|
47
56
|
</ErrorBoundary>
|
|
48
57
|
</LocaleProvider>
|
|
49
58
|
</ThemeProvider>
|
package/src/locales/en.tsx
CHANGED
|
@@ -363,6 +363,7 @@ export default flat({
|
|
|
363
363
|
invoices: 'Invoice History',
|
|
364
364
|
details: 'Billing Details',
|
|
365
365
|
update: 'Update',
|
|
366
|
+
empty: 'Seems you do not have any subscriptions or payments here',
|
|
366
367
|
cancel: {
|
|
367
368
|
button: 'Cancel',
|
|
368
369
|
title: 'Cancel your subscription',
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
6
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
7
6
|
|
|
8
7
|
const SubscriptionDetail = React.lazy(() => import('./subscriptions/detail'));
|
|
@@ -43,14 +42,7 @@ export default function BillingIndex() {
|
|
|
43
42
|
{t('admin.billing')}
|
|
44
43
|
</Typography>
|
|
45
44
|
<Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
|
|
46
|
-
<
|
|
47
|
-
fallback={
|
|
48
|
-
<Center relative="parent">
|
|
49
|
-
<CircularProgress />
|
|
50
|
-
</Center>
|
|
51
|
-
}>
|
|
52
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
53
|
-
</Suspense>
|
|
45
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
54
46
|
</div>
|
|
55
47
|
);
|
|
56
48
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
6
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
7
6
|
|
|
8
7
|
const CustomerDetail = React.lazy(() => import('./customers/detail'));
|
|
@@ -34,14 +33,7 @@ export default function CustomerIndex() {
|
|
|
34
33
|
{t('admin.customers')}
|
|
35
34
|
</Typography>
|
|
36
35
|
<Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
|
|
37
|
-
<
|
|
38
|
-
fallback={
|
|
39
|
-
<Center relative="parent">
|
|
40
|
-
<CircularProgress />
|
|
41
|
-
</Center>
|
|
42
|
-
}>
|
|
43
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
44
|
-
</Suspense>
|
|
36
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
45
37
|
</div>
|
|
46
38
|
);
|
|
47
39
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
6
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
7
6
|
|
|
8
7
|
const EventDetail = React.lazy(() => import('./events/detail'));
|
|
@@ -47,14 +46,7 @@ export default function DevelopersIndex() {
|
|
|
47
46
|
{t('admin.developers')}
|
|
48
47
|
</Typography>
|
|
49
48
|
<Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
|
|
50
|
-
<
|
|
51
|
-
fallback={
|
|
52
|
-
<Center relative="parent">
|
|
53
|
-
<CircularProgress />
|
|
54
|
-
</Center>
|
|
55
|
-
}>
|
|
56
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
57
|
-
</Suspense>
|
|
49
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
58
50
|
</div>
|
|
59
51
|
);
|
|
60
52
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
-
import { Box, Chip,
|
|
4
|
-
import React, {
|
|
2
|
+
import { Box, Chip, Stack } from '@mui/material';
|
|
3
|
+
import React, { isValidElement } from 'react';
|
|
5
4
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
5
|
|
|
7
6
|
import Layout from '../../components/layout';
|
|
@@ -97,16 +96,7 @@ function Admin() {
|
|
|
97
96
|
</label>
|
|
98
97
|
</Stack>
|
|
99
98
|
</Stack>
|
|
100
|
-
<div className="page-content">
|
|
101
|
-
<Suspense
|
|
102
|
-
fallback={
|
|
103
|
-
<Center relative="parent">
|
|
104
|
-
<CircularProgress />
|
|
105
|
-
</Center>
|
|
106
|
-
}>
|
|
107
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
108
|
-
</Suspense>
|
|
109
|
-
</div>
|
|
99
|
+
<div className="page-content">{isValidElement(TabComponent) ? TabComponent : <TabComponent />}</div>
|
|
110
100
|
</Layout>
|
|
111
101
|
);
|
|
112
102
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
3
|
+
import { Stack, Typography } from '@mui/material';
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
6
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
7
6
|
|
|
8
7
|
const PaymentLinkCreate = React.lazy(() => import('./links/create'));
|
|
@@ -52,14 +51,7 @@ export default function PaymentIndex() {
|
|
|
52
51
|
{extra}
|
|
53
52
|
</Stack>
|
|
54
53
|
<Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
|
|
55
|
-
<
|
|
56
|
-
fallback={
|
|
57
|
-
<Center relative="parent">
|
|
58
|
-
<CircularProgress />
|
|
59
|
-
</Center>
|
|
60
|
-
}>
|
|
61
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
62
|
-
</Suspense>
|
|
54
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
63
55
|
</div>
|
|
64
56
|
);
|
|
65
57
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import Button from '@arcblock/ux/lib/Button';
|
|
2
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
3
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
3
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
5
4
|
import { AddOutlined } from '@mui/icons-material';
|
|
6
|
-
import {
|
|
7
|
-
import React, {
|
|
5
|
+
import { Stack, Typography } from '@mui/material';
|
|
6
|
+
import React, { isValidElement } from 'react';
|
|
8
7
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
9
8
|
|
|
10
9
|
const ProductCreate = React.lazy(() => import('./products/create'));
|
|
@@ -68,14 +67,7 @@ export default function Products() {
|
|
|
68
67
|
onChange={(newTab: string) => navigate(`/admin/products/${newTab}`)}
|
|
69
68
|
scrollButtons="auto"
|
|
70
69
|
/>
|
|
71
|
-
<
|
|
72
|
-
fallback={
|
|
73
|
-
<Center relative="parent">
|
|
74
|
-
<CircularProgress />
|
|
75
|
-
</Center>
|
|
76
|
-
}>
|
|
77
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
78
|
-
</Suspense>
|
|
70
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
79
71
|
</>
|
|
80
72
|
);
|
|
81
73
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
import React, { isValidElement } from 'react';
|
|
6
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
7
6
|
|
|
8
7
|
const pages = {
|
|
@@ -34,14 +33,7 @@ export default function SettingsIndex() {
|
|
|
34
33
|
{t('admin.settings')}
|
|
35
34
|
</Typography>
|
|
36
35
|
<Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
|
|
37
|
-
<
|
|
38
|
-
fallback={
|
|
39
|
-
<Center relative="parent">
|
|
40
|
-
<CircularProgress />
|
|
41
|
-
</Center>
|
|
42
|
-
}>
|
|
43
|
-
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
44
|
-
</Suspense>
|
|
36
|
+
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
45
37
|
</div>
|
|
46
38
|
);
|
|
47
39
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import React, { Suspense } from 'react';
|
|
1
|
+
import { Box } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
4
3
|
import { useParams } from 'react-router-dom';
|
|
5
4
|
|
|
6
5
|
import { SettingsProvider } from '../../contexts/settings';
|
|
@@ -17,14 +16,7 @@ function Checkout() {
|
|
|
17
16
|
|
|
18
17
|
return (
|
|
19
18
|
<Box>
|
|
20
|
-
<
|
|
21
|
-
fallback={
|
|
22
|
-
<Center relative="parent">
|
|
23
|
-
<CircularProgress />
|
|
24
|
-
</Center>
|
|
25
|
-
}>
|
|
26
|
-
<TabComponent id={id} />
|
|
27
|
-
</Suspense>
|
|
19
|
+
<TabComponent id={id} />
|
|
28
20
|
</Box>
|
|
29
21
|
);
|
|
30
22
|
}
|
|
@@ -30,10 +30,20 @@ export default function CustomerHome() {
|
|
|
30
30
|
return <Alert severity="error">{formatError(error)}</Alert>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (loading
|
|
33
|
+
if (loading) {
|
|
34
34
|
return <CircularProgress />;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
if (!data) {
|
|
38
|
+
return (
|
|
39
|
+
<Layout>
|
|
40
|
+
<Alert sx={{ mt: 3 }} severity="info">
|
|
41
|
+
{t('customer.empty')}
|
|
42
|
+
</Alert>
|
|
43
|
+
</Layout>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
return (
|
|
38
48
|
<Layout>
|
|
39
49
|
<Grid container spacing={5}>
|
package/src/pages/home.tsx
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
|
+
import Header from '@blocklet/ui-react/lib/Header';
|
|
2
|
+
import { Avatar, Button, Stack, Typography } from '@mui/material';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
4
|
+
import Typewriter from 'typewriter-effect';
|
|
5
|
+
|
|
1
6
|
function Home() {
|
|
2
7
|
return (
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
8
|
+
<div>
|
|
9
|
+
<Header />
|
|
10
|
+
<Stack alignItems="center" justifyContent="center" sx={{ height: '60vh', width: '100vw' }}>
|
|
11
|
+
<Stack maxWidth="sm" direction="column" alignItems="center" spacing={3}>
|
|
12
|
+
<Avatar src={window.blocklet.appLogo} sx={{ width: 80, height: 80 }} />
|
|
13
|
+
<Stack direction="column" alignItems="center" spacing={1}>
|
|
14
|
+
<Typography variant="h4">Payment Kit</Typography>
|
|
15
|
+
<Typography variant="h5" color="text.secondary" fontWeight="normal">
|
|
16
|
+
<Typewriter
|
|
17
|
+
options={{
|
|
18
|
+
strings: ['The decentralized stripe alike payment solution for blocklets'],
|
|
19
|
+
autoStart: true,
|
|
20
|
+
loop: true,
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
</Typography>
|
|
24
|
+
</Stack>
|
|
25
|
+
<Stack direction="row" spacing={3}>
|
|
26
|
+
<Button variant="outlined" color="secondary" size="large" component={Link} to="/admin/overview">
|
|
27
|
+
Admin Dashboard
|
|
28
|
+
</Button>
|
|
29
|
+
<Button variant="outlined" color="primary" size="large" component={Link} to="/customer">
|
|
30
|
+
Customer Portal
|
|
31
|
+
</Button>
|
|
32
|
+
</Stack>
|
|
33
|
+
</Stack>
|
|
34
|
+
</Stack>
|
|
35
|
+
</div>
|
|
6
36
|
);
|
|
7
37
|
}
|
|
8
38
|
|