@qlover/create-app 0.3.2 → 0.3.4
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/CHANGELOG.md +139 -0
- package/package.json +4 -4
- package/templates/react-app/README.md +311 -120
- package/templates/react-app/config/Identifier.I18n.ts +1048 -0
- package/templates/react-app/config/app.router.json +7 -7
- package/templates/react-app/config/common.ts +13 -0
- package/templates/react-app/config/theme.json +7 -88
- package/templates/react-app/package.json +11 -5
- package/templates/react-app/postcss.config.js +1 -2
- package/templates/react-app/public/locales/en/common.json +142 -1
- package/templates/react-app/public/locales/zh/common.json +142 -1
- package/templates/react-app/src/App.tsx +16 -3
- package/templates/react-app/src/base/apis/AiApi.ts +4 -4
- package/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +2 -2
- package/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +2 -2
- package/templates/react-app/src/base/cases/AppConfig.ts +103 -0
- package/templates/react-app/src/base/cases/{appError/AppError.ts → AppError.ts} +0 -3
- package/templates/react-app/src/base/cases/DialogHandler.ts +86 -0
- package/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
- package/templates/react-app/src/base/cases/RouterLoader.ts +166 -0
- package/templates/react-app/src/base/port/InteractionHubInterface.ts +94 -0
- package/templates/react-app/src/base/services/I18nService.ts +50 -3
- package/templates/react-app/src/base/services/ProcesserService.ts +0 -1
- package/templates/react-app/src/base/types/deprecated-antd.d.ts +60 -0
- package/templates/react-app/src/core/IOC.ts +18 -8
- package/templates/react-app/src/core/bootstrap.ts +41 -62
- package/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +14 -0
- package/templates/react-app/src/core/bootstraps/index.ts +36 -7
- package/templates/react-app/src/core/globals.ts +8 -1
- package/templates/react-app/src/core/registers/RegisterApi.ts +2 -5
- package/templates/react-app/src/core/registers/RegisterCommon.ts +38 -29
- package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -10
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +21 -17
- package/templates/react-app/src/core/registers/index.ts +27 -13
- package/templates/react-app/src/main.tsx +1 -1
- package/templates/react-app/src/pages/404.tsx +1 -1
- package/templates/react-app/src/pages/500.tsx +1 -1
- package/templates/react-app/src/pages/auth/Login.tsx +128 -36
- package/templates/react-app/src/pages/base/About.tsx +118 -2
- package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +38 -19
- package/templates/react-app/src/pages/base/Executor.tsx +442 -29
- package/templates/react-app/src/pages/base/Home.tsx +99 -93
- package/templates/react-app/src/pages/base/JSONStorage.tsx +47 -38
- package/templates/react-app/src/pages/base/Layout.tsx +5 -2
- package/templates/react-app/src/pages/base/Request.tsx +90 -208
- package/templates/react-app/src/pages/base/components/BaseHeader.tsx +13 -5
- package/templates/react-app/src/styles/css/antd-themes/_default.css +239 -0
- package/templates/react-app/src/styles/css/antd-themes/dark.css +176 -0
- package/templates/react-app/src/styles/css/antd-themes/index.css +3 -0
- package/templates/react-app/src/styles/css/antd-themes/no-context.css +34 -0
- package/templates/react-app/src/styles/css/antd-themes/pink.css +199 -0
- package/templates/react-app/src/{uikit/styles → styles}/css/index.css +3 -0
- package/templates/react-app/src/styles/css/page.css +11 -0
- package/templates/react-app/src/styles/css/tailwind.css +5 -0
- package/templates/react-app/src/styles/css/themes/_default.css +29 -0
- package/templates/react-app/src/styles/css/themes/dark.css +29 -0
- package/templates/react-app/src/styles/css/themes/index.css +3 -0
- package/templates/react-app/src/styles/css/themes/pink.css +29 -0
- package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +56 -0
- package/templates/react-app/src/uikit/components/Loading.tsx +27 -21
- package/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
- package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +63 -13
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
- package/templates/react-app/src/uikit/controllers/RouterController.ts +1 -1
- package/templates/react-app/src/uikit/controllers/UserController.ts +2 -2
- package/templates/react-app/tailwind.config.js +1 -15
- package/templates/react-app/tsconfig.json +3 -2
- package/templates/react-app/tsconfig.node.json +2 -1
- package/templates/react-app/vite.config.ts +15 -3
- package/templates/react-app/lib/tailwind/root10px.js +0 -178
- package/templates/react-app/lib/tailwind/theme-generator.js +0 -238
- package/templates/react-app/public/locales/en/about.json +0 -3
- package/templates/react-app/public/locales/en/executor.json +0 -6
- package/templates/react-app/public/locales/en/home.json +0 -10
- package/templates/react-app/public/locales/en/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/en/login.json +0 -7
- package/templates/react-app/public/locales/en/request.json +0 -15
- package/templates/react-app/public/locales/zh/about.json +0 -3
- package/templates/react-app/public/locales/zh/executor.json +0 -6
- package/templates/react-app/public/locales/zh/home.json +0 -10
- package/templates/react-app/public/locales/zh/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/zh/login.json +0 -7
- package/templates/react-app/public/locales/zh/request.json +0 -15
- package/templates/react-app/src/base/cases/router-loader/index.ts +0 -90
- package/templates/react-app/src/base/port/InversifyIocInterface.ts +0 -9
- package/templates/react-app/src/core/AppConfig.ts +0 -36
- package/templates/react-app/src/uikit/styles/css/page.css +0 -3
- package/templates/react-app/src/uikit/styles/css/tailwind.css +0 -3
- /package/templates/react-app/config/{ErrorIdentifier.ts → Identifier.Error.ts} +0 -0
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
+
import { Form, Input, Button } from 'antd';
|
|
3
|
+
import { UserOutlined, LockOutlined, GoogleOutlined } from '@ant-design/icons';
|
|
2
4
|
import { IOC } from '@/core/IOC';
|
|
3
5
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
4
6
|
import { RouterController } from '@/uikit/controllers/RouterController';
|
|
5
7
|
import { UserController } from '@/uikit/controllers/UserController';
|
|
6
|
-
import AppConfig from '@/core/AppConfig';
|
|
7
8
|
import { useSliceStore } from '@qlover/slice-store-react';
|
|
8
9
|
|
|
10
|
+
interface LoginFormData {
|
|
11
|
+
email: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
export default function Login() {
|
|
10
16
|
const { t } = useBaseRoutePage();
|
|
11
17
|
const userController = IOC(UserController);
|
|
18
|
+
const AppConfig = IOC('AppConfig');
|
|
12
19
|
useSliceStore(userController);
|
|
13
|
-
|
|
14
|
-
const [email, setEmail] = useState(AppConfig.loginUser);
|
|
15
|
-
const [password, setPassword] = useState(AppConfig.loginPassword);
|
|
16
20
|
const [loading, setLoading] = useState(false);
|
|
17
21
|
|
|
18
|
-
const handleLogin = async () => {
|
|
22
|
+
const handleLogin = async (values: LoginFormData) => {
|
|
19
23
|
try {
|
|
20
24
|
setLoading(true);
|
|
21
|
-
await userController.login({
|
|
22
|
-
|
|
25
|
+
await userController.login({
|
|
26
|
+
username: values.email,
|
|
27
|
+
password: values.password
|
|
28
|
+
});
|
|
23
29
|
IOC(RouterController).replaceToHome();
|
|
24
30
|
} catch (error) {
|
|
25
|
-
// Handle login error
|
|
26
31
|
console.error(error);
|
|
27
32
|
} finally {
|
|
28
33
|
setLoading(false);
|
|
@@ -30,37 +35,124 @@ export default function Login() {
|
|
|
30
35
|
};
|
|
31
36
|
|
|
32
37
|
return (
|
|
33
|
-
<div className="min-h-screen
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
38
|
+
<div className="flex min-h-screen text-xs1 bg-primary">
|
|
39
|
+
{/* Left side - Brand section */}
|
|
40
|
+
<div className="hidden lg:flex lg:w-1/2 bg-secondary p-12 flex-col">
|
|
41
|
+
<div className="flex items-center gap-3 mb-12">
|
|
42
|
+
<div className="w-10 h-10 bg-brand rounded-lg"></div>
|
|
43
|
+
<span className="text-2xl font-semibold text-text">
|
|
44
|
+
{AppConfig.appName}
|
|
45
|
+
</span>
|
|
46
|
+
</div>
|
|
47
|
+
<h1 className="text-4xl font-bold text-text mb-4">
|
|
48
|
+
Welcome back to the future of learning
|
|
49
|
+
</h1>
|
|
50
|
+
<p className="text-text-secondary text-lg mb-8">
|
|
51
|
+
Unlock personalized AI-powered learning experiences designed to
|
|
52
|
+
accelerate your knowledge journey.
|
|
53
|
+
</p>
|
|
54
|
+
<div className="space-y-4">
|
|
55
|
+
<FeatureItem
|
|
56
|
+
icon="🎯"
|
|
57
|
+
text="AI-powered personalized learning paths"
|
|
58
|
+
/>
|
|
59
|
+
<FeatureItem icon="🎯" text="Smart content recommendations" />
|
|
60
|
+
<FeatureItem icon="📊" text="Real-time progress tracking" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
{/* Right side - Login form */}
|
|
65
|
+
<div className="w-full lg:w-1/2 p-8 sm:p-12 flex items-center justify-center">
|
|
66
|
+
<div className="w-full max-w-[420px]">
|
|
67
|
+
<h2 className="text-2xl font-semibold mb-2 text-text">
|
|
68
|
+
{t('Sign in to your account')}
|
|
69
|
+
</h2>
|
|
70
|
+
<p className="text-text-secondary mb-8">
|
|
71
|
+
Enter your credentials to access your dashboard
|
|
72
|
+
</p>
|
|
73
|
+
|
|
74
|
+
<Form
|
|
75
|
+
name="login"
|
|
76
|
+
initialValues={{
|
|
77
|
+
email: AppConfig.loginUser,
|
|
78
|
+
password: AppConfig.loginPassword
|
|
79
|
+
}}
|
|
80
|
+
onFinish={handleLogin}
|
|
81
|
+
layout="vertical"
|
|
82
|
+
className="space-y-4"
|
|
83
|
+
>
|
|
84
|
+
<Form.Item
|
|
85
|
+
name="email"
|
|
86
|
+
rules={[{ required: true, message: 'Please input your email!' }]}
|
|
58
87
|
>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
88
|
+
<Input
|
|
89
|
+
prefix={<UserOutlined className="text-text-tertiary" />}
|
|
90
|
+
placeholder={t('email')}
|
|
91
|
+
className="h-12 text-base bg-secondary border-border"
|
|
92
|
+
/>
|
|
93
|
+
</Form.Item>
|
|
94
|
+
|
|
95
|
+
<Form.Item
|
|
96
|
+
name="password"
|
|
97
|
+
rules={[
|
|
98
|
+
{ required: true, message: 'Please input your password!' }
|
|
99
|
+
]}
|
|
100
|
+
>
|
|
101
|
+
<Input.Password
|
|
102
|
+
prefix={<LockOutlined />}
|
|
103
|
+
placeholder={t('password')}
|
|
104
|
+
className="h-12 text-base"
|
|
105
|
+
/>
|
|
106
|
+
</Form.Item>
|
|
107
|
+
|
|
108
|
+
<div className="flex justify-end">
|
|
109
|
+
<a href="#" className="text-brand hover:text-brand-hover">
|
|
110
|
+
{t('Forgot your password?')}
|
|
111
|
+
</a>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<Form.Item>
|
|
115
|
+
<Button
|
|
116
|
+
type="primary"
|
|
117
|
+
htmlType="submit"
|
|
118
|
+
loading={loading}
|
|
119
|
+
className="w-full h-12 text-base"
|
|
120
|
+
>
|
|
121
|
+
{t('Sign In')}
|
|
122
|
+
</Button>
|
|
123
|
+
</Form.Item>
|
|
124
|
+
|
|
125
|
+
<div className="text-center text-text-tertiary my-4">
|
|
126
|
+
or continue with
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<Button icon={<GoogleOutlined />} className="w-full h-12 text-base">
|
|
130
|
+
Sign in with Google
|
|
131
|
+
</Button>
|
|
132
|
+
|
|
133
|
+
<div className="text-center mt-6">
|
|
134
|
+
<span className="text-text-tertiary">
|
|
135
|
+
Don't have an account?{' '}
|
|
136
|
+
</span>
|
|
137
|
+
<a href="#" className="text-brand hover:text-brand-hover">
|
|
138
|
+
Create one here
|
|
139
|
+
</a>
|
|
140
|
+
</div>
|
|
141
|
+
</Form>
|
|
62
142
|
</div>
|
|
63
143
|
</div>
|
|
64
144
|
</div>
|
|
65
145
|
);
|
|
66
146
|
}
|
|
147
|
+
|
|
148
|
+
// Helper component for feature items
|
|
149
|
+
function FeatureItem({ icon, text }: { icon: string; text: string }) {
|
|
150
|
+
return (
|
|
151
|
+
<div className="flex items-center gap-3 text-text">
|
|
152
|
+
<div className="w-8 h-8 bg-elevated rounded-lg flex items-center justify-center">
|
|
153
|
+
{icon}
|
|
154
|
+
</div>
|
|
155
|
+
<span>{text}</span>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
@@ -1,11 +1,127 @@
|
|
|
1
1
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
2
|
+
import * as i18nKeys from '@config/Identifier.I18n';
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Tooltip,
|
|
6
|
+
message,
|
|
7
|
+
notification,
|
|
8
|
+
Modal,
|
|
9
|
+
Drawer,
|
|
10
|
+
Popover,
|
|
11
|
+
Popconfirm,
|
|
12
|
+
Alert
|
|
13
|
+
} from 'antd';
|
|
14
|
+
import { useState } from 'react';
|
|
2
15
|
|
|
3
16
|
export default function About() {
|
|
4
17
|
const { t } = useBaseRoutePage();
|
|
18
|
+
const [messageApi, contextHolder] = message.useMessage();
|
|
19
|
+
const [notificationApi, contextHolder2] = notification.useNotification();
|
|
20
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
21
|
+
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
22
|
+
|
|
23
|
+
const showMessage = () => {
|
|
24
|
+
messageApi.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 2000);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const showNotification = () => {
|
|
28
|
+
notificationApi.open({
|
|
29
|
+
message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
|
|
30
|
+
description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
|
|
31
|
+
duration: 2000
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
const showNotification2 = () => {
|
|
35
|
+
notification.open({
|
|
36
|
+
message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
|
|
37
|
+
description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
|
|
38
|
+
duration: 2000
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const showModal = () => {
|
|
43
|
+
setIsModalOpen(true);
|
|
44
|
+
};
|
|
45
|
+
const showMessage2 = () => {
|
|
46
|
+
message.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 200);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const showDrawer = () => {
|
|
50
|
+
setIsDrawerOpen(true);
|
|
51
|
+
};
|
|
52
|
+
|
|
5
53
|
return (
|
|
6
|
-
<div className="min-h-screen bg-
|
|
54
|
+
<div className="min-h-screen bg-primary py-6 flex flex-col justify-center sm:py-12">
|
|
55
|
+
{contextHolder}
|
|
56
|
+
{contextHolder2}
|
|
7
57
|
<div className="relative py-3 sm:max-w-xl sm:mx-auto">
|
|
8
|
-
<h1 className="text-2xl font-bold text-center">
|
|
58
|
+
<h1 className="text-2xl font-bold text-center text-text mb-8">
|
|
59
|
+
{t(i18nKeys.PAGE_ABOUT_TITLE)}
|
|
60
|
+
</h1>
|
|
61
|
+
|
|
62
|
+
<div className="space-x-4 flex justify-center flex-wrap gap-4">
|
|
63
|
+
<Button onClick={showMessage}>{t(i18nKeys.ABOUT_BTN_MESSAGE)}</Button>
|
|
64
|
+
<Button onClick={showMessage2}>
|
|
65
|
+
{t(i18nKeys.ABOUT_BTN_MESSAGE2)}
|
|
66
|
+
</Button>
|
|
67
|
+
|
|
68
|
+
<Button onClick={showNotification}>
|
|
69
|
+
{t(i18nKeys.ABOUT_BTN_NOTIFICATION)}
|
|
70
|
+
</Button>
|
|
71
|
+
|
|
72
|
+
<Button onClick={showNotification2}>
|
|
73
|
+
{t(i18nKeys.ABOUT_BTN_NOTIFICATION2)}
|
|
74
|
+
</Button>
|
|
75
|
+
|
|
76
|
+
<Tooltip title={t(i18nKeys.ABOUT_TOOLTIP_TEXT)}>
|
|
77
|
+
<Button>{t(i18nKeys.ABOUT_BTN_TOOLTIP)}</Button>
|
|
78
|
+
</Tooltip>
|
|
79
|
+
|
|
80
|
+
<Modal
|
|
81
|
+
title={t(i18nKeys.ABOUT_MODAL_TITLE)}
|
|
82
|
+
open={isModalOpen}
|
|
83
|
+
onOk={() => setIsModalOpen(false)}
|
|
84
|
+
onCancel={() => setIsModalOpen(false)}
|
|
85
|
+
>
|
|
86
|
+
<p>{t(i18nKeys.ABOUT_MODAL_CONTENT)}</p>
|
|
87
|
+
</Modal>
|
|
88
|
+
|
|
89
|
+
<Button onClick={showModal}>{t(i18nKeys.ABOUT_BTN_MODAL)}</Button>
|
|
90
|
+
|
|
91
|
+
<Drawer
|
|
92
|
+
title={t(i18nKeys.ABOUT_DRAWER_TITLE)}
|
|
93
|
+
open={isDrawerOpen}
|
|
94
|
+
onClose={() => setIsDrawerOpen(false)}
|
|
95
|
+
>
|
|
96
|
+
<p>{t(i18nKeys.ABOUT_DRAWER_CONTENT)}</p>
|
|
97
|
+
</Drawer>
|
|
98
|
+
|
|
99
|
+
<Button onClick={showDrawer}>{t(i18nKeys.ABOUT_BTN_DRAWER)}</Button>
|
|
100
|
+
|
|
101
|
+
<Popover
|
|
102
|
+
content={t(i18nKeys.ABOUT_POPOVER_CONTENT)}
|
|
103
|
+
title={t(i18nKeys.ABOUT_POPOVER_TITLE)}
|
|
104
|
+
>
|
|
105
|
+
<Button>{t(i18nKeys.ABOUT_BTN_POPOVER)}</Button>
|
|
106
|
+
</Popover>
|
|
107
|
+
|
|
108
|
+
<Popconfirm
|
|
109
|
+
title={t(i18nKeys.ABOUT_POPCONFIRM_TITLE)}
|
|
110
|
+
description={t(i18nKeys.ABOUT_POPCONFIRM_DESC)}
|
|
111
|
+
okText={t(i18nKeys.COMMON_OK)}
|
|
112
|
+
cancelText={t(i18nKeys.COMMON_CANCEL)}
|
|
113
|
+
>
|
|
114
|
+
<Button>{t(i18nKeys.ABOUT_BTN_POPCONFIRM)}</Button>
|
|
115
|
+
</Popconfirm>
|
|
116
|
+
|
|
117
|
+
<Alert
|
|
118
|
+
message={t(i18nKeys.ABOUT_ALERT_MESSAGE)}
|
|
119
|
+
type="warning"
|
|
120
|
+
showIcon
|
|
121
|
+
closable
|
|
122
|
+
className="mt-4"
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
9
125
|
</div>
|
|
10
126
|
</div>
|
|
11
127
|
);
|
|
@@ -1,38 +1,57 @@
|
|
|
1
|
+
import { Button } from 'antd';
|
|
1
2
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
2
|
-
import * as ErrorIdentifierList from '@config/
|
|
3
|
+
import * as ErrorIdentifierList from '@config/Identifier.Error';
|
|
4
|
+
import * as i18nKeys from '@config/Identifier.I18n';
|
|
3
5
|
|
|
4
6
|
export default function ErrorIdentifier() {
|
|
5
7
|
const { t } = useBaseRoutePage();
|
|
6
8
|
|
|
7
9
|
return (
|
|
8
|
-
<div className="min-h-screen bg-
|
|
9
|
-
<div className="max-w-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
<div className="min-h-screen bg-primary py-8 px-4 sm:px-6 lg:px-8">
|
|
11
|
+
<div className="max-w-4xl mx-auto space-y-6">
|
|
12
|
+
{/* Header Section */}
|
|
13
|
+
<section className="py-8">
|
|
14
|
+
<div className="text-center">
|
|
15
|
+
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-text">
|
|
16
|
+
{t(i18nKeys.PAGE_ERROR_IDENTIFIER_MAIN_TITLE)}
|
|
14
17
|
</h1>
|
|
15
|
-
<p className="text-
|
|
16
|
-
|
|
18
|
+
<p className="text-xl text-text-secondary mb-8">
|
|
19
|
+
{t(i18nKeys.PAGE_ERROR_IDENTIFIER_SOURCE_DESCRIPTION)}
|
|
17
20
|
</p>
|
|
18
21
|
</div>
|
|
22
|
+
</section>
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
{/* Error Identifier List */}
|
|
25
|
+
<div className="grid gap-4">
|
|
26
|
+
{Object.entries(ErrorIdentifierList).map(([key, value]) => (
|
|
27
|
+
<div
|
|
28
|
+
key={key}
|
|
29
|
+
className="bg-secondary shadow sm:rounded-lg p-6 border border-border hover:bg-elevated transition-colors duration-200"
|
|
30
|
+
>
|
|
31
|
+
<div className="flex flex-col sm:flex-row sm:items-center justify-between">
|
|
32
|
+
<span className="font-medium text-text mb-2 sm:mb-0">
|
|
27
33
|
{key}
|
|
28
34
|
</span>
|
|
29
|
-
<span className="
|
|
35
|
+
<span className="text-sm text-text-secondary bg-primary px-3 py-1 rounded-md">
|
|
30
36
|
{t(value)}
|
|
31
37
|
</span>
|
|
32
38
|
</div>
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
</div>
|
|
40
|
+
))}
|
|
35
41
|
</div>
|
|
42
|
+
|
|
43
|
+
{/* Call to Action Section */}
|
|
44
|
+
<section className="py-8 text-center">
|
|
45
|
+
<h2 className="text-2xl font-bold mb-4 text-text">
|
|
46
|
+
{t(i18nKeys.PAGE_ERROR_IDENTIFIER_HELP_TITLE)}
|
|
47
|
+
</h2>
|
|
48
|
+
<p className="text-lg text-text-secondary mb-6">
|
|
49
|
+
{t(i18nKeys.PAGE_ERROR_IDENTIFIER_HELP_DESCRIPTION)}
|
|
50
|
+
</p>
|
|
51
|
+
<Button type="primary" size="large">
|
|
52
|
+
{t(i18nKeys.PAGE_ERROR_IDENTIFIER_CONTACT_SUPPORT)}
|
|
53
|
+
</Button>
|
|
54
|
+
</section>
|
|
36
55
|
</div>
|
|
37
56
|
</div>
|
|
38
57
|
);
|