dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
22 changed files with 25171 additions and 14419 deletions
Showing only changes of commit 7de0799b02 - 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
}

32473
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,75 +1,76 @@
{
"name": "digi-health-admin-dashboard",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.3.0",
"@mui/material": "^6.3.0",
"@mui/x-charts": "^7.23.2",
"@mui/x-data-grid": "^7.23.5",
"@mui/x-date-pickers": "^7.23.3",
"@mui/x-tree-view": "^7.23.2",
"@react-spring/web": "^9.7.5",
"@reduxjs/toolkit": "^2.5.0",
"AdapterDayjs": "link:@mui/x-date-pickers/AdapterDayjs",
"AppBar": "link:@mui/material/AppBar",
"Box": "link:@mui/material/Box",
"PieChart": "link:@mui/x-charts/PieChart",
"RichTreeView": "link:@mui/x-tree-view/RichTreeView",
"Stack": "link:@mui/material/Stack",
"Tabs": "link:@mui/material/Tabs",
"Toolbar": "link:@mui/material/Toolbar",
"Typography": "link:@mui/material/Typography",
"add": "^2.0.6",
"axios": "^1.7.9",
"clsx": "^2.1.1",
"cra-template-typescript": "1.2.0",
"dayjs": "^1.11.13",
"hooks": "link:@mui/x-charts/hooks",
"mui-phone-number": "^3.0.3",
"mui-tel-input": "^7.0.0",
"prop-types": "^15.8.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.54.2",
"react-redux": "^9.2.0",
"react-router-dom": "^7.1.1",
"react-scripts": "5.0.1",
"react-toastify": "^11.0.2",
"styles": "link:@mui/material/styles",
"web-vitals": "^4.2.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/node": "^22.10.5",
"@types/react": "^19.0.3",
"@types/react-dom": "^19.0.2",
"typescript": "^5.7.2"
}
"name": "digi-ev-admin-dashboard",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.3.0",
"@mui/material": "^6.3.0",
"@mui/x-charts": "^7.23.2",
"@mui/x-data-grid": "^7.23.5",
"@mui/x-date-pickers": "^7.23.3",
"@mui/x-tree-view": "^7.23.2",
"@react-spring/web": "^9.7.5",
"@reduxjs/toolkit": "^2.5.0",
"AdapterDayjs": "file:@mui/x-date-pickers/AdapterDayjs",
"add": "^2.0.6",
"AppBar": "file:@mui/material/AppBar",
"axios": "^1.7.9",
"Box": "file:@mui/material/Box",
"clsx": "^2.1.1",
"cra-template-typescript": "1.2.0",
"dayjs": "^1.11.13",
"hooks": "file:@mui/x-charts/hooks",
"mui-phone-number": "^3.0.3",
"mui-tel-input": "^7.0.0",
"PieChart": "file:@mui/x-charts/PieChart",
"prop-types": "^15.8.1",
"react": "^18.0.0",
"react-cookie": "^7.2.2",
"react-dom": "^18.0.0",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.54.2",
"react-redux": "^9.2.0",
"react-router-dom": "^7.1.1",
"react-scripts": "5.0.1",
"react-toastify": "^11.0.2",
"RichTreeView": "file:@mui/x-tree-view/RichTreeView",
"Stack": "file:@mui/material/Stack",
"styles": "file:@mui/material/styles",
"Tabs": "file:@mui/material/Tabs",
"Toolbar": "file:@mui/material/Toolbar",
"Typography": "file:@mui/material/Typography",
"web-vitals": "^4.2.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/node": "^22.10.5",
"@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2",
"typescript": "^5.7.3"
}
}

File diff suppressed because it is too large Load diff

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,12 @@
import { BrowserRouter as Router} from 'react-router-dom';
import AppRouter from './router';
import { BrowserRouter as Router } from "react-router-dom";
import AppRouter from "./router";
function App() {
return (
<Router>
<AppRouter />
</Router>
);
return (
<Router>
<AppRouter />
</Router>
);
}
export default App;

View file

