@qlover/create-app 0.4.1 → 0.4.2
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 +37 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/react-app/.env +1 -2
- package/templates/react-app/README.md +70 -8
- package/templates/react-app/config/app.router.json +13 -13
- package/templates/react-app/config/common.ts +8 -0
- package/templates/react-app/config/i18n.ts +3 -1
- package/templates/react-app/config/{Identifier.I18n.ts → identifier/I18n.ts} +321 -3
- package/templates/react-app/index.html +1 -1
- package/templates/react-app/public/locales/en/common.json +54 -8
- package/templates/react-app/public/locales/zh/common.json +54 -8
- package/templates/react-app/public/router-root/logo.svg +1 -0
- package/templates/react-app/src/App.tsx +6 -3
- package/templates/react-app/src/base/cases/PublicAssetsPath.ts +17 -0
- package/templates/react-app/src/base/port/LoginInterface.ts +8 -0
- package/templates/react-app/src/base/port/StoreInterface.ts +58 -0
- package/templates/react-app/src/base/services/I18nService.ts +15 -9
- package/templates/react-app/src/{uikit/controllers/RouterController.ts → base/services/RouteService.ts} +12 -12
- package/templates/react-app/src/{uikit/controllers/UserController.ts → base/services/UserService.ts} +21 -11
- package/templates/react-app/src/core/bootstrap.ts +1 -1
- package/templates/react-app/src/core/registers/RegisterCommon.ts +11 -1
- package/templates/react-app/src/core/registers/RegisterControllers.ts +3 -12
- package/templates/react-app/src/pages/auth/Layout.tsx +5 -5
- package/templates/react-app/src/pages/auth/Login.tsx +50 -29
- package/templates/react-app/src/pages/auth/Register.tsx +238 -1
- package/templates/react-app/src/pages/base/About.tsx +1 -1
- package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +2 -2
- package/templates/react-app/src/pages/base/Executor.tsx +4 -4
- package/templates/react-app/src/pages/base/Home.tsx +1 -1
- package/templates/react-app/src/pages/base/JSONStorage.tsx +3 -3
- package/templates/react-app/src/pages/base/Request.tsx +4 -4
- package/templates/react-app/src/pages/base/components/BaseHeader.tsx +8 -2
- package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +7 -7
- package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +3 -3
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
- package/templates/react-app/src/uikit/controllers/ExecutorController.ts +6 -3
- package/templates/react-app/src/uikit/controllers/JSONStorageController.ts +6 -3
- package/templates/react-app/src/uikit/controllers/RequestController.ts +3 -4
- package/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +15 -0
- package/templates/react-app/src/uikit/hooks/useStore.ts +12 -0
- package/templates/react-app/src/uikit/providers/BaseRouteProvider.tsx +7 -1
- package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +7 -7
- package/templates/react-app/vite.config.ts +20 -11
- /package/templates/react-app/config/{Identifier.Error.ts → identifier/Error.ts} +0 -0
|
@@ -3,9 +3,11 @@ import { Form, Input, Button } from 'antd';
|
|
|
3
3
|
import { UserOutlined, LockOutlined, GoogleOutlined } from '@ant-design/icons';
|
|
4
4
|
import { IOC } from '@/core/IOC';
|
|
5
5
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { RouteService } from '@/base/services/RouteService';
|
|
7
|
+
import { UserService } from '@/base/services/UserService';
|
|
8
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
9
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
10
|
+
import LocaleLink from '@/uikit/components/LocaleLink';
|
|
9
11
|
|
|
10
12
|
interface LoginFormData {
|
|
11
13
|
email: string;
|
|
@@ -14,19 +16,19 @@ interface LoginFormData {
|
|
|
14
16
|
|
|
15
17
|
export default function Login() {
|
|
16
18
|
const { t } = useBaseRoutePage();
|
|
17
|
-
const
|
|
19
|
+
const userService = IOC(UserService);
|
|
18
20
|
const AppConfig = IOC('AppConfig');
|
|
19
|
-
|
|
21
|
+
useStore(userService);
|
|
20
22
|
const [loading, setLoading] = useState(false);
|
|
21
23
|
|
|
22
24
|
const handleLogin = async (values: LoginFormData) => {
|
|
23
25
|
try {
|
|
24
26
|
setLoading(true);
|
|
25
|
-
await
|
|
27
|
+
await userService.login({
|
|
26
28
|
username: values.email,
|
|
27
29
|
password: values.password
|
|
28
30
|
});
|
|
29
|
-
IOC(
|
|
31
|
+
IOC(RouteService).replaceToHome();
|
|
30
32
|
} catch (error) {
|
|
31
33
|
console.error(error);
|
|
32
34
|
} finally {
|
|
@@ -45,19 +47,21 @@ export default function Login() {
|
|
|
45
47
|
</span>
|
|
46
48
|
</div>
|
|
47
49
|
<h1 className="text-4xl font-bold text-text mb-4">
|
|
48
|
-
|
|
50
|
+
{t(i18nKeys.LOGIN_WELCOME)}
|
|
49
51
|
</h1>
|
|
50
52
|
<p className="text-text-secondary text-lg mb-8">
|
|
51
|
-
|
|
52
|
-
accelerate your knowledge journey.
|
|
53
|
+
{t(i18nKeys.LOGIN_SUBTITLE)}
|
|
53
54
|
</p>
|
|
54
55
|
<div className="space-y-4">
|
|
56
|
+
<FeatureItem icon="🎯" text={t(i18nKeys.LOGIN_FEATURE_AI_PATHS)} />
|
|
55
57
|
<FeatureItem
|
|
56
58
|
icon="🎯"
|
|
57
|
-
text=
|
|
59
|
+
text={t(i18nKeys.LOGIN_FEATURE_SMART_RECOMMENDATIONS)}
|
|
60
|
+
/>
|
|
61
|
+
<FeatureItem
|
|
62
|
+
icon="📊"
|
|
63
|
+
text={t(i18nKeys.LOGIN_FEATURE_PROGRESS_TRACKING)}
|
|
58
64
|
/>
|
|
59
|
-
<FeatureItem icon="🎯" text="Smart content recommendations" />
|
|
60
|
-
<FeatureItem icon="📊" text="Real-time progress tracking" />
|
|
61
65
|
</div>
|
|
62
66
|
</div>
|
|
63
67
|
|
|
@@ -65,10 +69,10 @@ export default function Login() {
|
|
|
65
69
|
<div className="w-full lg:w-1/2 p-8 sm:p-12 flex items-center justify-center">
|
|
66
70
|
<div className="w-full max-w-[420px]">
|
|
67
71
|
<h2 className="text-2xl font-semibold mb-2 text-text">
|
|
68
|
-
{t(
|
|
72
|
+
{t(i18nKeys.LOGIN_TITLE)}
|
|
69
73
|
</h2>
|
|
70
74
|
<p className="text-text-secondary mb-8">
|
|
71
|
-
|
|
75
|
+
{t(i18nKeys.LOGIN_SUBTITLE)}
|
|
72
76
|
</p>
|
|
73
77
|
|
|
74
78
|
<Form
|
|
@@ -83,11 +87,14 @@ export default function Login() {
|
|
|
83
87
|
>
|
|
84
88
|
<Form.Item
|
|
85
89
|
name="email"
|
|
86
|
-
rules={[
|
|
90
|
+
rules={[
|
|
91
|
+
{ required: true, message: t(i18nKeys.LOGIN_EMAIL_REQUIRED) }
|
|
92
|
+
]}
|
|
87
93
|
>
|
|
88
94
|
<Input
|
|
89
95
|
prefix={<UserOutlined className="text-text-tertiary" />}
|
|
90
|
-
placeholder={t(
|
|
96
|
+
placeholder={t(i18nKeys.LOGIN_EMAIL)}
|
|
97
|
+
title={t(i18nKeys.LOGIN_EMAIL_TITLE)}
|
|
91
98
|
className="h-12 text-base bg-secondary border-border"
|
|
92
99
|
/>
|
|
93
100
|
</Form.Item>
|
|
@@ -95,19 +102,24 @@ export default function Login() {
|
|
|
95
102
|
<Form.Item
|
|
96
103
|
name="password"
|
|
97
104
|
rules={[
|
|
98
|
-
{ required: true, message:
|
|
105
|
+
{ required: true, message: t(i18nKeys.LOGIN_PASSWORD_REQUIRED) }
|
|
99
106
|
]}
|
|
100
107
|
>
|
|
101
108
|
<Input.Password
|
|
102
109
|
prefix={<LockOutlined />}
|
|
103
|
-
placeholder={t(
|
|
110
|
+
placeholder={t(i18nKeys.LOGIN_PASSWORD)}
|
|
111
|
+
title={t(i18nKeys.LOGIN_PASSWORD_TITLE)}
|
|
104
112
|
className="h-12 text-base"
|
|
105
113
|
/>
|
|
106
114
|
</Form.Item>
|
|
107
115
|
|
|
108
116
|
<div className="flex justify-end">
|
|
109
|
-
<a
|
|
110
|
-
|
|
117
|
+
<a
|
|
118
|
+
href="#"
|
|
119
|
+
className="text-brand hover:text-brand-hover"
|
|
120
|
+
title={t(i18nKeys.LOGIN_FORGOT_PASSWORD_TITLE)}
|
|
121
|
+
>
|
|
122
|
+
{t(i18nKeys.LOGIN_FORGOT_PASSWORD)}
|
|
111
123
|
</a>
|
|
112
124
|
</div>
|
|
113
125
|
|
|
@@ -116,27 +128,36 @@ export default function Login() {
|
|
|
116
128
|
type="primary"
|
|
117
129
|
htmlType="submit"
|
|
118
130
|
loading={loading}
|
|
131
|
+
title={t(i18nKeys.LOGIN_BUTTON_TITLE)}
|
|
119
132
|
className="w-full h-12 text-base"
|
|
120
133
|
>
|
|
121
|
-
{t(
|
|
134
|
+
{t(i18nKeys.LOGIN_BUTTON)}
|
|
122
135
|
</Button>
|
|
123
136
|
</Form.Item>
|
|
124
137
|
|
|
125
138
|
<div className="text-center text-text-tertiary my-4">
|
|
126
|
-
|
|
139
|
+
{t(i18nKeys.LOGIN_CONTINUE_WITH)}
|
|
127
140
|
</div>
|
|
128
141
|
|
|
129
|
-
<Button
|
|
130
|
-
|
|
142
|
+
<Button
|
|
143
|
+
icon={<GoogleOutlined />}
|
|
144
|
+
className="w-full h-12 text-base"
|
|
145
|
+
title={t(i18nKeys.LOGIN_WITH_GOOGLE_TITLE)}
|
|
146
|
+
>
|
|
147
|
+
{t(i18nKeys.LOGIN_WITH_GOOGLE)}
|
|
131
148
|
</Button>
|
|
132
149
|
|
|
133
150
|
<div className="text-center mt-6">
|
|
134
151
|
<span className="text-text-tertiary">
|
|
135
|
-
|
|
152
|
+
{t(i18nKeys.LOGIN_NO_ACCOUNT)}{' '}
|
|
136
153
|
</span>
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
154
|
+
<LocaleLink
|
|
155
|
+
href="/register"
|
|
156
|
+
className="text-brand hover:text-brand-hover"
|
|
157
|
+
title={t(i18nKeys.LOGIN_CREATE_ACCOUNT_TITLE)}
|
|
158
|
+
>
|
|
159
|
+
{t(i18nKeys.LOGIN_CREATE_ACCOUNT)}
|
|
160
|
+
</LocaleLink>
|
|
140
161
|
</div>
|
|
141
162
|
</Form>
|
|
142
163
|
</div>
|
|
@@ -1,3 +1,240 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Form, Input, Button, Checkbox } from 'antd';
|
|
3
|
+
import { UserOutlined, LockOutlined, MailOutlined } from '@ant-design/icons';
|
|
4
|
+
import { IOC } from '@/core/IOC';
|
|
5
|
+
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
6
|
+
import { RouteService } from '@/base/services/RouteService';
|
|
7
|
+
import { UserService } from '@/base/services/UserService';
|
|
8
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
9
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
10
|
+
import type { RegisterFormData } from '@/base/port/LoginInterface';
|
|
11
|
+
|
|
1
12
|
export default function Register() {
|
|
2
|
-
|
|
13
|
+
const { t } = useBaseRoutePage();
|
|
14
|
+
const userService = IOC(UserService);
|
|
15
|
+
const AppConfig = IOC('AppConfig');
|
|
16
|
+
useStore(userService);
|
|
17
|
+
const [loading, setLoading] = useState(false);
|
|
18
|
+
const [form] = Form.useForm();
|
|
19
|
+
|
|
20
|
+
const handleRegister = async (values: RegisterFormData) => {
|
|
21
|
+
try {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
await userService.register(values);
|
|
24
|
+
IOC(RouteService).replaceToHome();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error(error);
|
|
27
|
+
} finally {
|
|
28
|
+
setLoading(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleLoginClick = (e: React.MouseEvent) => {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
IOC(RouteService).gotoLogin();
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
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
|
+
{t(i18nKeys.REGISTER_TITLE)}
|
|
49
|
+
</h1>
|
|
50
|
+
<p className="text-text-secondary text-lg mb-8">
|
|
51
|
+
{t(i18nKeys.REGISTER_SUBTITLE)}
|
|
52
|
+
</p>
|
|
53
|
+
<div className="space-y-4">
|
|
54
|
+
<FeatureItem
|
|
55
|
+
icon="🎯"
|
|
56
|
+
text={t(i18nKeys.REGISTER_FEATURE_PERSONALIZED)}
|
|
57
|
+
/>
|
|
58
|
+
<FeatureItem icon="👨🏫" text={t(i18nKeys.REGISTER_FEATURE_SUPPORT)} />
|
|
59
|
+
<FeatureItem
|
|
60
|
+
icon="👥"
|
|
61
|
+
text={t(i18nKeys.REGISTER_FEATURE_COMMUNITY)}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{/* Right side - Registration form */}
|
|
67
|
+
<div className="w-full lg:w-1/2 p-8 sm:p-12 flex items-center justify-center">
|
|
68
|
+
<div className="w-full max-w-[420px]">
|
|
69
|
+
<h2 className="text-2xl font-semibold mb-2 text-text">
|
|
70
|
+
{t(i18nKeys.REGISTER_TITLE)}
|
|
71
|
+
</h2>
|
|
72
|
+
<p className="text-text-secondary mb-8">
|
|
73
|
+
{t(i18nKeys.REGISTER_SUBTITLE)}
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
<Form
|
|
77
|
+
form={form}
|
|
78
|
+
name="register"
|
|
79
|
+
onFinish={handleRegister}
|
|
80
|
+
layout="vertical"
|
|
81
|
+
className="space-y-4"
|
|
82
|
+
>
|
|
83
|
+
<Form.Item
|
|
84
|
+
name="username"
|
|
85
|
+
rules={[
|
|
86
|
+
{
|
|
87
|
+
required: true,
|
|
88
|
+
message: t(i18nKeys.REGISTER_USERNAME_REQUIRED)
|
|
89
|
+
}
|
|
90
|
+
]}
|
|
91
|
+
>
|
|
92
|
+
<Input
|
|
93
|
+
prefix={<UserOutlined className="text-text-tertiary" />}
|
|
94
|
+
placeholder={t(i18nKeys.REGISTER_USERNAME)}
|
|
95
|
+
className="h-12 text-base bg-secondary border-border"
|
|
96
|
+
/>
|
|
97
|
+
</Form.Item>
|
|
98
|
+
|
|
99
|
+
<Form.Item
|
|
100
|
+
name="email"
|
|
101
|
+
rules={[
|
|
102
|
+
{
|
|
103
|
+
required: true,
|
|
104
|
+
message: t(i18nKeys.REGISTER_EMAIL_REQUIRED)
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
type: 'email',
|
|
108
|
+
message: t(i18nKeys.REGISTER_EMAIL_REQUIRED)
|
|
109
|
+
}
|
|
110
|
+
]}
|
|
111
|
+
>
|
|
112
|
+
<Input
|
|
113
|
+
prefix={<MailOutlined className="text-text-tertiary" />}
|
|
114
|
+
placeholder={t(i18nKeys.REGISTER_EMAIL)}
|
|
115
|
+
className="h-12 text-base bg-secondary border-border"
|
|
116
|
+
/>
|
|
117
|
+
</Form.Item>
|
|
118
|
+
|
|
119
|
+
<Form.Item
|
|
120
|
+
name="password"
|
|
121
|
+
rules={[
|
|
122
|
+
{
|
|
123
|
+
required: true,
|
|
124
|
+
message: t(i18nKeys.REGISTER_PASSWORD_REQUIRED)
|
|
125
|
+
}
|
|
126
|
+
]}
|
|
127
|
+
>
|
|
128
|
+
<Input.Password
|
|
129
|
+
prefix={<LockOutlined />}
|
|
130
|
+
placeholder={t(i18nKeys.REGISTER_PASSWORD)}
|
|
131
|
+
className="h-12 text-base"
|
|
132
|
+
/>
|
|
133
|
+
</Form.Item>
|
|
134
|
+
|
|
135
|
+
<Form.Item
|
|
136
|
+
name="confirmPassword"
|
|
137
|
+
dependencies={['password']}
|
|
138
|
+
rules={[
|
|
139
|
+
{
|
|
140
|
+
required: true,
|
|
141
|
+
message: t(i18nKeys.REGISTER_CONFIRM_PASSWORD_REQUIRED)
|
|
142
|
+
},
|
|
143
|
+
({ getFieldValue }) => ({
|
|
144
|
+
validator(_, value) {
|
|
145
|
+
if (!value || getFieldValue('password') === value) {
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
}
|
|
148
|
+
return Promise.reject(
|
|
149
|
+
t(i18nKeys.REGISTER_PASSWORD_MISMATCH)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
]}
|
|
154
|
+
>
|
|
155
|
+
<Input.Password
|
|
156
|
+
prefix={<LockOutlined />}
|
|
157
|
+
placeholder={t(i18nKeys.REGISTER_CONFIRM_PASSWORD)}
|
|
158
|
+
className="h-12 text-base"
|
|
159
|
+
/>
|
|
160
|
+
</Form.Item>
|
|
161
|
+
|
|
162
|
+
<Form.Item
|
|
163
|
+
name="agreeToTerms"
|
|
164
|
+
valuePropName="checked"
|
|
165
|
+
rules={[
|
|
166
|
+
{
|
|
167
|
+
validator: (_, value) =>
|
|
168
|
+
value
|
|
169
|
+
? Promise.resolve()
|
|
170
|
+
: Promise.reject(
|
|
171
|
+
new Error(t(i18nKeys.REGISTER_TERMS_REQUIRED))
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
]}
|
|
175
|
+
>
|
|
176
|
+
<Checkbox>
|
|
177
|
+
<span className="text-text-secondary">
|
|
178
|
+
{t(i18nKeys.REGISTER_TERMS_PREFIX)}{' '}
|
|
179
|
+
<a
|
|
180
|
+
href="#"
|
|
181
|
+
className="text-brand hover:text-brand-hover"
|
|
182
|
+
target="_blank"
|
|
183
|
+
rel="noopener noreferrer"
|
|
184
|
+
>
|
|
185
|
+
{t(i18nKeys.REGISTER_TERMS_LINK)}
|
|
186
|
+
</a>{' '}
|
|
187
|
+
{t(i18nKeys.REGISTER_TERMS_AND)}{' '}
|
|
188
|
+
<a
|
|
189
|
+
href="#"
|
|
190
|
+
className="text-brand hover:text-brand-hover"
|
|
191
|
+
target="_blank"
|
|
192
|
+
rel="noopener noreferrer"
|
|
193
|
+
>
|
|
194
|
+
{t(i18nKeys.REGISTER_PRIVACY_LINK)}
|
|
195
|
+
</a>
|
|
196
|
+
</span>
|
|
197
|
+
</Checkbox>
|
|
198
|
+
</Form.Item>
|
|
199
|
+
|
|
200
|
+
<Form.Item>
|
|
201
|
+
<Button
|
|
202
|
+
type="primary"
|
|
203
|
+
htmlType="submit"
|
|
204
|
+
loading={loading}
|
|
205
|
+
className="w-full h-12 text-base"
|
|
206
|
+
>
|
|
207
|
+
{t(i18nKeys.REGISTER_BUTTON)}
|
|
208
|
+
</Button>
|
|
209
|
+
</Form.Item>
|
|
210
|
+
|
|
211
|
+
<div className="text-center mt-6">
|
|
212
|
+
<span className="text-text-tertiary">
|
|
213
|
+
{t(i18nKeys.REGISTER_HAVE_ACCOUNT)}{' '}
|
|
214
|
+
</span>
|
|
215
|
+
<a
|
|
216
|
+
href="#"
|
|
217
|
+
className="text-brand hover:text-brand-hover"
|
|
218
|
+
onClick={handleLoginClick}
|
|
219
|
+
>
|
|
220
|
+
{t(i18nKeys.REGISTER_LOGIN_LINK)}
|
|
221
|
+
</a>
|
|
222
|
+
</div>
|
|
223
|
+
</Form>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Helper component for feature items
|
|
231
|
+
function FeatureItem({ icon, text }: { icon: string; text: string }) {
|
|
232
|
+
return (
|
|
233
|
+
<div className="flex items-center gap-3 text-text">
|
|
234
|
+
<div className="w-8 h-8 bg-elevated rounded-lg flex items-center justify-center">
|
|
235
|
+
{icon}
|
|
236
|
+
</div>
|
|
237
|
+
<span>{text}</span>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
3
240
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Button } from 'antd';
|
|
2
2
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
3
|
-
import * as ErrorIdentifierList from '@config/Identifier
|
|
4
|
-
import * as i18nKeys from '@config/Identifier
|
|
3
|
+
import * as ErrorIdentifierList from '@config/Identifier/Error';
|
|
4
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
5
5
|
|
|
6
6
|
export default function ErrorIdentifier() {
|
|
7
7
|
const { t } = useBaseRoutePage();
|
|
@@ -4,8 +4,8 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
import { IOC } from '@/core/IOC';
|
|
5
5
|
import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
|
|
6
6
|
import { ExecutorController } from '@/uikit/controllers/ExecutorController';
|
|
7
|
-
import {
|
|
8
|
-
import * as i18nKeys from '@config/Identifier
|
|
7
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
8
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
9
9
|
|
|
10
10
|
interface Task {
|
|
11
11
|
id: string;
|
|
@@ -24,12 +24,12 @@ export default function Executor() {
|
|
|
24
24
|
const { t } = useBaseRoutePage();
|
|
25
25
|
const executorController = IOC(ExecutorController);
|
|
26
26
|
const jSONStorageController = IOC(JSONStorageController);
|
|
27
|
-
const requestTimeout =
|
|
27
|
+
const requestTimeout = useStore(
|
|
28
28
|
jSONStorageController,
|
|
29
29
|
jSONStorageController.selector.requestTimeout
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
const helloState =
|
|
32
|
+
const helloState = useStore(
|
|
33
33
|
executorController,
|
|
34
34
|
executorController.selector.helloState
|
|
35
35
|
);
|
|
@@ -2,7 +2,7 @@ import { Button } from 'antd';
|
|
|
2
2
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
3
3
|
import LocaleLink from '@/uikit/components/LocaleLink';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
-
import * as i18nKeys from '@config/Identifier
|
|
5
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
6
6
|
|
|
7
7
|
export default function Home() {
|
|
8
8
|
const { t } = useBaseRoutePage();
|
|
@@ -2,13 +2,13 @@ import { IOC } from '@/core/IOC';
|
|
|
2
2
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
3
3
|
import template from 'lodash/template';
|
|
4
4
|
import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
|
|
5
|
-
import {
|
|
5
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
6
6
|
import { Button, Input } from 'antd';
|
|
7
|
-
import * as i18nKeys from '@config/Identifier
|
|
7
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
8
8
|
|
|
9
9
|
export default function JSONStorage() {
|
|
10
10
|
const jsonStorageController = IOC(JSONStorageController);
|
|
11
|
-
const controllerState =
|
|
11
|
+
const controllerState = useStore(jsonStorageController);
|
|
12
12
|
const { t } = useBaseRoutePage();
|
|
13
13
|
|
|
14
14
|
return (
|
|
@@ -3,10 +3,10 @@ import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
|
3
3
|
import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
|
|
4
4
|
import { RequestController } from '@/uikit/controllers/RequestController';
|
|
5
5
|
import { useMemo } from 'react';
|
|
6
|
-
import {
|
|
6
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
7
7
|
import { Button } from 'antd';
|
|
8
8
|
import { LoadingOutlined } from '@ant-design/icons';
|
|
9
|
-
import * as i18nKeys from '@config/Identifier
|
|
9
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
10
10
|
|
|
11
11
|
function JSONValue({ value }: { value: unknown }) {
|
|
12
12
|
const output = useMemo(() => {
|
|
@@ -25,8 +25,8 @@ function JSONValue({ value }: { value: unknown }) {
|
|
|
25
25
|
|
|
26
26
|
export default function Request() {
|
|
27
27
|
const requestController = IOC(RequestController);
|
|
28
|
-
const requestControllerState =
|
|
29
|
-
const jsonStorageControllerState =
|
|
28
|
+
const requestControllerState = useStore(requestController);
|
|
29
|
+
const jsonStorageControllerState = useStore(IOC(JSONStorageController));
|
|
30
30
|
const { t } = useBaseRoutePage();
|
|
31
31
|
|
|
32
32
|
return (
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import ThemeSwitcher from '@/uikit/components/ThemeSwitcher';
|
|
2
2
|
import LocaleLink from '@/uikit/components/LocaleLink';
|
|
3
3
|
import LanguageSwitcher from '@/uikit/components/LanguageSwitcher';
|
|
4
|
+
import { PublicAssetsPath } from '@/base/cases/PublicAssetsPath';
|
|
5
|
+
import { IOC } from '@/core/IOC';
|
|
4
6
|
|
|
5
7
|
export default function BaseHeader() {
|
|
6
8
|
return (
|
|
@@ -11,9 +13,13 @@ export default function BaseHeader() {
|
|
|
11
13
|
href="/"
|
|
12
14
|
className="flex items-center hover:opacity-80 transition-opacity"
|
|
13
15
|
>
|
|
14
|
-
<img
|
|
16
|
+
<img
|
|
17
|
+
src={IOC(PublicAssetsPath).getPath('/logo.svg')}
|
|
18
|
+
alt="logo"
|
|
19
|
+
className="h-8 w-auto"
|
|
20
|
+
/>
|
|
15
21
|
<span className="ml-2 text-lg font-semibold text-text">
|
|
16
|
-
{'appName
|
|
22
|
+
{IOC('AppConfig').appName}
|
|
17
23
|
</span>
|
|
18
24
|
</LocaleLink>
|
|
19
25
|
</div>
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { Select } from 'antd';
|
|
2
2
|
import { GlobalOutlined } from '@ant-design/icons';
|
|
3
|
-
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
|
+
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
|
4
4
|
import i18nConfig from '@config/i18n';
|
|
5
5
|
import { IOC } from '@/core/IOC';
|
|
6
6
|
import { I18nService, I18nServiceLocale } from '@/base/services/I18nService';
|
|
7
7
|
import { useCallback } from 'react';
|
|
8
|
-
import {
|
|
8
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
9
9
|
|
|
10
10
|
const { supportedLngs } = i18nConfig;
|
|
11
11
|
|
|
12
12
|
export default function LanguageSwitcher() {
|
|
13
13
|
const navigate = useNavigate();
|
|
14
14
|
const i18nService = IOC(I18nService);
|
|
15
|
-
const loading =
|
|
15
|
+
const loading = useStore(i18nService, i18nService.selector.loading);
|
|
16
16
|
const { lng } = useParams<{ lng: I18nServiceLocale }>();
|
|
17
|
-
const
|
|
17
|
+
const { pathname } = useLocation();
|
|
18
18
|
|
|
19
19
|
const languageOptions = supportedLngs.map((lang) => ({
|
|
20
20
|
key: lang,
|
|
@@ -33,11 +33,11 @@ export default function LanguageSwitcher() {
|
|
|
33
33
|
// Change i18n language
|
|
34
34
|
await i18nService.changeLanguage(newLang);
|
|
35
35
|
// Update URL path
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
navigate(pathname.replace(`/${lng}`, `/${newLang}`));
|
|
37
|
+
|
|
38
38
|
i18nService.changeLoading(false);
|
|
39
39
|
},
|
|
40
|
-
[lng,
|
|
40
|
+
[lng, pathname, navigate, i18nService]
|
|
41
41
|
);
|
|
42
42
|
|
|
43
43
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IOC } from '@/core/IOC';
|
|
2
2
|
import { ThemeService } from '@qlover/corekit-bridge';
|
|
3
|
-
import {
|
|
3
|
+
import { useStore } from '@/uikit/hooks/useStore';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { Select } from 'antd';
|
|
6
6
|
import {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '@ant-design/icons';
|
|
12
12
|
import clsx from 'clsx';
|
|
13
13
|
import { useMemo } from 'react';
|
|
14
|
-
import * as i18nKeys from '@config/Identifier
|
|
14
|
+
import * as i18nKeys from '@config/Identifier/I18n';
|
|
15
15
|
|
|
16
16
|
const colorMap: Record<
|
|
17
17
|
string,
|
|
@@ -36,7 +36,7 @@ const colorMap: Record<
|
|
|
36
36
|
|
|
37
37
|
export default function ThemeSwitcher() {
|
|
38
38
|
const themeService = IOC(ThemeService);
|
|
39
|
-
const { theme } =
|
|
39
|
+
const { theme } = useStore(themeService);
|
|
40
40
|
const themes = themeService.getSupportedThemes();
|
|
41
41
|
const { t } = useTranslation('common');
|
|
42
42
|
|
|
@@ -5,7 +5,7 @@ import { RouteMeta } from '@/base/types/Page';
|
|
|
5
5
|
import { createContext } from 'react';
|
|
6
6
|
import merge from 'lodash/merge';
|
|
7
7
|
import i18nConfig from '@config/i18n';
|
|
8
|
-
import { WITHIN_PAGE_PROVIDER } from '@config/Identifier
|
|
8
|
+
import { WITHIN_PAGE_PROVIDER } from '@config/Identifier/Error';
|
|
9
9
|
|
|
10
10
|
const { defaultNS } = i18nConfig;
|
|
11
11
|
|
|
@@ -6,9 +6,12 @@ import {
|
|
|
6
6
|
RequestAdapterFetchConfig
|
|
7
7
|
} from '@qlover/fe-corekit';
|
|
8
8
|
import { inject, injectable } from 'inversify';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
StoreInterface,
|
|
11
|
+
StoreStateInterface
|
|
12
|
+
} from '@/base/port/StoreInterface';
|
|
10
13
|
|
|
11
|
-
class ExecutorControllerState {
|
|
14
|
+
class ExecutorControllerState implements StoreStateInterface {
|
|
12
15
|
helloState = {
|
|
13
16
|
loading: false,
|
|
14
17
|
result: null as Record<string, unknown> | null,
|
|
@@ -31,7 +34,7 @@ const TestPlugin: ExecutorPlugin<RequestAdapterFetchConfig> = {
|
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
@injectable()
|
|
34
|
-
export class ExecutorController extends
|
|
37
|
+
export class ExecutorController extends StoreInterface<ExecutorControllerState> {
|
|
35
38
|
selector = {
|
|
36
39
|
helloState: (state: ExecutorControllerState) => state.helloState
|
|
37
40
|
};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { JSONStorage } from '@qlover/fe-corekit';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
StoreInterface,
|
|
4
|
+
StoreStateInterface
|
|
5
|
+
} from '@/base/port/StoreInterface';
|
|
3
6
|
import { random } from 'lodash';
|
|
4
7
|
|
|
5
|
-
interface JSONStoragePageState {
|
|
8
|
+
interface JSONStoragePageState extends StoreStateInterface {
|
|
6
9
|
testKey1?: number;
|
|
7
10
|
testKey2?: number;
|
|
8
11
|
expireTime: number;
|
|
9
12
|
requestTimeout: number;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
export class JSONStorageController extends
|
|
15
|
+
export class JSONStorageController extends StoreInterface<JSONStoragePageState> {
|
|
13
16
|
selector = {
|
|
14
17
|
requestTimeout: (state: JSONStoragePageState) => state.requestTimeout
|
|
15
18
|
};
|