@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/index.js +1 -1
  3. package/package.json +1 -1
  4. package/templates/react-app/.env +1 -2
  5. package/templates/react-app/README.md +70 -8
  6. package/templates/react-app/config/app.router.json +13 -13
  7. package/templates/react-app/config/common.ts +8 -0
  8. package/templates/react-app/config/i18n.ts +3 -1
  9. package/templates/react-app/config/{Identifier.I18n.ts → identifier/I18n.ts} +321 -3
  10. package/templates/react-app/index.html +1 -1
  11. package/templates/react-app/public/locales/en/common.json +54 -8
  12. package/templates/react-app/public/locales/zh/common.json +54 -8
  13. package/templates/react-app/public/router-root/logo.svg +1 -0
  14. package/templates/react-app/src/App.tsx +6 -3
  15. package/templates/react-app/src/base/cases/PublicAssetsPath.ts +17 -0
  16. package/templates/react-app/src/base/port/LoginInterface.ts +8 -0
  17. package/templates/react-app/src/base/port/StoreInterface.ts +58 -0
  18. package/templates/react-app/src/base/services/I18nService.ts +15 -9
  19. package/templates/react-app/src/{uikit/controllers/RouterController.ts → base/services/RouteService.ts} +12 -12
  20. package/templates/react-app/src/{uikit/controllers/UserController.ts → base/services/UserService.ts} +21 -11
  21. package/templates/react-app/src/core/bootstrap.ts +1 -1
  22. package/templates/react-app/src/core/registers/RegisterCommon.ts +11 -1
  23. package/templates/react-app/src/core/registers/RegisterControllers.ts +3 -12
  24. package/templates/react-app/src/pages/auth/Layout.tsx +5 -5
  25. package/templates/react-app/src/pages/auth/Login.tsx +50 -29
  26. package/templates/react-app/src/pages/auth/Register.tsx +238 -1
  27. package/templates/react-app/src/pages/base/About.tsx +1 -1
  28. package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +2 -2
  29. package/templates/react-app/src/pages/base/Executor.tsx +4 -4
  30. package/templates/react-app/src/pages/base/Home.tsx +1 -1
  31. package/templates/react-app/src/pages/base/JSONStorage.tsx +3 -3
  32. package/templates/react-app/src/pages/base/Request.tsx +4 -4
  33. package/templates/react-app/src/pages/base/components/BaseHeader.tsx +8 -2
  34. package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +7 -7
  35. package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +3 -3
  36. package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
  37. package/templates/react-app/src/uikit/controllers/ExecutorController.ts +6 -3
  38. package/templates/react-app/src/uikit/controllers/JSONStorageController.ts +6 -3
  39. package/templates/react-app/src/uikit/controllers/RequestController.ts +3 -4
  40. package/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +15 -0
  41. package/templates/react-app/src/uikit/hooks/useStore.ts +12 -0
  42. package/templates/react-app/src/uikit/providers/BaseRouteProvider.tsx +7 -1
  43. package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +7 -7
  44. package/templates/react-app/vite.config.ts +20 -11
  45. /package/templates/react-app/config/{Identifier.Error.ts → identifier/Error.ts} +0 -0
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Template FE-React</title>
7
+ <title>react-app</title>
8
8
  </head>
9
9
  <body>
10
10
  <div id="root"></div>