@ -1,82 +1,311 @@
import React,{useEffect} from "react";
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@mui/material";
// import React, { useEffect } from "react";
// import {
// Button,
// Dialog,
// DialogActions,
// DialogContent,
// DialogTitle,
// TextField,
// } from "@mui/material";
// import { useForm, Controller } from "react-hook-form";
// import { useSelector } from "react-redux";
// import { RootState } from "../../redux/store/store";
// //By Jaanvi : Edit Model :: 11-feb-25
// interface AddEditCategoryModalProps {
// open: boolean;
// handleClose: () => void;
// editRow: any;
// handleUpdate: (id: string, name: string, role: string) => void;
// }
// interface FormData {
// role: string;
// name: string;
// category: string;
// }
// const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
// open,
// handleClose,
// editRow,
// handleUpdate,
// }) => {
// const {
// control,
// handleSubmit,
// formState: { errors },
// setValue,
// reset,
// } = useForm<FormData>({
// defaultValues: {
// category: "",
// name: "",
// role: "",
// },
// });
// const { isLoading } = useSelector((state: RootState) => state.auth.admin);
// const onSubmit = (data: FormData) => {
// if (editRow) {
// handleUpdate(editRow.id, data.name, data.role);
// handleClose();
// reset();
// } else {
// console.log(data.category);
// }
// };
// useEffect(() => {
// if (editRow) {
// setValue("category", editRow.name);
// setValue("name", editRow.name);
// setValue("role", editRow.role);
// } else {
// reset();
// }
// }, [editRow, setValue, reset]);
// return (
// <>
// <Dialog
// open={open}
// onClose={handleClose}
// maxWidth="md"
// fullWidth
// PaperProps={{
// component: "form",
// onSubmit: handleSubmit(onSubmit),
// }}
// >
// <DialogTitle>{editRow ? "Edit" : "Add"} Category</DialogTitle>
// <DialogContent>
// <Controller
// name="category"
// control={control}
// rules={{
// required: "Category Name is required",
// }}
// render={({ field }) => (
// <TextField
// {...field}
// autoFocus
// required
// margin="dense"
// label="Add Category Name"
// type="text"
// fullWidth
// variant="standard"
// error={!!errors.category}
// helperText={errors.category?.message}
// />
// )}
// />
// {/* AdminField */}
// <Controller
// name="name"
// control={control}
// rules={{
// required: "Admin Name is required",
// }}
// render={({ field }) => (
// <TextField
// {...field}
// autoFocus
// required
// margin="dense"
// label="Admin Name"
// type="text"
// fullWidth
// variant="standard"
// error={!!errors.name}
// helperText={errors.name?.message}
// />
// )}
// />
// <Controller
// name="role"
// control={control}
// rules={{
// required: "Role is required",
// }}
// render={({ field }) => (
// <TextField
// {...field}
// margin="dense"
// label="Role"
// type="text"
// fullWidth
// variant="standard"
// error={!!errors.role}
// helperText={errors.role?.message}
// />
// )}
// />
// </DialogContent>
// <DialogActions>
// <Button onClick={handleClose}>Cancel</Button>
// <Button type="submit">Save</Button>
// </DialogActions>
// </Dialog>
// </>
// );
// };
// export default AddEditCategoryModal;
import React, { useEffect } from "react";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
TextField,
} from "@mui/material";
import { useForm, Controller } from "react-hook-form";
//By Jaanvi : Edit Model :: 11-feb-25
interface AddEditCategoryModalProps {
open: boolean;
handleClose: () => void;
editRow:any;
open: boolean;
handleClose: () => void;
editRow: any;
handleUpdate: (id: string, name: string, role: string) => void;
}
interface FormData {
category: string;
role: string;
name: string;
//category: string;
}
const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handleClose,editRow }) => {
const { control, handleSubmit, formState: { errors },setValue,reset } = useForm<FormData>({
defaultValues: {
category: "",
},
});
const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
open,
handleClose,
editRow,
handleUpdate,
}) => {
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>({
defaultValues: {
//category: "",
name: "",
role: "",
},
});
const onSubmit = (data: FormData) => {
console.log(data.category);
handleClose();
reset();
};
const onSubmit = (data: FormData) => {
if (editRow) {
handleUpdate(editRow.id, data.name, data.role);
}
// else {
// console.log(data.category);
// }
handleClose();
reset();
};
useEffect(() => {
if (editRow) {
setValue('category', editRow.name);
} else {
reset();
}
}, [editRow, setValue, reset]);
useEffect(() => {
if (editRow) {
// setValue("category", editRow.name);
setValue("name", editRow.name);
setValue("role", editRow.role);
} else {
reset();
}
}, [editRow, setValue, reset]);
return (
<>
<Dialog
open={open}
onClose={handleClose}
maxWidth="md"
fullWidth
PaperProps={{
component: 'form',
onSubmit: handleSubmit(onSubmit),
}}
>
<DialogTitle>{editRow ? "Editwefwefwe" : 'Add'} Category</DialogTitle>
<DialogContent>
<Controller
name="category"
control={control}
rules={{
required: "Category Name is required",
}}
render={({ field }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label="Add Category Name"
type="text"
fullWidth
variant="standard"
error={!!errors.category}
helperText={errors.category?.message}
/>
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit">Save</Button>
</DialogActions>
</Dialog>
</>
);
return (
<>
<Dialog
open={open}
onClose={handleClose}
maxWidth="md"
fullWidth
PaperProps={{
component: "form",
onSubmit: handleSubmit(onSubmit),
}}
>
<DialogTitle>{editRow ? "Edit" : "Add"} Category</DialogTitle>
<DialogContent>
{/* <Controller
name="category"
control={control}
rules={{
required: "Category Name is required",
}}
render={({ field }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label="Add Category Name"
type="text"
fullWidth
variant="standard"
error={!!errors.category}
helperText={errors.category?.message}
/>
)}
/> */}
{/* AdminField */}
<Controller
name="name"
control={control}
rules={{
required: "Admin Name is required",
}}
render={({ field }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label="Admin Name"
type="text"
fullWidth
variant="standard"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
<Controller
name="role"
control={control}
rules={{
required: "Role is required",
}}
render={({ field }) => (
<TextField
{...field}
margin="dense"
label="Role"
type="text"
fullWidth
variant="standard"
error={!!errors.role}
helperText={errors.role?.message}
/>
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit">Save</Button>
</DialogActions>
</Dialog>
</>
);
};
export default AddEditCategoryModal;

View file

@ -1,187 +1,193 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper, { paperClasses } from '@mui/material/Paper';
import * as React from "react";
import { styled } from "@mui/material/styles";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell, { tableCellClasses } from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper, { paperClasses } from "@mui/material/Paper";
import {
Box,
Button,
dividerClasses,
IconButton,
listClasses,
Menu,
} from '@mui/material';
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
Box,
Button,
dividerClasses,
IconButton,
listClasses,
Menu,
} from "@mui/material";
import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded";
// Styled components for customization
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: ' #1565c0',
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
[`&.${tableCellClasses.head}`]: {
backgroundColor: " #1565c0",
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover,
},
'&:last-child td, &:last-child th': {
border: 0,
},
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover,
},
"&:last-child td, &:last-child th": {
border: 0,
},
}));
interface Column {
id: string;
label: string;
align?: 'left' | 'center' | 'right';
id: string;
label: string;
align?: "left" | "center" | "right";
}
interface Row {
[key: string]: any;
[key: string]: any;
}
interface CustomTableProps {
columns: Column[];
rows: Row[];
setDeleteModal: Function;
setRowData: Function;
setModalOpen: Function;
columns: Column[];
rows: Row[];
setDeleteModal: Function;
setRowData: Function;
setModalOpen: Function;
}
const CustomTable: React.FC<CustomTableProps> = ({
columns,
rows,
setDeleteModal,
setRowData,
setModalOpen,
columns,
rows,
setDeleteModal,
setRowData,
setModalOpen,
}) => {
console.log('columnsss', columns, rows);
console.log("columnsss", columns, rows);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const isImage = (value: any) => {
if (typeof value === 'string') {
return value.startsWith('http') || value.startsWith('data:image'); // Check for URL or base64 image
}
return false;
};
const isImage = (value: any) => {
if (typeof value === "string") {
return value.startsWith("http") || value.startsWith("data:image"); // Check for URL or base64 image
}
return false;
};
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
{columns.map((column) => (
<StyledTableCell key={column.id} align={column.align || 'left'}>
{column.label}
</StyledTableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, rowIndex) => (
<StyledTableRow key={rowIndex}>
{columns.map((column) => (
<StyledTableCell key={column.id} align={column.align || 'left'}>
{isImage(row[column.id]) ? (
<img
src={row[column.id]}
alt="Row "
style={{
width: '50px',
height: '50px',
objectFit: 'cover',
}}
/>
) : column.id !== 'action' ? (
row[column.id]
) : (
<IconButton
onClick={(e) => {
handleClick(e);
setRowData(row);
}}
>
<MoreVertRoundedIcon />
</IconButton>
)}
</StyledTableCell>
))}
</StyledTableRow>
))}
</TableBody>
</Table>
{open && (
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
sx={{
[`& .${listClasses.root}`]: {
padding: '4px',
},
[`& .${paperClasses.root}`]: {
padding: 0,
},
[`& .${dividerClasses.root}`]: {
margin: '4px -4px',
},
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
}}
>
<Button
variant="text"
onClick={() => setModalOpen(true)}
color="primary"
sx={{
justifyContent: 'flex-start',
py: 0,
textTransform: 'capitalize',
}}
>
Edit
</Button>
<Button
variant="text"
onClick={() => setDeleteModal(true)}
color="error"
sx={{
justifyContent: 'flex-start',
py: 0,
textTransform: 'capitalize',
}}
>
Delete
</Button>
</Box>
</Menu>
)}
</TableContainer>
);
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
{columns.map((column) => (
<StyledTableCell
key={column.id}
align={column.align || "left"}
>
{column.label}
</StyledTableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, rowIndex) => (
<StyledTableRow key={rowIndex}>
{columns.map((column) => (
<StyledTableCell
key={column.id}
align={column.align || "left"}
>
{isImage(row[column.id]) ? (
<img
src={row[column.id]}
alt="Row "
style={{
width: "50px",
height: "50px",
objectFit: "cover",
}}
/>
) : column.id !== "action" ? (
row[column.id]
) : (
<IconButton
onClick={(e) => {
handleClick(e);
setRowData(row);
}}
>
<MoreVertRoundedIcon />
</IconButton>
)}
</StyledTableCell>
))}
</StyledTableRow>
))}
</TableBody>
</Table>
{open && (
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
sx={{
[`& .${listClasses.root}`]: {
padding: "4px",
},
[`& .${paperClasses.root}`]: {
padding: 0,
},
[`& .${dividerClasses.root}`]: {
margin: "4px -4px",
},
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
}}
>
<Button
variant="text"
onClick={() => setModalOpen(true)}
color="primary"
sx={{
justifyContent: "flex-start",
py: 0,
textTransform: "capitalize",
}}
>
Edit
</Button>
<Button
variant="text"
onClick={() => setDeleteModal(true)}
color="error"
sx={{
justifyContent: "flex-start",
py: 0,
textTransform: "capitalize",
}}
>
Delete
</Button>
</Box>
</Menu>
)}
</TableContainer>
);
};
export default CustomTable;

