dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
16 changed files with 403 additions and 285 deletions
Showing only changes of commit f67c9c17bc - Show all commits

View file

@ -1,6 +1,8 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": false
}
"useTabs": true,
"semi": true,
"singleQuote": false,
"bracketSpacing": true
}

View file

@ -32,6 +32,7 @@
"mui-tel-input": "^7.0.0",
"prop-types": "^15.8.1",
"react": "^19.0.0",
"react-cookie": "^7.2.2",
"react-dom": "^19.0.0",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.54.2",
@ -68,8 +69,8 @@
},
"devDependencies": {
"@types/node": "^22.10.5",
"@types/react": "^19.0.3",
"@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2",
"typescript": "^5.7.2"
"typescript": "^5.7.3"
}
}

View file

@ -95,6 +95,9 @@ importers:
react:
specifier: ^19.0.0
version: 19.0.0
react-cookie:
specifier: ^7.2.2
version: 7.2.2(react@19.0.0)
react-dom:
specifier: ^19.0.0
version: 19.0.0(react@19.0.0)
@ -127,13 +130,13 @@ importers:
specifier: ^22.10.5
version: 22.10.5
'@types/react':
specifier: ^19.0.3
specifier: ^19.0.4
version: 19.0.4
'@types/react-dom':
specifier: ^19.0.2
version: 19.0.2(@types/react@19.0.4)
typescript:
specifier: ^5.7.2
specifier: ^5.7.3
version: 5.7.3
packages:
@ -1598,6 +1601,9 @@ packages:
'@types/graceful-fs@4.1.9':
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
'@types/hoist-non-react-statics@3.3.6':
resolution: {integrity: sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==}
'@types/html-minifier-terser@6.1.0':
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
@ -2339,6 +2345,10 @@ packages:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
cookie@0.7.2:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
cookie@1.0.2:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
@ -4915,6 +4925,11 @@ packages:
resolution: {integrity: sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==}
engines: {node: '>=14'}
react-cookie@7.2.2:
resolution: {integrity: sha512-e+hi6axHcw9VODoeVu8WyMWyoosa1pzpyjfvrLdF7CexfU+WSGZdDuRfHa4RJgTpfv3ZjdIpHE14HpYBieHFhg==}
peerDependencies:
react: '>= 16.3.0'
react-dev-utils@12.0.1:
resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==}
engines: {node: '>=14'}
@ -5742,6 +5757,9 @@ packages:
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
engines: {node: '>=8'}
universal-cookie@7.2.2:
resolution: {integrity: sha512-fMiOcS3TmzP2x5QV26pIH3mvhexLIT0HmPa3V7Q7knRfT9HG6kTwq02HZGLPw0sAOXrAmotElGRvTLCMbJsvxQ==}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
@ -7883,6 +7901,11 @@ snapshots:
dependencies:
'@types/node': 22.10.5
'@types/hoist-non-react-statics@3.3.6':
dependencies:
'@types/react': 19.0.4
hoist-non-react-statics: 3.3.2
'@types/html-minifier-terser@6.1.0': {}
'@types/http-errors@2.0.4': {}
@ -8744,6 +8767,8 @@ snapshots:
cookie@0.7.1: {}
cookie@0.7.2: {}
cookie@1.0.2: {}
core-js-compat@3.40.0:
@ -11735,6 +11760,13 @@ snapshots:
regenerator-runtime: 0.13.11
whatwg-fetch: 3.6.20
react-cookie@7.2.2(react@19.0.0):
dependencies:
'@types/hoist-non-react-statics': 3.3.6
hoist-non-react-statics: 3.3.2
react: 19.0.0
universal-cookie: 7.2.2
react-dev-utils@12.0.1(eslint@8.57.1)(typescript@5.7.3)(webpack@5.97.1):
dependencies:
'@babel/code-frame': 7.26.2
@ -12745,6 +12777,11 @@ snapshots:
dependencies:
crypto-random-string: 2.0.0
universal-cookie@7.2.2:
dependencies:
'@types/cookie': 0.6.0
cookie: 0.7.2
universalify@0.2.0: {}
universalify@2.0.1: {}