@@ -1,14 +1,14 @@
1
1
  {
2
- "404.notComponent": "Component not found",
3
- "404.notPage": "Page not found",
4
- "500.title": "Server Error",
5
- "header.theme.label": "Switch Theme",
6
2
  "err.ioc.not.implemented": "IOC not implemented",
7
3
  "err.local.no.user.token": "Local no user token",
8
4
  "err.global.no.window": "Global no window",
9
5
  "err.within.page.provider": "Must be used in PageProvider",
10
6
  "page.about.title": "About",
11
7
  "page.about.description": "Learn more about our project and team information",
8
+ "404.notComponent": "Component not found",
9
+ "404.notPage": "Page not found",
10
+ "500.title": "Server Error",
11
+ "header.theme.label": "Switch Theme",
12
12
  "about.title": "About",
13
13
  "jsonStorage.title": "JSONStorage Demo",
14
14
  "jsonStorage.title2": "Permanent storage test",
@@ -54,7 +54,6 @@
54
54
  "page.request.title": "Request Examples",
55
55
  "page.request.description": "Demonstrate various request examples and usage",
56
56
  "page.executor.title": "Executor Examples",
57
- "page.executor.description": "A powerful task executor supporting multiple task types and state management",
58
57
  "page.error.identifier.title": "Error Identifier",
59
58
  "page.error.identifier.description": "Error identifier usage and examples",
60
59
  "home.explore": "Explore",
@@ -88,6 +87,7 @@
88
87
  "page.request.trigger_api_catch": "Trigger API Catch Result",
89
88
  "page.request.stop_api_catch": "Stop API Catch Result",
90
89
  "page.executor.main_title": "Executor",
90
+ "page.executor.description": "A powerful task executor supporting multiple task types and state management",
91
91
  "page.executor.test_plugin.title": "Test Plugin",
92
92
  "page.executor.task.status.pending": "Pending",
93
93
  "page.executor.task.status.running": "Running",
@@ -120,7 +120,7 @@
120
120
  "page.executor.view_guide": "View Guide",
121
121
  "page.executor.contact_support": "Contact Support",
122
122
  "page.error.identifier.main_title": "Error Identifier",
123
- "page.error.identifier.source_description": "Identifier From: '@config/Identifier.Error'",
123
+ "page.error.identifier.source_description": "Identifier From: '@config/Identifier/Error'",
124
124
  "page.error.identifier.help.title": "Need Help?",
125
125
  "page.error.identifier.help.description": "If you encounter any issues while using error identifiers, please contact our support team",
126
126
  "page.error.identifier.contact_support": "Contact Support",
@@ -128,7 +128,9 @@
128
128
  "about.notification.title": "Notification Title",
129
129
  "about.notification.description": "This is a test notification",
130
130
  "about.button.message": "Show Message",
131
+ "about.button.message2": "Static Message",
131
132
  "about.button.notification": "Show Notification",
133
+ "about.button.notification2": "Static Notification",
132
134
  "about.tooltip.text": "This is a tooltip text",
133
135
  "about.button.tooltip": "Hover to show Tooltip",
134
136
  "about.modal.title": "Modal Example",
@@ -146,6 +148,50 @@
146
148
  "about.alert.message": "This is a warning alert",
147
149
  "common.ok": "OK",
148
150
  "common.cancel": "Cancel",
149
- "about.button.message2": "Static Message",
150
- "about.button.notification2": "Static Notification"
151
+ "login.welcome": "Welcome to the future of learning",
152
+ "login.subtitle": "Unlock personalized AI-powered learning experiences designed to accelerate your knowledge journey.",
153
+ "login.forgot_password": "Forgot your password?",
154
+ "login.continue_with": "or continue with",
155
+ "login.with_google": "Sign in with Google",
156
+ "login.no_account": "Don't have an account?",
157
+ "login.create_account": "Create one here",
158
+ "login.email_required": "Please input your email!",
159
+ "login.password_required": "Please input your password!",
160
+ "login.feature.ai_paths": "AI-powered personalized learning paths",
161
+ "login.feature.smart_recommendations": "Smart content recommendations",
162
+ "login.feature.progress_tracking": "Real-time progress tracking",
163
+ "login.email.title": "Enter email",
164
+ "login.password.title": "Enter password",
165
+ "login.forgot_password.title": "Reset password",
166
+ "login.button.title": "Sign in to account",
167
+ "login.with_google.title": "Sign in with Google account",
168
+ "login.create_account.title": "Create new account",
169
+ "register.title": "Create Account",
170
+ "register.subtitle": "Start your learning journey",
171
+ "register.username": "Username",
172
+ "register.username_required": "Please input your username!",
173
+ "register.email": "Email",
174
+ "register.email_required": "Please input your email!",
175
+ "register.password": "Password",
176
+ "register.password_required": "Please input your password!",
177
+ "register.confirm_password": "Confirm Password",
178
+ "register.confirm_password_required": "Please confirm your password!",
179
+ "register.password_mismatch": "The passwords you entered don't match!",
180
+ "register.button": "Register",
181
+ "register.terms_prefix": "By registering, you agree to our",
182
+ "register.terms_link": "Terms of Service",
183
+ "register.terms_and": "and",
184
+ "register.privacy_link": "Privacy Policy",
185
+ "register.have_account": "Already have an account?",
186
+ "register.login_link": "Sign in",
187
+ "register.feature.personalized": "Personalized Learning Experience",
188
+ "register.feature.support": "Expert Support and Guidance",
189
+ "register.feature.community": "Active Learning Community",
190
+ "register.terms_required": "Please agree to the Terms of Service and Privacy Policy",
191
+ "page.error_identifier.title": "Error Identifier",
192
+ "page.home.title": "Home",
193
+ "page.404.title": "404 - Page Not Found",
194
+ "page.500.title": "500 - Server Error",
195
+ "page.login.title": "Login",
196
+ "page.register.title": "Register"
151
197
  }