View file

@ -1,89 +1,89 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Divider, { dividerClasses } from '@mui/material/Divider';
import Menu from '@mui/material/Menu';
import MuiMenuItem from '@mui/material/MenuItem';
import { paperClasses } from '@mui/material/Paper';
import { listClasses } from '@mui/material/List';
import ListItemText from '@mui/material/ListItemText';
import ListItemIcon, { listItemIconClasses } from '@mui/material/ListItemIcon';
import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded';
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
import MenuButton from '../MenuButton';
import { Avatar } from '@mui/material';
import * as React from "react";
import { styled } from "@mui/material/styles";
import Divider, { dividerClasses } from "@mui/material/Divider";
import Menu from "@mui/material/Menu";
import MuiMenuItem from "@mui/material/MenuItem";
import { paperClasses } from "@mui/material/Paper";
import { listClasses } from "@mui/material/List";
import ListItemText from "@mui/material/ListItemText";
import ListItemIcon, { listItemIconClasses } from "@mui/material/ListItemIcon";
import LogoutRoundedIcon from "@mui/icons-material/LogoutRounded";
import MoreVertRoundedIcon from "@mui/icons-material/MoreVertRounded";
import MenuButton from "../MenuButton";
import { Avatar } from "@mui/material";
const MenuItem = styled(MuiMenuItem)({
margin: '2px 0',
margin: "2px 0",
});
export default function OptionsMenu({ avatar }: { avatar?: boolean }) {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<React.Fragment>
<MenuButton
aria-label="Open menu"
onClick={handleClick}
sx={{ borderColor: 'transparent' }}
>
{avatar ? (
<MoreVertRoundedIcon />
) : (
<Avatar
sizes="small"
alt="Riley Carter"
src="/static/images/avatar/7.jpg"
sx={{ width: 36, height: 36 }}
/>
)}
</MenuButton>
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
sx={{
[`& .${listClasses.root}`]: {
padding: '4px',
},
[`& .${paperClasses.root}`]: {
padding: 0,
},
[`& .${dividerClasses.root}`]: {
margin: '4px -4px',
},
}}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<Divider />
<MenuItem onClick={handleClose}>Add another account</MenuItem>
<MenuItem onClick={handleClose}>Settings</MenuItem>
<Divider />
<MenuItem
onClick={handleClose}
sx={{
[`& .${listItemIconClasses.root}`]: {
ml: 'auto',
minWidth: 0,
},
}}
>
<ListItemText>Logout</ListItemText>
<ListItemIcon>
<LogoutRoundedIcon fontSize="small" />
</ListItemIcon>
</MenuItem>
</Menu>
</React.Fragment>
);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<React.Fragment>
<MenuButton
aria-label="Open menu"
onClick={handleClick}
sx={{ borderColor: "transparent" }}
>
{avatar ? (
<MoreVertRoundedIcon />
) : (
<Avatar
sizes="small"
alt="Riley Carter"
src="/static/images/avatar/7.jpg"
sx={{ width: 36, height: 36 }}
/>
)}
</MenuButton>
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
sx={{
[`& .${listClasses.root}`]: {
padding: "4px",
},
[`& .${paperClasses.root}`]: {
padding: 0,
},
[`& .${dividerClasses.root}`]: {
margin: "4px -4px",
},
}}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<Divider />
<MenuItem onClick={handleClose}>Add another account</MenuItem>
<MenuItem onClick={handleClose}>Settings</MenuItem>
<Divider />
<MenuItem
onClick={handleClose}
sx={{
[`& .${listItemIconClasses.root}`]: {
ml: "auto",
minWidth: 0,
},
}}
>
<ListItemText>Logout</ListItemText>
<ListItemIcon>
<LogoutRoundedIcon fontSize="small" />
</ListItemIcon>
</MenuItem>
</Menu>
</React.Fragment>
);
}

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,26 +1,26 @@
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 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";
const root = ReactDOM.createRoot(document.getElementById('root'));
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>
<React.StrictMode>
<Provider store={store}>
<App />
<ToastContainer
autoClose={2000}
hideProgressBar
theme="dark"
transition={Slide}
toastStyle={{ border: "1px solid dimgray" }}
/>
</Provider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function

