generator-kodly-react-app 1.0.5 → 1.0.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/generators/app/index.js +1 -0
- package/generators/app/templates/.env.example +1 -1
- package/generators/app/templates/README.md +10 -5
- package/generators/app/templates/package.json +10 -5
- package/generators/app/templates/src/lib/api/client.ts +3 -3
- package/generators/app/templates/src/lib/utils/error-handler.ts +7 -2
- package/generators/app/templates/src/modules/auth/auth-context.tsx +6 -8
- package/generators/app/templates/src/modules/auth/auth-types.ts +24 -0
- package/generators/app/templates/src/modules/auth/use-auth-hook.ts +12 -11
- package/generators/app/templates/src/routes/__root.tsx +3 -3
- package/generators/constants.js +8 -8
- package/package.json +1 -1
package/generators/app/index.js
CHANGED
|
@@ -60,6 +60,7 @@ export default class ReactAppGenerator extends BaseGenerator {
|
|
|
60
60
|
|
|
61
61
|
_writeAuthFiles() {
|
|
62
62
|
const authFiles = [
|
|
63
|
+
'src/modules/auth/auth-types.ts',
|
|
63
64
|
'src/modules/auth/auth-context.tsx',
|
|
64
65
|
'src/modules/auth/use-auth-hook.ts',
|
|
65
66
|
'src/modules/auth/login/login-page.tsx',
|
|
@@ -5,11 +5,13 @@ A React application built with Vite, TanStack Router, and TypeScript.
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
7
7
|
1. Install dependencies:
|
|
8
|
+
|
|
8
9
|
```bash
|
|
9
10
|
npm install
|
|
10
11
|
```
|
|
11
12
|
|
|
12
13
|
2. Create a `.env` file from `.env.example`:
|
|
14
|
+
|
|
13
15
|
```bash
|
|
14
16
|
cp .env.example .env
|
|
15
17
|
```
|
|
@@ -17,13 +19,14 @@ cp .env.example .env
|
|
|
17
19
|
3. Update the `.env` file with your API base URL.
|
|
18
20
|
|
|
19
21
|
4. Start the development server:
|
|
22
|
+
|
|
20
23
|
```bash
|
|
21
24
|
npm run dev
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
## Environment Variables
|
|
25
28
|
|
|
26
|
-
- `VITE_API_BASE_URL` - Base URL for your API backend (default: `http://localhost:8181`)
|
|
29
|
+
- `VITE_API_BASE_URL` - Base URL for your API backend (default: `http://localhost:8181/api/v1`)
|
|
27
30
|
- `PORT` - Port for the development server (default: `3000`)
|
|
28
31
|
|
|
29
32
|
### Setting Environment Variables
|
|
@@ -31,20 +34,23 @@ npm run dev
|
|
|
31
34
|
You can set environment variables in several ways:
|
|
32
35
|
|
|
33
36
|
**Option 1: Using a `.env` file (recommended)**
|
|
37
|
+
|
|
34
38
|
```bash
|
|
35
39
|
# Create .env file
|
|
36
|
-
echo "VITE_API_BASE_URL=http://localhost:8080/api" > .env
|
|
40
|
+
echo "VITE_API_BASE_URL=http://localhost:8080/api/v1" > .env
|
|
37
41
|
echo "PORT=3001" >> .env
|
|
38
42
|
```
|
|
39
43
|
|
|
40
44
|
**Option 2: Using environment variables when running commands**
|
|
45
|
+
|
|
41
46
|
```bash
|
|
42
|
-
VITE_API_BASE_URL=http://localhost:8080/api PORT=3001 npm run dev
|
|
47
|
+
VITE_API_BASE_URL=http://localhost:8080/api/v1 PORT=3001 npm run dev
|
|
43
48
|
```
|
|
44
49
|
|
|
45
50
|
**Option 3: Using cross-env (works on all platforms)**
|
|
51
|
+
|
|
46
52
|
```bash
|
|
47
|
-
cross-env VITE_API_BASE_URL=http://localhost:8080/api PORT=3001 npm run dev
|
|
53
|
+
cross-env VITE_API_BASE_URL=http://localhost:8080/api/v1 PORT=3001 npm run dev
|
|
48
54
|
```
|
|
49
55
|
|
|
50
56
|
## Project Structure
|
|
@@ -54,4 +60,3 @@ cross-env VITE_API_BASE_URL=http://localhost:8080/api PORT=3001 npm run dev
|
|
|
54
60
|
- `src/components/` - Reusable UI components
|
|
55
61
|
- `src/lib/` - Utility functions and configurations
|
|
56
62
|
- `src/locales/` - i18n translation files
|
|
57
|
-
|
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"version": "0.0.1",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
7
|
+
"generate-routes": "tsr generate",
|
|
8
|
+
"watch-routes": "tsr watch",
|
|
9
|
+
"vite:dev": "vite",
|
|
10
|
+
"dev": "npm-run-all --parallel watch-routes vite:dev",
|
|
11
|
+
"start": "dev",
|
|
12
|
+
"build": "npm run generate-routes && vite build && tsc",
|
|
10
13
|
"serve": "vite preview"
|
|
11
14
|
},
|
|
12
15
|
"dependencies": {
|
|
@@ -20,7 +23,7 @@
|
|
|
20
23
|
"dotenv": "<%= DOTENV_VERSION %>",
|
|
21
24
|
"i18next": "<%= I18NEXT_VERSION %>",
|
|
22
25
|
"jotai": "<%= JOTAI_VERSION %>",
|
|
23
|
-
"lucide-react": "^0.
|
|
26
|
+
"lucide-react": "^0.555.0",
|
|
24
27
|
"react": "<%= REACT_VERSION %>",
|
|
25
28
|
"react-dom": "<%= REACT_DOM_VERSION %>",
|
|
26
29
|
"react-i18next": "<%= REACT_I18NEXT_VERSION %>",
|
|
@@ -30,11 +33,13 @@
|
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"@tailwindcss/postcss": "<%= TAILWIND_VERSION %>",
|
|
32
35
|
"@tailwindcss/vite": "<%= TAILWIND_VERSION %>",
|
|
36
|
+
"@tanstack/router-cli": "^1.139.14",
|
|
33
37
|
"@types/node": "^24.10.1",
|
|
34
|
-
"@types/react": "^19.2.
|
|
38
|
+
"@types/react": "^19.2.7",
|
|
35
39
|
"@types/react-dom": "^19.2.3",
|
|
36
40
|
"@vitejs/plugin-react": "^5.1.1",
|
|
37
41
|
"cross-env": "<%= CROSS_ENV_VERSION %>",
|
|
42
|
+
"npm-run-all": "^4.1.5",
|
|
38
43
|
"tailwindcss": "<%= TAILWIND_VERSION %>",
|
|
39
44
|
"typescript": "<%= TYPESCRIPT_VERSION %>",
|
|
40
45
|
"vite": "<%= VITE_VERSION %>"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
1
|
+
import axios, { AxiosResponse } from 'axios';
|
|
2
2
|
import { handleBackendError } from '../utils/error-handler';
|
|
3
3
|
|
|
4
|
-
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8181';
|
|
4
|
+
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8181/api/v1';
|
|
5
5
|
|
|
6
6
|
export const client = axios.create({
|
|
7
7
|
baseURL: apiBaseUrl,
|
|
@@ -12,7 +12,7 @@ export const client = axios.create({
|
|
|
12
12
|
|
|
13
13
|
// Add response interceptor to handle non-2xx responses and network errors
|
|
14
14
|
client.interceptors.response.use(
|
|
15
|
-
(response:
|
|
15
|
+
(response: AxiosResponse) => response,
|
|
16
16
|
(error: unknown) => {
|
|
17
17
|
// Handle all errors: non-2xx responses and network errors
|
|
18
18
|
if (error && typeof error === 'object' && 'response' in error) {
|
|
@@ -4,7 +4,7 @@ import { AxiosError } from 'axios';
|
|
|
4
4
|
interface BackendErrorResponse {
|
|
5
5
|
message?: string;
|
|
6
6
|
status?: boolean;
|
|
7
|
-
data?:
|
|
7
|
+
data?: unknown;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -41,7 +41,12 @@ export const handleBackendError = (error: unknown): void => {
|
|
|
41
41
|
// If the response doesn't match the expected format,
|
|
42
42
|
// try to extract a message from the response data
|
|
43
43
|
if (errorData && typeof errorData === 'object') {
|
|
44
|
-
const
|
|
44
|
+
const errorObj = errorData as Record<string, unknown>;
|
|
45
|
+
const message =
|
|
46
|
+
(typeof errorObj.message === 'string' ? errorObj.message : null) ||
|
|
47
|
+
(typeof errorObj.error === 'string' ? errorObj.error : null) ||
|
|
48
|
+
response.statusText ||
|
|
49
|
+
'An error occurred';
|
|
45
50
|
toast.error(message);
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { createContext } from
|
|
2
|
-
import { currentUserDetailsAtom } from
|
|
3
|
-
import {
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
import { currentUserDetailsAtom } from './use-auth-hook';
|
|
3
|
+
import { AuthData } from './auth-types';
|
|
4
|
+
import { useAtomValue } from 'jotai';
|
|
4
5
|
|
|
5
|
-
export const AuthContext = createContext<
|
|
6
|
+
export const AuthContext = createContext<AuthData | undefined>(undefined);
|
|
6
7
|
|
|
7
8
|
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
|
8
9
|
const authData = useAtomValue(currentUserDetailsAtom);
|
|
9
|
-
return
|
|
10
|
-
<AuthContext.Provider value={authData}>{children}</AuthContext.Provider>
|
|
11
|
-
);
|
|
10
|
+
return <AuthContext.Provider value={authData}>{children}</AuthContext.Provider>;
|
|
12
11
|
};
|
|
13
|
-
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface UserData {
|
|
2
|
+
id: string;
|
|
3
|
+
slug: string;
|
|
4
|
+
email: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ModulePermission {
|
|
8
|
+
module: string;
|
|
9
|
+
permissions: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AuthData {
|
|
13
|
+
token: string;
|
|
14
|
+
data: UserData;
|
|
15
|
+
roleName: string;
|
|
16
|
+
modulePermissions: ModulePermission[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AuthResponse {
|
|
20
|
+
message: string | null;
|
|
21
|
+
status: boolean;
|
|
22
|
+
data: AuthData;
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -5,12 +5,13 @@ import { useNavigate } from '@tanstack/react-router';
|
|
|
5
5
|
import { atom, useAtomValue, useSetAtom } from 'jotai';
|
|
6
6
|
import { atomWithStorage } from 'jotai/utils';
|
|
7
7
|
import { client } from '@/lib/api/client';
|
|
8
|
+
import { AuthData, AuthResponse } from './auth-types';
|
|
8
9
|
|
|
9
10
|
export const authTokenAtom = atomWithStorage<string>('authTokenAtom', '', undefined, {
|
|
10
11
|
getOnInit: true,
|
|
11
12
|
});
|
|
12
13
|
|
|
13
|
-
export const currentUserDetailsAtom = atom<
|
|
14
|
+
export const currentUserDetailsAtom = atom<AuthData | undefined>();
|
|
14
15
|
|
|
15
16
|
export const setTokenInAxios = (token?: string | null) => {
|
|
16
17
|
if (token) {
|
|
@@ -29,18 +30,18 @@ export const useLogin = () => {
|
|
|
29
30
|
const setCurrentUser = useSetAtom(currentUserDetailsAtom);
|
|
30
31
|
const navigate = useNavigate();
|
|
31
32
|
return useMutation({
|
|
32
|
-
mutationFn: async (data: { email: string; password: string }) => {
|
|
33
|
-
const response = await client.post('/auth/user/login', data);
|
|
33
|
+
mutationFn: async (data: { email: string; password: string }): Promise<AuthResponse> => {
|
|
34
|
+
const response = await client.post<AuthResponse>('/auth/user/login', data);
|
|
34
35
|
return response.data;
|
|
35
36
|
},
|
|
36
|
-
onSuccess: (authData) => {
|
|
37
|
-
const token = authData?.token || '';
|
|
37
|
+
onSuccess: (authData: AuthResponse) => {
|
|
38
|
+
const token = authData?.data?.token || '';
|
|
38
39
|
setAuthToken(token);
|
|
39
|
-
setCurrentUser(authData);
|
|
40
|
+
setCurrentUser(authData.data);
|
|
40
41
|
setTokenInAxios(token);
|
|
41
42
|
navigate({ to: AppRoute.to });
|
|
42
43
|
},
|
|
43
|
-
onError: (err:
|
|
44
|
+
onError: (err: unknown) => {
|
|
44
45
|
// Error is already handled by axios interceptor
|
|
45
46
|
console.error('Login failed:', err);
|
|
46
47
|
},
|
|
@@ -53,13 +54,13 @@ export const useValidateToken = () => {
|
|
|
53
54
|
const authToken = useAtomValue(authTokenAtom);
|
|
54
55
|
setTokenInAxios(authToken);
|
|
55
56
|
return useMutation({
|
|
56
|
-
mutationFn: async () => {
|
|
57
|
-
const response = await client.post('/auth/user/validate');
|
|
57
|
+
mutationFn: async (): Promise<AuthResponse> => {
|
|
58
|
+
const response = await client.post<AuthResponse>('/auth/user/validate-token');
|
|
58
59
|
return response.data;
|
|
59
60
|
},
|
|
60
61
|
retry: false,
|
|
61
|
-
onSuccess: (data) => {
|
|
62
|
-
setCurrentUser(data);
|
|
62
|
+
onSuccess: (data: AuthResponse) => {
|
|
63
|
+
setCurrentUser(data.data);
|
|
63
64
|
},
|
|
64
65
|
onError: () => {
|
|
65
66
|
setCurrentUser(undefined);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Outlet, createRootRouteWithContext } from
|
|
1
|
+
import { Outlet, createRootRouteWithContext } from '@tanstack/react-router';
|
|
2
|
+
import { AuthData } from '@/modules/auth/auth-types';
|
|
2
3
|
|
|
3
4
|
interface RouterContext {
|
|
4
5
|
token: string;
|
|
5
|
-
data:
|
|
6
|
+
data: AuthData;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export const Route = createRootRouteWithContext<RouterContext>()({
|
|
@@ -12,4 +13,3 @@ export const Route = createRootRouteWithContext<RouterContext>()({
|
|
|
12
13
|
function App() {
|
|
13
14
|
return <Outlet />;
|
|
14
15
|
}
|
|
15
|
-
|
package/generators/constants.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
const constants = {
|
|
2
|
-
REACT_VERSION: '^19.2.
|
|
3
|
-
REACT_DOM_VERSION: '^19.2.
|
|
4
|
-
VITE_VERSION: '^7.2.
|
|
2
|
+
REACT_VERSION: '^19.2.1',
|
|
3
|
+
REACT_DOM_VERSION: '^19.2.1',
|
|
4
|
+
VITE_VERSION: '^7.2.6',
|
|
5
5
|
TYPESCRIPT_VERSION: '^5.9.3',
|
|
6
|
-
TANSTACK_ROUTER_VERSION: '^1.139.
|
|
7
|
-
TANSTACK_ROUTER_PLUGIN_VERSION: '^1.139.
|
|
8
|
-
TANSTACK_REACT_QUERY_VERSION: '^5.90.
|
|
9
|
-
I18NEXT_VERSION: '^25.
|
|
6
|
+
TANSTACK_ROUTER_VERSION: '^1.139.14',
|
|
7
|
+
TANSTACK_ROUTER_PLUGIN_VERSION: '^1.139.14',
|
|
8
|
+
TANSTACK_REACT_QUERY_VERSION: '^5.90.12',
|
|
9
|
+
I18NEXT_VERSION: '^25.7.1',
|
|
10
10
|
REACT_I18NEXT_VERSION: '^16.3.5',
|
|
11
11
|
AXIOS_VERSION: '^1.13.2',
|
|
12
|
-
JOTAI_VERSION: '^2.15.
|
|
12
|
+
JOTAI_VERSION: '^2.15.2',
|
|
13
13
|
TAILWIND_VERSION: '^4.1.17',
|
|
14
14
|
RADIX_UI_VERSION: '^1.4.3',
|
|
15
15
|
DOTENV_VERSION: '^17.2.3',
|
package/package.json
CHANGED