@@ -1,14 +1,14 @@
1
1
  {
2
- "404.notComponent": "组件不存在",
3
- "404.notPage": "页面不存在",
4
- "500.title": "服务器错误",
5
- "header.theme.label": "切换主题",
6
2
  "err.ioc.not.implemented": "IOC 未实现",
7
3
  "err.local.no.user.token": "本地未找到 user token",
8
4
  "err.global.no.window": "全局未找到 window",
9
5
  "err.within.page.provider": "必须在 PageProvider 中使用",
10
6
  "page.about.title": "关于",
11
7
  "page.about.description": "了解更多关于我们的项目和团队信息",
8
+ "404.notComponent": "组件不存在",
9
+ "404.notPage": "页面不存在",
10
+ "500.title": "服务器错误",
11
+ "header.theme.label": "切换主题",
12
12
  "about.title": "关于我们",
13
13
  "jsonStorage.title": "JSONStorage Demo",
14
14
  "jsonStorage.title2": "永久存储测试",
@@ -54,7 +54,6 @@
54
54
  "page.request.title": "请求示例",
55
55
  "page.request.description": "展示各种请求示例和用法",
56
56
  "page.executor.title": "执行器示例",
57
- "page.executor.description": "一个强大的任务执行器,支持多种任务类型和状态管理",
58
57
  "page.error.identifier.title": "错误标识符",
59
58
  "page.error.identifier.description": "错误标识符的使用和示例",
60
59
  "home.explore": "探索",
@@ -88,6 +87,7 @@
88
87
  "page.request.trigger_api_catch": "触发 API 捕获结果",
89
88
  "page.request.stop_api_catch": "停止 API 捕获结果",
90
89
  "page.executor.main_title": "执行器",
90
+ "page.executor.description": "一个强大的任务执行器,支持多种任务类型和状态管理",
91
91
  "page.executor.test_plugin.title": "测试插件",
92
92
  "page.executor.task.status.pending": "等待中",
93
93
  "page.executor.task.status.running": "运行中",
@@ -120,7 +120,7 @@
120
120
  "page.executor.view_guide": "查看指南",
121
121
  "page.executor.contact_support": "联系支持",
122
122
  "page.error.identifier.main_title": "错误标识符",
123
- "page.error.identifier.source_description": "来自 '@config/Identifier.Error' 的标识符",
123
+ "page.error.identifier.source_description": "来自 '@config/Identifier/Error' 的标识符",
124
124
  "page.error.identifier.help.title": "需要帮助?",
125
125
  "page.error.identifier.help.description": "如果您在使用错误标识符时遇到问题,请联系我们的支持团队",
126
126
  "page.error.identifier.contact_support": "联系支持",
@@ -128,7 +128,9 @@
128
128
  "about.notification.title": "通知标题",
129
129
  "about.notification.description": "这是一条测试通知",
130
130
  "about.button.message": "显示 Message",
131
+ "about.button.message2": "静态消息",
131
132
  "about.button.notification": "显示 Notification",
133
+ "about.button.notification2": "静态通知",
132
134
  "about.tooltip.text": "这是一个提示文本",
133
135
  "about.button.tooltip": "悬停显示 Tooltip",
134
136
  "about.modal.title": "模态框示例",
@@ -146,6 +148,50 @@
146
148
  "about.alert.message": "这是一个警告提示",
147
149
  "common.ok": "确定",
148
150
  "common.cancel": "取消",
149
- "about.button.message2": "静态消息",
150
- "about.button.notification2": "静态通知"
151
+ "login.welcome": "欢迎来到未来学习",
152
+ "login.subtitle": "解锁个性化 AI 驱动的学习体验,加速您的知识旅程。",
153
+ "login.forgot_password": "忘记密码?",
154
+ "login.continue_with": "或继续使用",
155
+ "login.with_google": "使用 Google 登录",
156
+ "login.no_account": "还没有账号?",
157
+ "login.create_account": "在此创建",
158
+ "login.email_required": "请输入您的邮箱!",
159
+ "login.password_required": "请输入您的密码!",
160
+ "login.feature.ai_paths": "AI驱动的个性化学习路径",
161
+ "login.feature.smart_recommendations": "智能内容推荐",
162
+ "login.feature.progress_tracking": "实时进度追踪",
163
+ "login.email.title": "输入邮箱",
164
+ "login.password.title": "输入密码",
165
+ "login.forgot_password.title": "重置密码",
166
+ "login.button.title": "登录账号",
167
+ "login.with_google.title": "使用Google账号登录",
168
+ "login.create_account.title": "创建新账号",
169
+ "register.title": "创建账号",
170
+ "register.subtitle": "开始您的学习之旅",
171
+ "register.username": "用户名",
172
+ "register.username_required": "请输入用户名!",
173
+ "register.email": "邮箱",
174
+ "register.email_required": "请输入邮箱!",
175
+ "register.password": "密码",
176
+ "register.password_required": "请输入密码!",
177
+ "register.confirm_password": "确认密码",
178
+ "register.confirm_password_required": "请确认密码!",
179
+ "register.password_mismatch": "两次输入的密码不匹配!",
180
+ "register.button": "注册",
181
+ "register.terms_prefix": "注册即表示您同意我们的",
182
+ "register.terms_link": "服务条款",
183
+ "register.terms_and": "和",
184
+ "register.privacy_link": "隐私政策",
185
+ "register.have_account": "已有账号?",
186
+ "register.login_link": "登录",
187
+ "register.feature.personalized": "个性化学习体验",
188
+ "register.feature.support": "专家支持和指导",
189
+ "register.feature.community": "活跃的学习社区",
190
+ "register.terms_required": "请同意服务条款和隐私政策",
191
+ "page.error_identifier.title": "错误标识符",
192
+ "page.home.title": "首页",
193
+ "page.404.title": "404 - 页面未找到",
194
+ "page.500.title": "500 - 服务器错误",
195
+ "page.login.title": "登录",
196
+ "page.register.title": "注册"
151
197
  }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path><text x="50" y="50" font-family="Arial" font-size="24" fill="black">fe</text></svg>