View file

@ -1,114 +1,129 @@
import React, { useEffect, useState } from "react"
import { Box, Button, Typography } from "@mui/material"
import AddEditCategoryModal from "../../components/AddEditCategoryModal"
import { useForm } from "react-hook-form"
import CustomTable from "../../components/CustomTable"
import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal"
import { useDispatch, useSelector } from "react-redux"
import { adminList } from "../../redux/slices/authSlice"
import { AppDispatch, RootState } from "../../redux/store/store" // Import RootState for selector
import React, { useEffect, useState } from "react";
import { Box, Button, Typography } from "@mui/material";
import AddEditCategoryModal from "../../components/AddEditCategoryModal";
// import { useForm } from "react-hook-form";
import { useForm } from "react-hook-form";
import CustomTable from "../../components/CustomTable";
import DeleteModal from "../../components/Modals/DeleteModal/DeleteModal";
import { useDispatch, useSelector } from "react-redux";
import { adminList, updateAdmin } from "../../redux/slices/authSlice";
import { AppDispatch, RootState } from "../../redux/store/store"; // Import RootState for selector
// Sample data for categories
export default function AdminList() {
const [modalOpen, setModalOpen] = useState(false)
const [editRow, setEditRow] = useState<any>(null)
const { reset } = useForm()
const [modalOpen, setModalOpen] = useState(false);
const [editRow, setEditRow] = useState<any>(null);
const { reset } = useForm();
const [deleteModal, setDeleteModal] = React.useState<boolean>(false)
const [rowData, setRowData] = React.useState<any | null>(null)
const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
const [rowData, setRowData] = React.useState<any | null>(null);
const dispatch = useDispatch<AppDispatch>()
const dispatch = useDispatch<AppDispatch>();
// Fetching admin data from the Redux store
const admins = useSelector((state: RootState) => state.auth.admins)
// Fetching admin data from the Redux store
const admins = useSelector((state: RootState) => state.auth.admins);
// Dispatching the API call when the component mounts
useEffect(() => {
dispatch(adminList())
}, [dispatch])
// Dispatching the API call when the component mounts
useEffect(() => {
dispatch(adminList());
}, [dispatch]);
const handleClickOpen = () => {
setModalOpen(true)
setEditRow(null)
}
const handleClickOpen = () => {
setModalOpen(true);
setEditRow(null);
};
const handleCloseModal = () => {
setModalOpen(false)
reset()
}
const handleCloseModal = () => {
setModalOpen(false);
reset();
};
const handleDelete = () => {
setDeleteModal(false)
}
const handleDelete = () => {
setDeleteModal(false);
};
//By Jaanvi : Edit feature :: 11-feb-25
const handleUpdate = async (id: string, name: string, role: string) => {
try {
await dispatch(updateAdmin({ id, name, role }));
dispatch(adminList()); // Fetch updated admins list after update
} catch (error) {
console.error("Update failed", error);
}
};
const categoryColumns = [
{ id: "srno", label: "Sr No" },
{ id: "name", label: "Name" },
{ id: "role", label: "Role" },
{ id: "action", label: "Action", align: "center" },
]
const categoryColumns = [
{ id: "srno", label: "Sr No" },
{ id: "name", label: "Name" },
{ id: "role", label: "Role" },
{ id: "action", label: "Action", align: "center" },
];
// If no admins are available, display the sample data
const categoryRows = admins?.length
? admins?.map(
(admin: { name: string; role: string }, index: number) => ({
srno: index + 1,
name: admin?.name,
role: admin?.role || "N/A",
})
)
: []
// If no admins are available, display the sample data
const categoryRows = admins?.length
? admins?.map(
(
admin: { id: string; name: string; role: string },
index: number
) => ({
srno: index + 1,
id: admin?.id,
name: admin?.name,
role: admin?.role || "N/A",
})
)
: [];
return (
<>
<Box
sx={{
width: "100%",
maxWidth: {
sm: "100%",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
},
}}
>
{/* Title and Add Category button */}
<Typography
component="h2"
variant="h6"
sx={{ mt: 2, fontWeight: 600 }}
>
Admins
</Typography>
<Button
variant="contained"
size="medium"
sx={{ textAlign: "right" }}
onClick={handleClickOpen}
>
Add Category
</Button>
</Box>
return (
<>
<Box
sx={{
width: "100%",
maxWidth: {
sm: "100%",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
},
}}
>
{/* Title and Add Category button */}
<Typography
component="h2"
variant="h6"
sx={{ mt: 2, fontWeight: 600 }}
>
Admins
</Typography>
<Button
variant="contained"
size="medium"
sx={{ textAlign: "right" }}
onClick={handleClickOpen}
>
Add Category
</Button>
</Box>
<CustomTable
columns={categoryColumns}
rows={categoryRows}
editRow={editRow}
setDeleteModal={setDeleteModal}
setRowData={setRowData}
setModalOpen={setModalOpen}
/>
<AddEditCategoryModal
open={modalOpen}
handleClose={handleCloseModal}
editRow={rowData}
/>
<DeleteModal
open={deleteModal}
setDeleteModal={setDeleteModal}
handleDelete={handleDelete}
/>
</>
)
<CustomTable
columns={categoryColumns}
rows={categoryRows}
editRow={editRow}
setDeleteModal={setDeleteModal}
setRowData={setRowData}
setModalOpen={setModalOpen}
/>
<AddEditCategoryModal
open={modalOpen}
handleClose={handleCloseModal}
editRow={rowData}
handleUpdate={handleUpdate}
/>
<DeleteModal
open={deleteModal}
setDeleteModal={setDeleteModal}
handleDelete={handleDelete}
/>
</>
);
}