View file

@ -1,43 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
jaanvi marked this conversation as resolved Outdated

add app specific meta description.

add app specific meta description.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
<title>DigiEV - Eco-friendly Charge</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View file

@ -1,12 +1,28 @@
import { BrowserRouter as Router} from 'react-router-dom';
import AppRouter from './router';
import AppRouter from "./router";
import { useSelector } from "react-redux";
import { useMatch, useNavigate, useSearchParams } from "react-router-dom";
import { useEffect } from "react";
import { RootState } from "./redux/store";
import { withCookies, ReactCookieProps } from "react-cookie";
function App() {
return (
<Router>
<AppRouter />
</Router>
const App: React.FC<ReactCookieProps> = ({ cookies }) => {
const navigate = useNavigate();
const isPanel = useMatch("/auth/login");
const isCookiePresent = !!cookies?.get("authToken");
console.log("cookies present:", isCookiePresent);
const [searchParams] = useSearchParams();
const isAuthenticated = useSelector(
(state: RootState) => state.authReducer.isAuthenticated
);
}
export default App;
useEffect(() => {
if (isPanel && isAuthenticated) {
navigate("/panel/dashboard");
}
}, [isPanel, isAuthenticated, searchParams]);
return <AppRouter />;
};
export default withCookies(App);

View file

@ -11,6 +11,9 @@ import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded';
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
import MenuButton from '../MenuButton';
import { Avatar } from '@mui/material';
import { useDispatch } from 'react-redux';
import { logoutUser } from '../../redux/slices/authSlice';
import { useCookies } from 'react-cookie';
const MenuItem = styled(MuiMenuItem)({
margin: '2px 0',
@ -19,12 +22,20 @@ const MenuItem = styled(MuiMenuItem)({
export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const dispatch = useDispatch();
const [cookies, setCookie, removeCookie] = useCookies(['authToken']);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleLogout = () => {
dispatch(logoutUser({ removeCookie }));
console.log('click')
handleClose();
};
return (
<React.Fragment>
<MenuButton
@ -70,7 +81,7 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
<MenuItem onClick={handleClose}>Settings</MenuItem>
<Divider />
<MenuItem
onClick={handleClose}
onClick={handleLogout}
sx={{
[`& .${listItemIconClasses.root}`]: {
ml: 'auto',

View file

@ -1,39 +1,22 @@
import { intersection, uniq } from 'lodash';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { checkUserAuth } from '../redux/slices/authSlice';
const useAuth = (caps, { matchAllCaps = false }) => {
const useAuth = () => {
const dispatch = useDispatch();
const [isAuthorized, setIsAuthorized] = React.useState(false);
const { isAuthenticated, userCapabilities } = useSelector((state) => ({
const { isAuthenticated } = useSelector((state) => ({
isAuthenticated: state.authReducer.isAuthenticated,
userCapabilities: state.authReducer.userCapabilities,
}));
const requiredCaps = React.useMemo(
() => uniq(Array.isArray(caps) ? caps : [caps]),
[caps]
);
React.useEffect(() => {
const userMatchedCaps = intersection(userCapabilities, requiredCaps);
let isUserAuthorized = matchAllCaps
? userMatchedCaps?.length === requiredCaps?.length
: userMatchedCaps?.length > 0;
if (requiredCaps.length === 0) {
isUserAuthorized = true;
}
// if (isAuthenticated === null) {
if (isAuthenticated === null || false || undefined) {
if (isAuthenticated) {
dispatch(checkUserAuth());
jaanvi marked this conversation as resolved Outdated

If its authenticated then why again checking checkUserAuth.

If its authenticated then why again checking checkUserAuth.
} else {
setIsAuthorized(isAuthenticated && isUserAuthorized);
setIsAuthorized(false);
}
}, [dispatch, isAuthenticated, requiredCaps, userCapabilities]);
}, [dispatch, isAuthenticated]);
return { isAuthenticated, isAuthorized };
};

View file

@ -1,29 +1,32 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import reportWebVitals from './reportWebVitals';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store/store.ts';
import { Slide, ToastContainer } from 'react-toastify';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./redux/store";
import { Slide, ToastContainer } from "react-toastify";
import { BrowserRouter as Router } from "react-router-dom";
import { CookiesProvider } from "react-cookie";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
<ToastContainer
autoClose={2000}
hideProgressBar
theme="dark"
transition={Slide}
toastStyle={{ border: '1px solid dimgray' }}
/>
</Provider>
</React.StrictMode>
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
root.render(
<React.StrictMode>
<CookiesProvider defaultSetOptions={{ path: "/" }}>
<Provider store={store}>
<Router>
<App />
</Router>
<ToastContainer
autoClose={2000}
hideProgressBar
theme="dark"
transition={Slide}
toastStyle={{ border: "1px solid dimgray" }}
/>
</Provider>
</CookiesProvider>
</React.StrictMode>
);

View file

@ -1,16 +1,36 @@
import axios from 'axios';
import axios from "axios";
import { Cookies } from "react-cookie";
const cookies = new Cookies();
const http = axios.create({
baseURL: process.env.REACT_APP_BACKEND_URL,
baseURL: process.env.REACT_APP_BACKEND_URL,
});
console.log(process.env.REACT_APP_BACKEND_URL);
http.interceptors.request.use((config) => {
const authToken = localStorage.getItem('authToken');
if (authToken) {
config.headers.Authorization = authToken;
}
return config;
http.interceptors.request.use((config) => {
const authToken = cookies.get("authToken");
console.log(authToken);
if (authToken) {
config.headers.Authorization = authToken;
}
return config;
});
http.interceptors.response.use(
(response) => response,
(error) => {
const isCookiePresent = cookies.get("authToken");
console.log(isCookiePresent,"jkk")
if (
error.response &&
isCookiePresent &&
(error.response.status === 403 || error.response.status === 401)
) {
cookies.remove("authToken", { path: "/" });
window.location.href = "/";
}
return Promise.reject(error);
}
);
export default http;

View file

@ -0,0 +1,9 @@
import React from 'react'
function NotFoundPage() {
return (
<div>NotFoundPage</div>
)
}
export default NotFoundPage;

View file

@ -19,7 +19,7 @@ const categoryRows = [
];
export default function Vehicles() {
const [modalOpen, setModalOpen] = useState(false);
const [modalOpen, setModalOpen] = useState<boolean>(false);
const [editRow, setEditRow] = useState<any>(null);
const { reset } = useForm();

11
src/redux/reducers.ts Normal file
View file

@ -0,0 +1,11 @@
import { combineReducers } from "@reduxjs/toolkit";
import authReducer from "./slices/authSlice";
const rootReducer = combineReducers({
authReducer,
});
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;

View file

@ -1,118 +1,160 @@
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"
import axios from "axios"
import http from "../../lib/https"
import { toast } from "react-toastify"
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import axios from "axios";
import http from "../../lib/https";
import { toast } from "react-toastify";
import { Cookies } from "react-cookie";
const cookies = new Cookies();
// Define types for state
interface User {
id: string
email: string
id: string;
email: string;
}
interface AuthState {
user: User | null
isAuthenticated: boolean
isLoading: boolean
error: string | null
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
}
export const checkUserAuth = createAsyncThunk<
boolean,
void,
{ rejectValue: any }
>("application/checkUserAuth", async (_, thunkAPI) => {
try {
const isCookiePresent = cookies.get("authToken");
if (!isCookiePresent) return thunkAPI.rejectWithValue(null);
return thunkAPI.fulfillWithValue(true);
} catch (error) {
console.log(error);
return thunkAPI.rejectWithValue(error);
}
});
// Async thunk for login
export const loginUser = createAsyncThunk<
User,
{ email: string; password: string },
{ rejectValue: string }
User,
{ email: string; password: string },
{ rejectValue: string }
>("auth/login", async ({ email, password }, { rejectWithValue }) => {
try {
const response = await http.post("admin/login", { email, password })
localStorage.setItem("authToken", response.data?.data?.token) // Save token
toast.success(response.data?.message)
return response.data
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
)
}
})
try {
const response = await http.post("admin/login", { email, password });
cookies.set("authToken", response.data?.data?.token);
toast.success(response.data?.message);
return response.data;
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
});
// Async thunk for register
export const registerUser = createAsyncThunk<
User,
{ email: string; password: string },
{ rejectValue: string }
User,
{ email: string; password: string },
{ rejectValue: string }
>("auth/register", async (data, { rejectWithValue }) => {
try {
const response = await axios.post(
"https://health-digi.dmlabs.in/auth/register",
data
)
return response.data
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
)
}
})
try {
const response = await axios.post(
"https://health-digi.dmlabs.in/auth/register",
data
);
return response.data;
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
});
export const logoutUser = createAsyncThunk<
void,
{ removeCookie: any },
{ rejectValue: string }
>("auth/logout", async ({ removeCookie }, { rejectWithValue }) => {
try {
removeCookie("authToken", { path: "/auth" });
toast.success("You have been logged out successfully.");
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "Failed to log out."
);
}
});
const initialState: AuthState = {
user: null,
isAuthenticated: false,
isLoading: false,
error: null,
}
user: null,
isAuthenticated: false,
isLoading: false,
error: null,
};
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
logout: (state) => {
state.user = null
state.isAuthenticated = false
},
},
extraReducers: (builder) => {
builder
// Login
.addCase(loginUser.pending, (state) => {
state.isLoading = true
state.error = null
})
.addCase(
loginUser.fulfilled,
(state, action: PayloadAction<User>) => {
state.isLoading = false
state.isAuthenticated = true
state.user = action.payload
}
)
.addCase(
loginUser.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false
state.error = action.payload || "An error occurred"
}
)
// Register
.addCase(registerUser.pending, (state) => {
state.isLoading = true
state.error = null
})
.addCase(
registerUser.fulfilled,
(state, action: PayloadAction<User>) => {
state.isLoading = false
state.isAuthenticated = true
state.user = action.payload
}
)
.addCase(
registerUser.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false
state.error = action.payload || "An error occurred"
}
)
},
})
name: "auth",
initialState,
reducers: {
logout: (state) => {
state.user = null;
state.isAuthenticated = false;
},
},
extraReducers: (builder) => {
builder
// Login
.addCase(loginUser.pending, (state) => {
state.isLoading = true;
state.error = null;
})
.addCase(
loginUser.fulfilled,
(state, action: PayloadAction<User>) => {
state.isLoading = false;
state.isAuthenticated = true;
state.user = action.payload;
}
)
.addCase(
loginUser.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false;
state.error = action.payload || "An error occurred";
}
)
// Register
.addCase(registerUser.pending, (state) => {
state.isLoading = true;
state.error = null;
})
.addCase(
registerUser.fulfilled,
(state, action: PayloadAction<User>) => {
state.isLoading = false;
state.isAuthenticated = true;
state.user = action.payload;
}
)
.addCase(
registerUser.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false;
state.error = action.payload || "An error occurred";
}
)
// Logout
.addCase(logoutUser.fulfilled, (state) => {
state.user = null;
state.isAuthenticated = false;
})
.addCase(
logoutUser.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.error =
action.payload || "An error occurred during logout";
}
);
},
});
export const { logout } = authSlice.actions
export default authSlice.reducer
export default authSlice.reducer;