@@ -3,9 +3,10 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
3
3
  import { lazy, useMemo } from 'react';
4
4
  import { RouterRenderComponent } from './uikit/components/RouterRenderComponent';
5
5
  import { IOC } from './core/IOC';
6
- import { RouterController } from './uikit/controllers/RouterController';
6
+ import { RouteService } from './base/services/RouteService';
7
7
  import { RouterLoader, type ComponentValue } from '@/base/cases/RouterLoader';
8
8
  import { AntdThemeProvider } from '@brain-toolkit/antd-theme-override/react';
9
+ import { routerPrefix } from '@config/common';
9
10
 
10
11
  function getAllPages() {
11
12
  const modules = import.meta.glob('./pages/**/*.tsx');
@@ -28,10 +29,12 @@ const routerLoader = new RouterLoader({
28
29
 
29
30
  function App() {
30
31
  const routerBase = useMemo(() => {
31
- const routes = IOC(RouterController)
32
+ const routes = IOC(RouteService)
32
33
  .getRoutes()
33
34
  .map((route) => routerLoader.toRoute(route));
34
- const router = createBrowserRouter(routes);
35
+ const router = createBrowserRouter(routes, {
36
+ basename: routerPrefix
37
+ });
35
38
  return router;
36
39
  }, []);
37
40
 
@@ -0,0 +1,17 @@
1
+ import { routerPrefix } from '@config/common';
2
+ import { injectable } from 'inversify';
3
+
4
+ /**
5
+ * Get Publish Assets Path
6
+ *
7
+ * - If router has prefix, the path will be `prefix/path`
8
+ * - If router has no prefix, the path will be `path`
9
+ */
10
+ @injectable()
11
+ export class PublicAssetsPath {
12
+ constructor(protected prefix: string = routerPrefix) {}
13
+
14
+ getPath(path: string): string {
15
+ return this.prefix + `/${path}`;
16
+ }
17
+ }
@@ -1,4 +1,12 @@
1
+ export interface RegisterFormData {
2
+ username: string;
3
+ email: string;
4
+ password: string;
5
+ confirmPassword: string;
6
+ agreeToTerms: boolean;
7
+ }
1
8
  export interface LoginInterface {
2
9
  login(params: { username: string; password: string }): Promise<unknown>;
3
10
  logout(): void;
11
+ register(params: RegisterFormData): Promise<unknown>;
4
12
  }
@@ -0,0 +1,58 @@
1
+ import { SliceStore } from '@qlover/slice-store-react';
2
+
3
+ /**
4
+ * Store State Interface
5
+ *
6
+ * This interface is used to define the state of a store.
7
+ * It is used to define the state of a store.
8
+ *
9
+ * must implement the copyWith method
10
+ */
11
+ export interface StoreStateInterface {
12
+ // You can define your own properties here
13
+ // ...
14
+ }
15
+
16
+ /**
17
+ * Store Interface
18
+ *
19
+ * This class is used to define the store interface.
20
+ * It is used to define the store interface.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * class ChatStoreState implements StoreStateInterface {
25
+ * isChatRunning: boolean = false;
26
+ *
27
+ * copyWith(state: { isChatRunning?: boolean }): this {
28
+ * return Object.assign(new ChatStoreState(), this, state);
29
+ * }
30
+ * }
31
+ *
32
+ * export class ChatStore extends StoreInterface<ChatStoreState> {
33
+ * constructor() {
34
+ * super(() => new ChatStoreState());
35
+ * }
36
+ * }
37
+ * ```
38
+ */
39
+ export abstract class StoreInterface<
40
+ T extends StoreStateInterface
41
+ > extends SliceStore<T> {
42
+ /**
43
+ * Constructor
44
+ *
45
+ * @param stateFactory - The factory function to create the initial state
46
+ */
47
+ constructor(protected stateFactory: () => T) {
48
+ super(stateFactory);
49
+ }
50
+
51
+ /**
52
+ * Reset the state of the store
53
+ */
54
+ resetState(): void {
55
+ // Create a new instance of initial state
56
+ this.emit(this.stateFactory());
57
+ }
58
+ }
@@ -4,22 +4,22 @@ import LanguageDetector from 'i18next-browser-languagedetector';
4
4
  import HttpApi from 'i18next-http-backend';
5
5
  import merge from 'lodash/merge';
6
6
  import i18nConfig from '@config/i18n';
7
+ import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
7
8
  import {
8
- SliceStore,
9
- type BootstrapExecutorPlugin
10
- } from '@qlover/corekit-bridge';
11
-
9
+ StoreInterface,
10
+ StoreStateInterface
11
+ } from '@/base/port/StoreInterface';
12
12
  const { supportedLngs, fallbackLng } = i18nConfig;
13
13
 
14
14
  export type I18nServiceLocale = (typeof supportedLngs)[number];
15
15
 
16
- export class I18nServiceState {
16
+ export class I18nServiceState implements StoreStateInterface {
17
17
  loading: boolean = false;
18
18
  constructor(public language: I18nServiceLocale) {}
19
19
  }
20
20
 
21
21
  export class I18nService
22
- extends SliceStore<I18nServiceState>
22
+ extends StoreInterface<I18nServiceState>
23
23
  implements BootstrapExecutorPlugin
24
24
  {
25
25
  readonly pluginName = 'I18nService';
@@ -57,9 +57,15 @@ export class I18nService
57
57
  const pathLanguageDetector = {
58
58
  name: 'pathLanguageDetector',
59
59
  lookup: () => {
60
- const path = this.pathname.split('/');
61
- const language = path[1];
62
- return I18nService.isValidLanguage(language) ? language : fallbackLng;
60
+ const paths = this.pathname.split('/');
61
+
62
+ for (const path of paths) {
63
+ if (I18nService.isValidLanguage(path)) {
64
+ return path;
65
+ }
66
+ }
67
+
68
+ return fallbackLng;
63
69
  },
64
70
  cacheUserLanguage() {
65
71
  // no cache, because we get language from URL
@@ -4,32 +4,32 @@ import type { UIDependenciesInterface } from '@/base/port/UIDependenciesInterfac
4
4
  import type { LoggerInterface } from '@qlover/logger';
5
5
  import { I18nService } from '@/base/services/I18nService';
6
6
 
7
- export type RouterControllerDependencies = {
7
+ export type RouterServiceDependencies = {
8
8
  navigate: NavigateFunction;
9
9
  };
10
10
 
11
- export type RouterControllerOptions = {
11
+ export type RouterServiceOptions = {
12
12
  config: {
13
13
  routes: RouteConfigValue[];
14
14
  };
15
15
  logger: LoggerInterface;
16
16
  };
17
17
 
18
- export type RouterControllerState = {
18
+ export type RouterServiceState = {
19
19
  routes: RouteConfigValue[];
20
20
  };
21
21
 
22
- export class RouterController
23
- implements UIDependenciesInterface<RouterControllerDependencies>
22
+ export class RouteService
23
+ implements UIDependenciesInterface<RouterServiceDependencies>
24
24
  {
25
25
  /**
26
26
  * @override
27
27
  */
28
- dependencies?: RouterControllerDependencies;
28
+ dependencies?: RouterServiceDependencies;
29
29
 
30
- state: RouterControllerState;
30
+ state: RouterServiceState;
31
31
 
32
- constructor(private options: RouterControllerOptions) {
32
+ constructor(private options: RouterServiceOptions) {
33
33
  this.state = {
34
34
  routes: options.config.routes
35
35
  };
@@ -49,7 +49,7 @@ export class RouterController
49
49
  return navigate;
50
50
  }
51
51
 
52
- static composePath(path: string): string {
52
+ composePath(path: string): string {
53
53
  const targetLang = I18nService.getCurrentLanguage();
54
54
  return `/${targetLang}${path}`;
55
55
  }
@@ -57,11 +57,11 @@ export class RouterController
57
57
  /**
58
58
  * @override
59
59
  */
60
- setDependencies(dependencies: Partial<RouterControllerDependencies>): void {
60
+ setDependencies(dependencies: Partial<RouterServiceDependencies>): void {
61
61
  this.dependencies = Object.assign(
62
62
  this.dependencies || {},
63
63
  dependencies
64
- ) as RouterControllerDependencies;
64
+ ) as RouterServiceDependencies;
65
65
  }
66
66
 
67
67
  getRoutes(): RouteConfigValue[] {
@@ -73,7 +73,7 @@ export class RouterController
73
73
  }
74
74
 
75
75
  goto(path: string, options?: NavigateOptions): void {
76
- path = RouterController.composePath(path);
76
+ path = this.composePath(path);
77
77
  this.logger.debug('Goto path => ', path);
78
78
  this.navigate?.(path, options);
79
79
  }
@@ -3,17 +3,17 @@ import type {
3
3
  UserApiGetUserInfoTransaction,
4
4
  UserApiLoginTransaction
5
5
  } from '@/base/apis/userApi/UserApiType';
6
- import { RouterController } from './RouterController';
6
+ import { RouteService } from './RouteService';
7
7
  import { ThreadUtil, type StorageTokenInterface } from '@qlover/corekit-bridge';
8
8
  import { inject, injectable } from 'inversify';
9
9
  import { IOCIdentifier } from '@/core/IOC';
10
- import { LoginInterface } from '@/base/port/LoginInterface';
10
+ import { LoginInterface, RegisterFormData } from '@/base/port/LoginInterface';
11
11
  import { UserApi } from '@/base/apis/userApi/UserApi';
12
12
  import { AppError } from '@/base/cases/AppError';
13
- import { LOCAL_NO_USER_TOKEN } from '@config/Identifier.Error';
14
- import { SliceStore } from '@qlover/slice-store-react';
13
+ import { LOCAL_NO_USER_TOKEN } from '@config/Identifier/Error';
14
+ import { StoreInterface, StoreStateInterface } from '../port/StoreInterface';
15
15
 
16
- class UserControllerState {
16
+ class UserServiceState implements StoreStateInterface {
17
17
  success: boolean = false;
18
18
  userInfo: UserApiGetUserInfoTransaction['response']['data'] = {
19
19
  name: '',
@@ -23,22 +23,22 @@ class UserControllerState {
23
23
  }
24
24
 
25
25
  @injectable()
26
- export class UserController
27
- extends SliceStore<UserControllerState>
26
+ export class UserService
27
+ extends StoreInterface<UserServiceState>
28
28
  implements ExecutorPlugin, LoginInterface
29
29
  {
30
- readonly pluginName = 'UserController';
30
+ readonly pluginName = 'UserService';
31
31
 
32
32
  constructor(
33
33
  @inject(UserApi) private userApi: UserApi,
34
- @inject(RouterController) private routerController: RouterController,
34
+ @inject(RouteService) private routerController: RouteService,
35
35
  @inject(IOCIdentifier.FeApiToken)
36
36
  private userToken: StorageTokenInterface<string>
37
37
  ) {
38
- super(() => new UserControllerState());
38
+ super(() => new UserServiceState());
39
39
  }
40
40
 
41
- setState(state: Partial<UserControllerState>): void {
41
+ setState(state: Partial<UserServiceState>): void {
42
42
  this.emit({ ...this.state, ...state });
43
43
  }
44
44
 
@@ -111,4 +111,14 @@ export class UserController
111
111
  isAuthenticated(): boolean {
112
112
  return this.state.success;
113
113
  }
114
+
115
+ /**
116
+ * @override
117
+ */
118
+ async register(params: RegisterFormData): Promise<unknown> {
119
+ return this.login({
120
+ username: params.username,
121
+ password: params.password
122
+ });
123
+ }
114
124
  }
@@ -4,7 +4,7 @@ import { IOC } from './IOC';
4
4
  import * as globals from '@/core/globals';
5
5
  import { IocRegister } from './registers';
6
6
  import { BootstrapsRegistry } from './bootstraps';
7
- import { GLOBAL_NO_WINDOW } from '@config/Identifier.Error';
7
+ import { GLOBAL_NO_WINDOW } from '@config/Identifier/Error';
8
8
 
9
9
  export default async function startup({
10
10
  root,
@@ -17,8 +17,10 @@ import {
17
17
  import mockDataJson from '@config/feapi.mock.json';
18
18
  import { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
19
19
  import themeConfig from '@config/theme.json';
20
- import { localJsonStorage } from '../globals';
20
+ import { localJsonStorage, logger } from '../globals';
21
21
  import { I18nService } from '@/base/services/I18nService';
22
+ import { RouteService } from '@/base/services/RouteService';
23
+ import { base as baseRoutes } from '@config/app.router.json';
22
24
 
23
25
  export class RegisterCommon implements InversifyRegisterInterface {
24
26
  register(
@@ -64,6 +66,14 @@ export class RegisterCommon implements InversifyRegisterInterface {
64
66
  })
65
67
  );
66
68
 
69
+ container.bind(
70
+ RouteService,
71
+ new RouteService({
72
+ config: baseRoutes,
73
+ logger
74
+ })
75
+ );
76
+
67
77
  container.bind(I18nService, new I18nService(options.pathname));
68
78
  }
69
79
  }
@@ -1,24 +1,15 @@
1
- import { localJsonStorage, logger } from '../globals';
2
- import { RouterController } from '@/uikit/controllers/RouterController';
1
+ import { localJsonStorage } from '../globals';
3
2
  import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
4
3
  import { ProcesserService } from '@/base/services/ProcesserService';
5
- import { UserController } from '@/uikit/controllers/UserController';
6
- import { base as baseRoutes } from '@config/app.router.json';
4
+ import { UserService } from '@/base/services/UserService';
7
5
  import { InversifyRegisterInterface } from '../IOC';
8
6
  import { InversifyContainer } from '../IOC';
9
-
10
7
  export class RegisterControllers implements InversifyRegisterInterface {
11
8
  register(container: InversifyContainer): void {
12
- const routerController = new RouterController({
13
- config: baseRoutes,
14
- logger
15
- });
16
-
17
9
  const jsonStorageController = new JSONStorageController(localJsonStorage);
18
10
 
19
- container.bind(RouterController, routerController);
20
11
  container.bind(JSONStorageController, jsonStorageController);
21
12
 
22
- container.get(ProcesserService).use(container.get(UserController));
13
+ container.get(ProcesserService).use(container.get(UserService));
23
14
  }
24
15
  }
@@ -1,14 +1,14 @@
1
1
  import { IOC } from '@/core/IOC';
2
- import { UserController } from '@/uikit/controllers/UserController';
2
+ import { UserService } from '@/base/services/UserService';
3
3
  import { Navigate, Outlet } from 'react-router-dom';
4
- import { useSliceStore } from '@qlover/slice-store-react';
4
+ import { useStore } from '@/uikit/hooks/useStore';
5
5
 
6
6
  export default function Layout() {
7
- const userController = IOC(UserController);
8
- useSliceStore(userController, (state) => state.success);
7
+ const userService = IOC(UserService);
8
+ useStore(userService, (state) => state.success);
9
9
 
10
10
  // If user is authenticated, redirect to home page
11
- if (userController.isAuthenticated()) {
11
+ if (userService.isAuthenticated()) {
12
12
  return <Navigate to="/" replace />;
13
13
  }
14
14