View file

@ -213,7 +213,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
<Typography sx={{ textAlign: 'center' }}>
Don&apos;t have an account?{' '}
<Link
href="/signup/"
href="/auth/signup"
variant="body2"
sx={{ alignSelf: 'center' }}
>

View file

@ -117,11 +117,11 @@ const dispatch = useDispatch();
return (
<AppTheme {...props}>
<CssBaseline enableColorScheme />
<ColorModeSelect sx={{ position: 'fixed', top: '1rem', right: '1rem' }} />
{/* <CssBaseline enableColorScheme /> */}
<ColorModeSelect sx={{ position: 'fixed', top: '1rem', right: '1rem' }} />/
<SignUpContainer direction="column" justifyContent="space-between">
<Card variant="outlined">
<SitemarkIcon />
Digi-EV
<Typography
component="h1"
variant="h4"
@ -204,12 +204,12 @@ const dispatch = useDispatch();
/>
</FormControl>
<MuiPhoneNumber
defaultCountry='it'
defaultCountry='in'
onChange={handleOnChange}
value={phoneNumber}
/>
<FormControlLabel
{/* <FormControlLabel
control={
<Controller
name="allowExtraEmails"
@ -220,16 +220,16 @@ const dispatch = useDispatch();
/>
}
label="I want to receive updates via email."
/>
/> */}
<Button type="submit" fullWidth variant="contained">
Sign up
</Button>
</Box>
<Divider>
{/* <Divider>
<Typography sx={{ color: 'text.secondary' }}>or</Typography>
</Divider>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
</Divider> */}
{/* <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<Button
fullWidth
variant="outlined"
@ -256,6 +256,19 @@ const dispatch = useDispatch();
Sign in
</Link>
</Typography>
</Box> */}
<Divider>or</Divider>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<Typography sx={{ textAlign: 'center' }}>
Already have an account? &nbsp;
<Link
href="/auth/login"
variant="body2"
sx={{ alignSelf: 'center' }}
>
Sign in
</Link>
</Typography>
</Box>
</Card>
</SignUpContainer>

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({
auth: authReducer,
});
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;

View file

@ -1,32 +0,0 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
// Example: You might have an API call for deleting admin like this
export const deleteAdmin = createAsyncThunk(
'auth/deleteAdmin',
async (adminId: number, thunkAPI) => {
try {
const response = await axios.delete(`/api/admins/${adminId}`);
return adminId; // Return the ID of the deleted admin
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data);
}
}
);
const authSlice = createSlice({
name: 'auth',
initialState: {
admins: [], // Array of admins
},
reducers: {},
extraReducers: (builder) => {
builder.addCase(deleteAdmin.fulfilled, (state, action) => {
// Remove the deleted admin from the state
state.admins = state.admins.filter((admin) => admin.id !== action.payload);
});
// Handle rejected state if needed
},
});
export default authSlice.reducer;