View file

@ -1,13 +1,10 @@
import { configureStore } from '@reduxjs/toolkit';
import authReducer from '../slices/authSlice.ts'
const store = configureStore({
reducer: {
auth: authReducer,
},
});
import rootReducer from './reducers';
export const store = configureStore({
reducer: rootReducer,
})
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;

View file

@ -1,54 +1,61 @@
import { Routes as BaseRoutes, Navigate, Route } from 'react-router-dom';
// import useAuth from "./hooks/useAuth";
import React, { Suspense } from 'react';
import LoadingComponent from './components/Loading';
import DashboardLayout from './layouts/DashboardLayout';
import Login from './pages/Auth/Login';
import SignUp from './pages/Auth/SignUp';
import Dashboard from './pages/Dashboard';
import Vehicles from './pages/Vechiles';
import { Routes as BaseRoutes, Navigate, Route } from "react-router-dom";
import { Suspense } from "react";
import LoadingComponent from "./components/Loading";
import DashboardLayout from "./layouts/DashboardLayout";
import Login from "./pages/Auth/Login";
import SignUp from "./pages/Auth/SignUp";
import Dashboard from "./pages/Dashboard";
import Vehicles from "./pages/Vehicles";
import { useSelector } from "react-redux";
import { RootState } from "./redux/reducers";
import { useCookies } from "react-cookie";
function ProtectedRoute({
caps,
component,
}: {
caps: string[];
component: React.ReactNode;
}) {
if (!localStorage.getItem('authToken'))
return <Navigate to={`/auth/login`} replace />;
interface ProtectedRouteProps {
component: JSX.Element;
cookies?: { get: (key: string) => string | null };
}
function ProtectedRoute({ component }: ProtectedRouteProps): JSX.Element {
const [cookies] = useCookies(["authToken"]);
const isCookiePresent = !!cookies?.authToken;
const isAuthenticated = useSelector(
(state: RootState) => state.authReducer.isAuthenticated
);
return component;
if (!isAuthenticated && !isCookiePresent) {
return <Navigate to="/auth/login" replace />;
}
return component;
}
export default function AppRouter() {
return (
<Suspense fallback={<LoadingComponent />}>
<BaseRoutes>
<Route element={<Navigate to="/auth/login" replace />} index />
return (
<Suspense fallback={<LoadingComponent />}>
<BaseRoutes>
<Route element={<Navigate to="/auth/login" replace />} index />
<Route path="/auth">
<Route
path=""
element={<Navigate to="/auth/login" replace />}
index
/>
<Route path="login" element={<Login />} />
<Route path="signup" element={<SignUp />} />
</Route>
<Route path="/panel" element={<DashboardLayout />}>
<Route
path="dashboard"
element={<ProtectedRoute caps={[]} component={<Dashboard />} />}
/>
<Route
path="vehicles"
element={<ProtectedRoute caps={[]} component={<Vehicles />} />}
/>
<Route path="*" element={<>404</>} />
</Route>
<Route path="*" element={<>404</>} />
</BaseRoutes>
</Suspense>
);
<Route path="/auth">
<Route
path=""
element={<Navigate to="/auth/login" replace />}
index
/>
<Route path="login" element={<Login />} />
<Route path="signup" element={<SignUp />} />
</Route>
<Route path="/panel" element={<DashboardLayout />}>
<Route
path="dashboard"
element={<ProtectedRoute component={<Dashboard />} />}
/>
<Route
path="vehicles"
element={<ProtectedRoute component={<Vehicles />} />}
/>
<Route path="*" element={<>404</>} />
</Route>
<Route path="*" element={<>404</>} />
</BaseRoutes>
</Suspense>
);
}

View file

@ -1,19 +1,20 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
}
}
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
],
"compilerOptions": {
"baseUrl": ".",
"jsx": "react-jsx",
"types": ["react", "react-dom"],
"lib": ["dom", "dom.iterable", "esnext"],
"paths": {
"@/*": ["./src/*"]
}
}
}