@qlover/create-app 0.7.5 → 0.7.7
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 +257 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/.env.template +22 -0
- package/dist/templates/next-app/.prettierignore +58 -0
- package/dist/templates/next-app/README.md +36 -0
- package/dist/templates/next-app/build/generateLocales.ts +25 -0
- package/dist/templates/next-app/config/IOCIdentifier.ts +45 -0
- package/dist/templates/next-app/config/Identifier/common.error.ts +34 -0
- package/dist/templates/next-app/config/Identifier/common.ts +62 -0
- package/dist/templates/next-app/config/Identifier/index.ts +10 -0
- package/dist/templates/next-app/config/Identifier/page.about.ts +181 -0
- package/dist/templates/next-app/config/Identifier/page.executor.ts +272 -0
- package/dist/templates/next-app/config/Identifier/page.home.ts +63 -0
- package/dist/templates/next-app/config/Identifier/page.identifiter.ts +39 -0
- package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +72 -0
- package/dist/templates/next-app/config/Identifier/page.login.ts +165 -0
- package/dist/templates/next-app/config/Identifier/page.register.ts +147 -0
- package/dist/templates/next-app/config/Identifier/page.request.ts +182 -0
- package/dist/templates/next-app/config/common.ts +34 -0
- package/dist/templates/next-app/config/i18n/PageI18nInterface.ts +51 -0
- package/dist/templates/next-app/config/i18n/i18nConfig.ts +12 -0
- package/dist/templates/next-app/config/i18n/index.ts +3 -0
- package/dist/templates/next-app/config/i18n/loginI18n.ts +42 -0
- package/dist/templates/next-app/config/theme.ts +23 -0
- package/dist/templates/next-app/docs/env.md +94 -0
- package/dist/templates/next-app/eslint.config.mjs +181 -0
- package/dist/templates/next-app/next.config.ts +21 -0
- package/dist/templates/next-app/package.json +58 -0
- package/dist/templates/next-app/plugins/eslint-plugin-testid.mjs +94 -0
- package/dist/templates/next-app/plugins/generateLocalesPlugin.ts +33 -0
- package/dist/templates/next-app/postcss.config.mjs +5 -0
- package/dist/templates/next-app/public/file.svg +1 -0
- package/dist/templates/next-app/public/globe.svg +1 -0
- package/dist/templates/next-app/public/locales/en/common.json +183 -0
- package/dist/templates/next-app/public/locales/zh/common.json +183 -0
- package/dist/templates/next-app/public/next.svg +1 -0
- package/dist/templates/next-app/public/vercel.svg +1 -0
- package/dist/templates/next-app/public/window.svg +1 -0
- package/dist/templates/next-app/src/app/[locale]/favicon.ico +0 -0
- package/dist/templates/next-app/src/app/[locale]/layout.tsx +44 -0
- package/dist/templates/next-app/src/app/[locale]/login/FeatureItem.tsx +13 -0
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +115 -0
- package/dist/templates/next-app/src/app/[locale]/login/page.tsx +73 -0
- package/dist/templates/next-app/src/app/[locale]/not-found.tsx +24 -0
- package/dist/templates/next-app/src/app/[locale]/page.tsx +106 -0
- package/dist/templates/next-app/src/base/cases/AppConfig.ts +15 -0
- package/dist/templates/next-app/src/base/cases/InversifyContainer.ts +33 -0
- package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +25 -0
- package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +11 -0
- package/dist/templates/next-app/src/base/services/I18nService.ts +115 -0
- package/dist/templates/next-app/src/base/services/UserService.ts +23 -0
- package/dist/templates/next-app/src/core/IOC.ts +58 -0
- package/dist/templates/next-app/src/core/IocRegisterImpl.ts +100 -0
- package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +98 -0
- package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +47 -0
- package/dist/templates/next-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
- package/dist/templates/next-app/src/core/bootstraps/PrintBootstrap.ts +18 -0
- package/dist/templates/next-app/src/core/globals.ts +21 -0
- package/dist/templates/next-app/src/i18n/request.ts +22 -0
- package/dist/templates/next-app/src/i18n/routing.ts +30 -0
- package/dist/templates/next-app/src/middleware.ts +22 -0
- package/dist/templates/next-app/src/server/getServerI18n.ts +26 -0
- package/dist/templates/next-app/src/styles/css/antd-themes/_default.css +239 -0
- package/dist/templates/next-app/src/styles/css/antd-themes/dark.css +178 -0
- package/dist/templates/next-app/src/styles/css/antd-themes/index.css +3 -0
- package/dist/templates/next-app/src/styles/css/antd-themes/no-context.css +34 -0
- package/dist/templates/next-app/src/styles/css/antd-themes/pink.css +204 -0
- package/dist/templates/next-app/src/styles/css/index.css +6 -0
- package/dist/templates/next-app/src/styles/css/page.css +19 -0
- package/dist/templates/next-app/src/styles/css/tailwind.css +5 -0
- package/dist/templates/next-app/src/styles/css/themes/_default.css +29 -0
- package/dist/templates/next-app/src/styles/css/themes/dark.css +29 -0
- package/dist/templates/next-app/src/styles/css/themes/index.css +3 -0
- package/dist/templates/next-app/src/styles/css/themes/pink.css +29 -0
- package/dist/templates/next-app/src/styles/css/zIndex.css +9 -0
- package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +42 -0
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +25 -0
- package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +45 -0
- package/dist/templates/next-app/src/uikit/components/LanguageSwitcher.tsx +52 -0
- package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +51 -0
- package/dist/templates/next-app/src/uikit/components/NextIntlProvider.tsx +21 -0
- package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +86 -0
- package/dist/templates/next-app/src/uikit/context/IOCContext.ts +6 -0
- package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +28 -0
- package/dist/templates/next-app/src/uikit/hook/useIOC.ts +37 -0
- package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +11 -0
- package/dist/templates/next-app/src/uikit/hook/useStore.ts +15 -0
- package/dist/templates/next-app/tailwind.config.ts +8 -0
- package/dist/templates/next-app/tsconfig.json +36 -0
- package/dist/templates/react-app/.env.template +0 -2
- package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +1 -1
- package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +6 -31
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +1 -1
- package/dist/templates/react-app/config/IOCIdentifier.ts +77 -5
- package/dist/templates/react-app/config/app.router.ts +2 -2
- package/dist/templates/react-app/package.json +4 -7
- package/dist/templates/react-app/public/locales/en/common.json +1 -1
- package/dist/templates/react-app/public/locales/zh/common.json +1 -1
- package/dist/templates/react-app/src/App.tsx +9 -4
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +4 -0
- package/dist/templates/react-app/src/base/cases/DialogHandler.ts +16 -13
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +4 -3
- package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +2 -2
- package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +39 -0
- package/dist/templates/react-app/src/base/cases/RequestState.ts +20 -0
- package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
- package/dist/templates/react-app/src/base/cases/RouterLoader.ts +8 -2
- package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +7 -0
- package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +24 -0
- package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +10 -0
- package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +20 -0
- package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +20 -0
- package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +23 -0
- package/dist/templates/react-app/src/base/port/RequestStatusInterface.ts +5 -0
- package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +27 -0
- package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +12 -0
- package/dist/templates/react-app/src/base/services/I18nService.ts +10 -6
- package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +23 -5
- package/dist/templates/react-app/src/base/services/RouteService.ts +25 -54
- package/dist/templates/react-app/src/base/services/UserService.ts +10 -20
- package/dist/templates/react-app/src/core/IOC.ts +1 -26
- package/dist/templates/react-app/src/core/IocRegisterImpl.ts +125 -0
- package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +4 -6
- package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +8 -6
- package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
- package/dist/templates/react-app/src/pages/auth/Layout.tsx +2 -2
- package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +5 -6
- package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +8 -7
- package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +8 -19
- package/dist/templates/react-app/src/pages/base/{ErrorIdentifierPage.tsx → IdentifierPage.tsx} +1 -1
- package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +11 -15
- package/dist/templates/react-app/src/pages/base/Layout.tsx +1 -1
- package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +2 -2
- package/dist/templates/react-app/src/pages/base/RequestPage.tsx +34 -46
- package/dist/templates/react-app/src/styles/css/antd-themes/_default.css +2 -2
- package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +2 -2
- package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +2 -2
- package/dist/templates/react-app/src/styles/css/index.css +1 -0
- package/dist/templates/react-app/src/styles/css/page.css +8 -0
- package/dist/templates/react-app/src/styles/css/zIndex.css +9 -0
- package/dist/templates/react-app/src/uikit/{controllers/ExecutorController.ts → bridges/ExecutorPageBridge.ts} +13 -36
- package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +41 -0
- package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +16 -0
- package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +136 -0
- package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +3 -2
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +2 -2
- package/dist/templates/react-app/src/uikit/{providers → components}/ProcessExecutorProvider.tsx +4 -4
- package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
- package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +3 -5
- package/dist/templates/react-app/src/uikit/{providers → components}/UserAuthProvider.tsx +3 -3
- package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +5 -2
- package/dist/templates/react-app/src/uikit/hooks/{userRouterService.ts → useNavigateBridge.ts} +3 -3
- package/dist/templates/react-app/src/uikit/hooks/useStore.ts +5 -2
- package/dist/templates/react-app/tsconfig.json +1 -4
- package/package.json +1 -1
- package/dist/templates/react-app/src/base/port/InteractionHubInterface.ts +0 -94
- package/dist/templates/react-app/src/base/port/UIDependenciesInterface.ts +0 -37
- package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +0 -25
- package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +0 -74
- package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +0 -26
- package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +0 -30
- package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +0 -49
- package/dist/templates/react-app/src/uikit/controllers/RequestController.ts +0 -158
- /package/dist/templates/react-app/src/uikit/{providers → components}/BaseRouteProvider.tsx +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useTranslations } from 'next-intl';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import type { PageI18nInterface } from '@config/i18n/PageI18nInterface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to get the i18n interface
|
|
7
|
+
*
|
|
8
|
+
* @param i18nInterface - The i18n interface to get
|
|
9
|
+
* @returns The i18n interface
|
|
10
|
+
*/
|
|
11
|
+
export function useI18nInterface<T extends PageI18nInterface>(
|
|
12
|
+
i18nInterface: T
|
|
13
|
+
): T {
|
|
14
|
+
const t = useTranslations();
|
|
15
|
+
|
|
16
|
+
const i18n = useMemo(() => {
|
|
17
|
+
return Object.fromEntries(
|
|
18
|
+
Object.entries(i18nInterface).map(([key, value]) => {
|
|
19
|
+
if (typeof value === 'string') {
|
|
20
|
+
return [key, t(value)];
|
|
21
|
+
}
|
|
22
|
+
return [key, value];
|
|
23
|
+
})
|
|
24
|
+
) as T;
|
|
25
|
+
}, [i18nInterface, t]);
|
|
26
|
+
|
|
27
|
+
return i18n;
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { IOCContext } from '../context/IOCContext';
|
|
3
|
+
import type { IOCIdentifierMap } from '@config/IOCIdentifier';
|
|
4
|
+
import type {
|
|
5
|
+
IOCContainerInterface,
|
|
6
|
+
IOCFunctionInterface
|
|
7
|
+
} from '@qlover/corekit-bridge';
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
type IOCIdentifier = keyof IOCIdentifierMap | (new (...args: any[]) => any);
|
|
11
|
+
|
|
12
|
+
export function useIOC(): IOCFunctionInterface<
|
|
13
|
+
IOCIdentifierMap,
|
|
14
|
+
IOCContainerInterface
|
|
15
|
+
>;
|
|
16
|
+
export function useIOC<T extends IOCIdentifier>(
|
|
17
|
+
identifier: T
|
|
18
|
+
): T extends keyof IOCIdentifierMap
|
|
19
|
+
? IOCIdentifierMap[T]
|
|
20
|
+
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
T extends new (...args: any[]) => any
|
|
22
|
+
? InstanceType<T>
|
|
23
|
+
: never;
|
|
24
|
+
|
|
25
|
+
export function useIOC<T extends IOCIdentifier>(identifier?: T) {
|
|
26
|
+
const IOC = useContext(IOCContext);
|
|
27
|
+
|
|
28
|
+
if (!IOC) {
|
|
29
|
+
throw new Error('IOC is not found');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (identifier === undefined) {
|
|
33
|
+
return IOC;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return IOC(identifier);
|
|
37
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useSliceStore, type SliceStore } from '@qlover/slice-store-react';
|
|
2
|
+
import type {
|
|
3
|
+
StoreInterface,
|
|
4
|
+
StoreStateInterface
|
|
5
|
+
} from '@qlover/corekit-bridge';
|
|
6
|
+
|
|
7
|
+
export function useStore<
|
|
8
|
+
C extends StoreInterface<StoreStateInterface>,
|
|
9
|
+
State = C['state']
|
|
10
|
+
>(store: C, selector?: (state: C['state']) => State): State {
|
|
11
|
+
return useSliceStore(
|
|
12
|
+
store as unknown as SliceStore<StoreStateInterface>,
|
|
13
|
+
selector
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"experimentalDecorators": true,
|
|
17
|
+
"emitDecoratorMetadata": true,
|
|
18
|
+
"plugins": [
|
|
19
|
+
{
|
|
20
|
+
"name": "next"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"paths": {
|
|
24
|
+
"@/*": ["./src/*"],
|
|
25
|
+
"@config/*": ["./config/*"]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"next-env.d.ts",
|
|
30
|
+
"src/**/*.ts",
|
|
31
|
+
"src/**/*.tsx",
|
|
32
|
+
".next/types/**/*.ts",
|
|
33
|
+
"config/**/*.ts"
|
|
34
|
+
],
|
|
35
|
+
"exclude": ["node_modules"]
|
|
36
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { IOC, type IOCContainer
|
|
1
|
+
import { IOC, type IOCContainer } from '@/core/IOC';
|
|
2
2
|
import { InversifyContainer } from '@/base/cases/InversifyContainer';
|
|
3
|
-
import { IocRegisterImpl } from '@/core/
|
|
3
|
+
import { IocRegisterImpl } from '@/core/IocRegisterImpl';
|
|
4
4
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
5
5
|
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
6
6
|
|
|
@@ -35,7 +35,8 @@ describe('IOC Container Tests', () => {
|
|
|
35
35
|
aiApiToken: '',
|
|
36
36
|
aiApiTokenPrefix: 'Bearer',
|
|
37
37
|
aiApiRequireToken: true,
|
|
38
|
-
bootHref: ''
|
|
38
|
+
bootHref: '',
|
|
39
|
+
isProduction: false
|
|
39
40
|
};
|
|
40
41
|
});
|
|
41
42
|
|
|
@@ -102,12 +103,6 @@ describe('IOC Container Tests', () => {
|
|
|
102
103
|
expect(registerImpl).toBeInstanceOf(IocRegisterImpl);
|
|
103
104
|
});
|
|
104
105
|
|
|
105
|
-
it('should return register list', () => {
|
|
106
|
-
const registerList = registerImpl.getRegisterList();
|
|
107
|
-
expect(Array.isArray(registerList)).toBe(true);
|
|
108
|
-
expect(registerList.length).toBeGreaterThan(0);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
106
|
it('should register services without throwing', () => {
|
|
112
107
|
const mockManager = {
|
|
113
108
|
get: vi.fn(),
|
|
@@ -125,34 +120,14 @@ describe('IOC Container Tests', () => {
|
|
|
125
120
|
describe('IOCIdentifierMap Type Safety', () => {
|
|
126
121
|
it('should have correct type mapping for JSON', () => {
|
|
127
122
|
// This test verifies that the type mapping is correct
|
|
128
|
-
const identifierMap
|
|
123
|
+
const identifierMap = {};
|
|
129
124
|
|
|
130
125
|
// TypeScript should enforce that these keys exist
|
|
131
|
-
expect(IOCIdentifier.
|
|
126
|
+
expect(IOCIdentifier.JSONSerializer in identifierMap).toBeDefined();
|
|
132
127
|
expect(IOCIdentifier.LocalStorage in identifierMap).toBeDefined();
|
|
133
128
|
expect(IOCIdentifier.Logger in identifierMap).toBeDefined();
|
|
134
129
|
expect(IOCIdentifier.AppConfig in identifierMap).toBeDefined();
|
|
135
130
|
});
|
|
136
|
-
|
|
137
|
-
it('should have all required identifiers', () => {
|
|
138
|
-
const requiredIdentifiers = [
|
|
139
|
-
'JSON',
|
|
140
|
-
'LocalStorage',
|
|
141
|
-
'LocalStorageEncrypt',
|
|
142
|
-
'CookieStorage',
|
|
143
|
-
'Logger',
|
|
144
|
-
'FeApiToken',
|
|
145
|
-
'FeApiCommonPlugin',
|
|
146
|
-
'AppConfig',
|
|
147
|
-
'ApiMockPlugin',
|
|
148
|
-
'ApiCatchPlugin',
|
|
149
|
-
'DialogHandler'
|
|
150
|
-
];
|
|
151
|
-
|
|
152
|
-
requiredIdentifiers.forEach((identifier) => {
|
|
153
|
-
expect(IOCIdentifier).toHaveProperty(identifier);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
131
|
});
|
|
157
132
|
|
|
158
133
|
describe('Service Registration Integration', () => {
|
|
@@ -2,7 +2,7 @@ import { InversifyContainer } from '@/base/cases/InversifyContainer';
|
|
|
2
2
|
import { BootstrapApp } from '@/core/bootstraps/BootstrapApp';
|
|
3
3
|
import type { BootstrapAppArgs } from '@/core/bootstraps/BootstrapApp';
|
|
4
4
|
import { createIOCFunction } from '@qlover/corekit-bridge';
|
|
5
|
-
import type { IOCIdentifierMap } from '
|
|
5
|
+
import type { IOCIdentifierMap } from '@config/IOCIdentifier';
|
|
6
6
|
import { name, version } from '../../../../package.json';
|
|
7
7
|
import { browserGlobalsName } from '@config/common';
|
|
8
8
|
|
|
@@ -1,13 +1,85 @@
|
|
|
1
|
+
import type * as CorekitBridge from '@qlover/corekit-bridge';
|
|
2
|
+
import type * as FeCorekit from '@qlover/fe-corekit';
|
|
3
|
+
import type * as Logger from '@qlover/logger';
|
|
4
|
+
import type { DialogHandler } from '@/base/cases/DialogHandler';
|
|
5
|
+
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
6
|
+
import type { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
|
|
7
|
+
import type { I18nService } from '@/base/services/I18nService';
|
|
8
|
+
import type { ProcesserExecutor } from '@/base/services/ProcesserExecutor';
|
|
9
|
+
import type { RouteService } from '@/base/services/RouteService';
|
|
10
|
+
import type { UserService } from '@/base/services/UserService';
|
|
11
|
+
import type { I18nKeyErrorPlugin } from '@/base/cases/I18nKeyErrorPlugin';
|
|
12
|
+
import type { ExecutorPageBridgeInterface } from '@/base/port/ExecutorPageBridgeInterface';
|
|
13
|
+
import type { JSONStoragePageBridgeInterface } from '@/base/port/JSONStoragePageBridgeInterface';
|
|
14
|
+
import type { RequestPageBridgeInterface } from '@/base/port/RequestPageBridgeInterface';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* IOC identifier
|
|
18
|
+
*/
|
|
1
19
|
export const IOCIdentifier = Object.freeze({
|
|
2
|
-
|
|
20
|
+
JSONSerializer: 'JSONSerializer',
|
|
21
|
+
Logger: 'Logger',
|
|
22
|
+
AppConfig: 'AppConfig',
|
|
23
|
+
DialogHandler: 'DialogHandler',
|
|
3
24
|
LocalStorage: 'LocalStorage',
|
|
4
25
|
LocalStorageEncrypt: 'LocalStorageEncrypt',
|
|
5
26
|
CookieStorage: 'CookieStorage',
|
|
6
|
-
|
|
7
|
-
|
|
27
|
+
EnvConfigInterface: 'EnvConfigInterface',
|
|
28
|
+
UIDialogInterface: 'UIDialogInterface',
|
|
29
|
+
AntdStaticApiInterface: 'AntdStaticApiInterface',
|
|
30
|
+
RequestCatcherInterface: 'RequestCatcherInterface',
|
|
31
|
+
I18nServiceInterface: 'I18nServiceInterface',
|
|
32
|
+
ProcesserExecutorInterface: 'ProcesserExecutorInterface',
|
|
33
|
+
RouteServiceInterface: 'RouteServiceInterface',
|
|
34
|
+
UserServiceInterface: 'UserServiceInterface',
|
|
35
|
+
I18nKeyErrorPlugin: 'I18nKeyErrorPlugin',
|
|
8
36
|
FeApiCommonPlugin: 'FeApiCommonPlugin',
|
|
9
|
-
AppConfig: 'AppConfig',
|
|
10
37
|
ApiMockPlugin: 'ApiMockPlugin',
|
|
11
38
|
ApiCatchPlugin: 'ApiCatchPlugin',
|
|
12
|
-
|
|
39
|
+
ThemeService: 'ThemeService',
|
|
40
|
+
ExecutorPageBridgeInterface: 'ExecutorPageBridgeInterface',
|
|
41
|
+
JSONStoragePageInterface: 'JSONStoragePageInterface',
|
|
42
|
+
RequestPageBridgeInterface: 'RequestPageBridgeInterface'
|
|
13
43
|
});
|
|
44
|
+
|
|
45
|
+
export const I = IOCIdentifier;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* IOC identifier map
|
|
49
|
+
*
|
|
50
|
+
* Define the implementation class corresponding to the string identifier
|
|
51
|
+
*
|
|
52
|
+
* - key: interface alias or name
|
|
53
|
+
* - value: implementation class
|
|
54
|
+
*/
|
|
55
|
+
export interface IOCIdentifierMap {
|
|
56
|
+
[IOCIdentifier.JSONSerializer]: FeCorekit.JSONSerializer;
|
|
57
|
+
[IOCIdentifier.Logger]: Logger.Logger;
|
|
58
|
+
[IOCIdentifier.AppConfig]: AppConfig;
|
|
59
|
+
[IOCIdentifier.DialogHandler]: DialogHandler;
|
|
60
|
+
[IOCIdentifier.LocalStorage]: FeCorekit.SyncStorage<
|
|
61
|
+
unknown,
|
|
62
|
+
FeCorekit.ObjectStorageOptions
|
|
63
|
+
>;
|
|
64
|
+
[IOCIdentifier.LocalStorageEncrypt]: FeCorekit.SyncStorage<
|
|
65
|
+
unknown,
|
|
66
|
+
FeCorekit.ObjectStorageOptions
|
|
67
|
+
>;
|
|
68
|
+
[IOCIdentifier.CookieStorage]: CorekitBridge.CookieStorage;
|
|
69
|
+
[IOCIdentifier.EnvConfigInterface]: AppConfig;
|
|
70
|
+
[IOCIdentifier.UIDialogInterface]: DialogHandler;
|
|
71
|
+
[IOCIdentifier.AntdStaticApiInterface]: DialogHandler;
|
|
72
|
+
[IOCIdentifier.RequestCatcherInterface]: RequestStatusCatcher;
|
|
73
|
+
[IOCIdentifier.I18nServiceInterface]: I18nService;
|
|
74
|
+
[IOCIdentifier.ProcesserExecutorInterface]: ProcesserExecutor;
|
|
75
|
+
[IOCIdentifier.RouteServiceInterface]: RouteService;
|
|
76
|
+
[IOCIdentifier.UserServiceInterface]: UserService;
|
|
77
|
+
[IOCIdentifier.I18nKeyErrorPlugin]: I18nKeyErrorPlugin;
|
|
78
|
+
[IOCIdentifier.FeApiCommonPlugin]: CorekitBridge.RequestCommonPlugin;
|
|
79
|
+
[IOCIdentifier.ApiMockPlugin]: CorekitBridge.ApiMockPlugin;
|
|
80
|
+
[IOCIdentifier.ApiCatchPlugin]: CorekitBridge.ApiCatchPlugin;
|
|
81
|
+
[IOCIdentifier.ThemeService]: CorekitBridge.ThemeService;
|
|
82
|
+
[IOCIdentifier.ExecutorPageBridgeInterface]: ExecutorPageBridgeInterface;
|
|
83
|
+
[IOCIdentifier.JSONStoragePageInterface]: JSONStoragePageBridgeInterface;
|
|
84
|
+
[IOCIdentifier.RequestPageBridgeInterface]: RequestPageBridgeInterface;
|
|
85
|
+
}
|
|
@@ -64,8 +64,8 @@ export const baseRoutes: RouteConfigValue[] = [
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
|
-
path: '
|
|
68
|
-
element: 'base/
|
|
67
|
+
path: 'identifier',
|
|
68
|
+
element: 'base/IdentifierPage',
|
|
69
69
|
meta: {
|
|
70
70
|
title: identifier.PAGE_ERROR_IDENTIFIER_TITLE,
|
|
71
71
|
description: identifier.PAGE_ERROR_IDENTIFIER_DESCRIPTION,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"version": "0.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": true,
|
|
7
|
-
"homepage": "",
|
|
7
|
+
"homepage": "https://github.com/qlover/fe-base/tree/master/packages/create-app/templates/react-app#readme",
|
|
8
8
|
"author": "qlover",
|
|
9
9
|
"license": "ISC",
|
|
10
10
|
"repository": {
|
|
@@ -26,9 +26,6 @@
|
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
|
-
"bin": {
|
|
30
|
-
"fe-release": "./bin/release.js"
|
|
31
|
-
},
|
|
32
29
|
"scripts": {
|
|
33
30
|
"dev": "vite --mode localhost",
|
|
34
31
|
"dev:staging": "vite --mode staging",
|
|
@@ -44,7 +41,7 @@
|
|
|
44
41
|
"@qlover/corekit-bridge": "latest",
|
|
45
42
|
"@qlover/fe-corekit": "latest",
|
|
46
43
|
"@qlover/logger": "^0.1.1",
|
|
47
|
-
"@qlover/slice-store-react": "^1.
|
|
44
|
+
"@qlover/slice-store-react": "^1.4.1",
|
|
48
45
|
"@tailwindcss/postcss": "^4.1.8",
|
|
49
46
|
"@tailwindcss/vite": "^4.1.8",
|
|
50
47
|
"antd": "^5.25.3",
|
|
@@ -64,9 +61,9 @@
|
|
|
64
61
|
"devDependencies": {
|
|
65
62
|
"@brain-toolkit/ts2locales": "^0.2.3",
|
|
66
63
|
"@qlover/env-loader": "latest",
|
|
67
|
-
"@qlover/eslint-plugin": "
|
|
64
|
+
"@qlover/eslint-plugin": "latest",
|
|
68
65
|
"@qlover/fe-scripts": "latest",
|
|
69
|
-
"@qlover/fe-standard": "
|
|
66
|
+
"@qlover/fe-standard": "latest",
|
|
70
67
|
"@testing-library/react": "^16.3.0",
|
|
71
68
|
"@types/lodash": "^4.17.13",
|
|
72
69
|
"@types/react": "^18.3.11",
|
|
@@ -3,11 +3,12 @@ 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 { RouteService } from './base/services/RouteService';
|
|
7
6
|
import { RouterLoader, type ComponentValue } from '@/base/cases/RouterLoader';
|
|
8
7
|
import { AntdThemeProvider } from '@brain-toolkit/antd-theme-override/react';
|
|
9
8
|
import { routerPrefix } from '@config/common';
|
|
10
9
|
import { useStore } from './uikit/hooks/useStore';
|
|
10
|
+
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
11
|
+
import { logger } from './core/globals';
|
|
11
12
|
|
|
12
13
|
function getAllPages() {
|
|
13
14
|
const modules = import.meta.glob('./pages/**/*.tsx');
|
|
@@ -25,11 +26,15 @@ function getAllPages() {
|
|
|
25
26
|
|
|
26
27
|
const routerLoader = new RouterLoader({
|
|
27
28
|
componentMaps: getAllPages(),
|
|
28
|
-
render: RouterRenderComponent
|
|
29
|
+
render: RouterRenderComponent,
|
|
30
|
+
logger: logger
|
|
29
31
|
});
|
|
30
32
|
|
|
31
33
|
function App() {
|
|
32
|
-
const routes = useStore(
|
|
34
|
+
const routes = useStore(
|
|
35
|
+
IOC(IOCIdentifier.RouteServiceInterface),
|
|
36
|
+
(state) => state.routes
|
|
37
|
+
);
|
|
33
38
|
|
|
34
39
|
const routerBase = useMemo(() => {
|
|
35
40
|
const routeList = routes.map((route) => routerLoader.toRoute(route));
|
|
@@ -41,7 +46,7 @@ function App() {
|
|
|
41
46
|
|
|
42
47
|
return (
|
|
43
48
|
<AntdThemeProvider
|
|
44
|
-
staticApi={IOC('
|
|
49
|
+
staticApi={IOC('AntdStaticApiInterface')}
|
|
45
50
|
theme={{
|
|
46
51
|
cssVar: {
|
|
47
52
|
key: 'fe-theme',
|
|
@@ -37,7 +37,7 @@ export class UserApi
|
|
|
37
37
|
protected store: UserAuthStoreInterface<UserInfo> | null = null;
|
|
38
38
|
|
|
39
39
|
constructor(
|
|
40
|
-
@inject(FetchAbortPlugin)
|
|
40
|
+
@inject(FetchAbortPlugin) protected abortPlugin: FetchAbortPlugin,
|
|
41
41
|
@inject(UserApiAdapter) adapter: RequestAdapterFetch
|
|
42
42
|
) {
|
|
43
43
|
super(adapter);
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
type ApiCatchPluginResponse
|
|
17
17
|
} from '@qlover/corekit-bridge';
|
|
18
18
|
import { UserApi } from './UserApi';
|
|
19
|
+
import { RequestLanguages } from '../../cases/RequestLanguages';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* UserApiConfig
|
|
@@ -68,6 +69,9 @@ export class UserApiBootstarp implements BootstrapExecutorPlugin {
|
|
|
68
69
|
.get<UserApi>(UserApi)
|
|
69
70
|
.usePlugin(new FetchURLPlugin())
|
|
70
71
|
.usePlugin(IOC.get(IOCIdentifier.FeApiCommonPlugin))
|
|
72
|
+
.usePlugin(
|
|
73
|
+
new RequestLanguages(ioc.get(IOCIdentifier.I18nServiceInterface))
|
|
74
|
+
)
|
|
71
75
|
.usePlugin(IOC.get(IOCIdentifier.ApiMockPlugin))
|
|
72
76
|
.usePlugin(IOC.get(RequestLogger))
|
|
73
77
|
.usePlugin(IOC.get(FetchAbortPlugin))
|
|
@@ -4,11 +4,14 @@ import type {
|
|
|
4
4
|
ModalApi,
|
|
5
5
|
NotificationApi
|
|
6
6
|
} from '@brain-toolkit/antd-theme-override/react';
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
import { UIDialogInterface, NotificationOptions } from '@qlover/corekit-bridge';
|
|
8
|
+
import { ModalFuncProps } from 'antd';
|
|
9
|
+
|
|
10
|
+
export interface DialogHandlerOptions
|
|
11
|
+
extends NotificationOptions,
|
|
12
|
+
ModalFuncProps {
|
|
13
|
+
content: string;
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Dialog Handler Implementation
|
|
@@ -32,9 +35,9 @@ import type {
|
|
|
32
35
|
* });
|
|
33
36
|
*/
|
|
34
37
|
export class DialogHandler
|
|
35
|
-
implements
|
|
38
|
+
implements UIDialogInterface<DialogHandlerOptions>, AntdStaticApiInterface
|
|
36
39
|
{
|
|
37
|
-
|
|
40
|
+
protected antds: {
|
|
38
41
|
message?: MessageApi;
|
|
39
42
|
modal?: ModalApi;
|
|
40
43
|
notification?: NotificationApi;
|
|
@@ -55,32 +58,32 @@ export class DialogHandler
|
|
|
55
58
|
/**
|
|
56
59
|
* Formats error message from various error types
|
|
57
60
|
*/
|
|
58
|
-
|
|
61
|
+
protected formatErrorMessage(error: unknown): string {
|
|
59
62
|
if (error instanceof Error) return error.message;
|
|
60
63
|
if (typeof error === 'string') return error;
|
|
61
64
|
return 'An unknown error occurred';
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
public success(msg: string, options?:
|
|
67
|
+
public success(msg: string, options?: NotificationOptions): void {
|
|
65
68
|
this.antds.message?.success({ content: msg, ...options });
|
|
66
69
|
}
|
|
67
70
|
|
|
68
|
-
public error(msg: string, options?:
|
|
71
|
+
public error(msg: string, options?: NotificationOptions): void {
|
|
69
72
|
this.antds.message?.error({
|
|
70
73
|
content: options?.error ? this.formatErrorMessage(options.error) : msg,
|
|
71
74
|
...options
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
77
|
|
|
75
|
-
public info(msg: string, options?:
|
|
78
|
+
public info(msg: string, options?: NotificationOptions): void {
|
|
76
79
|
this.antds.message?.info({ content: msg, ...options });
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
public warn(msg: string, options?:
|
|
82
|
+
public warn(msg: string, options?: NotificationOptions): void {
|
|
80
83
|
this.antds.message?.warning({ content: msg, ...options });
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
public confirm(options:
|
|
86
|
+
public confirm(options: DialogHandlerOptions): void {
|
|
84
87
|
this.antds.modal?.confirm(options);
|
|
85
88
|
}
|
|
86
89
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ExecutorContext, ExecutorPlugin } from '@qlover/fe-corekit';
|
|
2
2
|
import type { LoggerInterface } from '@qlover/logger';
|
|
3
3
|
import { inject, injectable } from 'inversify';
|
|
4
|
-
import { I18nService } from '../services/I18nService';
|
|
5
4
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
5
|
+
import type { I18nServiceInterface } from '../port/I18nServiceInterface';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* When throw error, it will be converted to i18n key
|
|
@@ -14,8 +14,9 @@ export class I18nKeyErrorPlugin implements ExecutorPlugin {
|
|
|
14
14
|
readonly pluginName = 'I18nKeyErrorPlugin';
|
|
15
15
|
|
|
16
16
|
constructor(
|
|
17
|
-
@inject(IOCIdentifier.Logger)
|
|
18
|
-
@inject(
|
|
17
|
+
@inject(IOCIdentifier.Logger) protected logger: LoggerInterface,
|
|
18
|
+
@inject(IOCIdentifier.I18nServiceInterface)
|
|
19
|
+
protected i18nService: I18nServiceInterface
|
|
19
20
|
) {}
|
|
20
21
|
|
|
21
22
|
onError(context: ExecutorContext<unknown>): Error | void {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IOCIdentifierMap } from '
|
|
1
|
+
import { IOCIdentifierMap } from '@config/IOCIdentifier';
|
|
2
2
|
import {
|
|
3
3
|
IOCContainerInterface,
|
|
4
4
|
ServiceIdentifier
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import { Container } from 'inversify';
|
|
7
7
|
|
|
8
8
|
export class InversifyContainer implements IOCContainerInterface {
|
|
9
|
-
|
|
9
|
+
protected container: Container;
|
|
10
10
|
|
|
11
11
|
constructor() {
|
|
12
12
|
this.container = new Container({
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { I18nServiceInterface } from '@/base/port/I18nServiceInterface';
|
|
2
|
+
import {
|
|
3
|
+
ExecutorContext,
|
|
4
|
+
ExecutorPlugin,
|
|
5
|
+
RequestAdapterConfig
|
|
6
|
+
} from '@qlover/fe-corekit';
|
|
7
|
+
|
|
8
|
+
export class RequestLanguages implements ExecutorPlugin {
|
|
9
|
+
readonly pluginName = 'RequestLanguages';
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
protected i18nService: I18nServiceInterface,
|
|
13
|
+
protected headerName = 'accept-language'
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
buildAcceptLanguage(langs: string[]): string {
|
|
17
|
+
return langs
|
|
18
|
+
.map((lang, index) => {
|
|
19
|
+
const q = Math.max(1 - index * 0.1, 0.1).toFixed(1);
|
|
20
|
+
return index === 0 ? lang : `${lang};q=${q}`;
|
|
21
|
+
})
|
|
22
|
+
.join(',');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onBefore(context: ExecutorContext<RequestAdapterConfig>): void {
|
|
26
|
+
const currentLanguage = this.i18nService.getCurrentLanguage();
|
|
27
|
+
const languages = this.i18nService.getSupportedLanguages();
|
|
28
|
+
|
|
29
|
+
if (!context.parameters.headers) {
|
|
30
|
+
context.parameters.headers = {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const languageValue = this.buildAcceptLanguage(
|
|
34
|
+
Array.from(new Set([currentLanguage, ...languages]))
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
context.parameters.headers[this.headerName] = languageValue;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AsyncStateInterface } from '@/base/port/AsyncStateInterface';
|
|
2
|
+
|
|
3
|
+
export class RequestState<T> implements AsyncStateInterface<T> {
|
|
4
|
+
startTime: number;
|
|
5
|
+
endTime: number;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
public loading: boolean = false,
|
|
9
|
+
public result: T | null = null,
|
|
10
|
+
public error: unknown | null = null
|
|
11
|
+
) {
|
|
12
|
+
this.startTime = Date.now();
|
|
13
|
+
this.endTime = 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
end(): this {
|
|
17
|
+
this.endTime = Date.now();
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -9,9 +9,9 @@ export class RequestStatusCatcher
|
|
|
9
9
|
implements RequestCatcherInterface<RequestAdapterResponse>
|
|
10
10
|
{
|
|
11
11
|
constructor(
|
|
12
|
-
@inject(IOCIdentifier.Logger)
|
|
13
|
-
private readonly logger: LoggerInterface
|
|
12
|
+
@inject(IOCIdentifier.Logger) protected logger: LoggerInterface
|
|
14
13
|
) {}
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* default handler
|
|
17
17
|
* @override
|