View file

@ -1,177 +1,201 @@
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"
import axios from "axios"
import { backendHttp, apiHttp } from "../../lib/https"
import { toast } from "react-toastify"
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import axios from "axios";
import { backendHttp, apiHttp } from "../../lib/https";
import { toast } from "react-toastify";
// Define types for state
interface User {
map(
arg0: (
admin: { name: string; role: string },
index: number
) => { srno: number; name: string; role: string }
): unknown
id: string
email: string
id: string;
email: string;
}
interface Admin {
id: string
name: string
role: string
id: string;
name: string;
role: string;
}
interface AuthState {
user: User | null
admins: Admin[]
isAuthenticated: boolean
isLoading: boolean
error: string | null
user: User | null;
admins: Admin[];
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
}
// 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 backendHttp.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 backendHttp.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"
);
}
});
// 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 adminList = createAsyncThunk<
Admin[],
void,
{ rejectValue: string }
Admin[],
void,
{ rejectValue: string }
>("/auth", async (_, { rejectWithValue }) => {
try {
const response = await apiHttp.get("/auth")
console.log(response)
return response?.data?.data?.map(
(admin: { name: string; role: string }) => ({
name: admin?.name,
role: admin?.role,
})
)
// console.log(response.data.data)
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
)
}
})
try {
const response = await apiHttp.get("/auth");
return response?.data?.data?.map(
(admin: { id: string; name: string; role: string }) => ({
id: admin.id,
name: admin.name,
role: admin.role || "N/A",
})
);
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
});
//By Jaanvi : Edit feature :: 11-feb-25
// updateAdmin Action
export const updateAdmin = createAsyncThunk(
"/auth/id",
async (
{ id, name, role }: { id: any; name: string; role: string },
{ rejectWithValue }
) => {
try {
const response = await apiHttp.put(`/auth/${id}`, { name, role });
toast.success("Admin updated successfully");
console.log(response.data);
return response.data;
} catch (error: any) {
return rejectWithValue(
error.response?.data?.message || "An error occurred"
);
}
}
);
const initialState: AuthState = {
user: null,
admins: [],
isAuthenticated: false,
isLoading: false,
error: null,
}
user: null,
admins: [],
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";
}
)
// Fetch admin list
.addCase(adminList.pending, (state) => {
state.isLoading = true;
state.error = null;
})
.addCase(
adminList.fulfilled,
(state, action: PayloadAction<Admin[]>) => {
state.isLoading = false;
state.admins = action.payload;
}
)
.addCase(
adminList.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false;
state.error = action.payload || "An error occurred";
}
)
// update admin cases
.addCase(updateAdmin.fulfilled, (state, action) => {
const updatedAdmin = action.payload;
state.admins = state.admins.map((admin) =>
admin.id === updatedAdmin.id ? updatedAdmin : admin
);
})
.addCase(updateAdmin.rejected, (state) => {
state.isLoading = false;
state.error = null;
});
},
});
// created by Jaanvi and Eknoor
.addCase(adminList.pending, (state) => {
state.isLoading = true
state.error = null
})
.addCase(
adminList.fulfilled,
(state, action: PayloadAction<Admin[]>) => {
state.isLoading = false
state.admins = action.payload // ✅ Store admins correctly
}
)
.addCase(
adminList.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.isLoading = false
state.error = action.payload || "An error occurred"
}
)
},
})
export const { logout } = authSlice.actions
export default authSlice.reducer
export const { logout } = authSlice.actions;
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 { configureStore } from "@reduxjs/toolkit";
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,74 +1,74 @@
import { Routes as BaseRoutes, Navigate, Route } from "react-router-dom"
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 AdminList from "./pages/AdminList"
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/Vehicles";
import AdminList from "./pages/AdminList";
function ProtectedRoute({
caps,
component,
caps,
component,
}: {
caps: string[]
component: React.ReactNode
caps: string[];
component: React.ReactNode;
}) {
if (!localStorage.getItem("authToken"))
return <Navigate to={`/auth/login`} replace />
if (!localStorage.getItem("authToken"))
return <Navigate to={`/auth/login`} replace />;
return component
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="adminlist"
element={
<ProtectedRoute
caps={[]}
component={<AdminList />}
/>
}
/>
<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
caps={[]}
component={<Dashboard />}
/>
}
/>
<Route
path="vehicles"
element={
<ProtectedRoute
caps={[]}
component={<Vehicles />}
/>
}
/>
<Route
path="adminlist"
element={
<ProtectedRoute
caps={[]}
component={<AdminList />}
/>
}
/>
<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/*"]
}
}
}