dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
10 changed files with 20745 additions and 8365 deletions
Showing only changes of commit 575e122b02 - Show all commits

13559
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
"@mui/x-charts": "^7.23.2", "@mui/x-charts": "^7.23.2",
"@mui/x-data-grid": "^7.23.5", "@mui/x-data-grid": "^7.23.5",
"@mui/x-date-pickers": "^7.23.3", "@mui/x-date-pickers": "^7.23.3",
"@mui/x-tree-view": "^7.23.2", "@mui/x-tree-view": "^7.23.2",
"@react-spring/web": "^9.7.5", "@react-spring/web": "^9.7.5",
"@reduxjs/toolkit": "^2.5.0", "@reduxjs/toolkit": "^2.5.0",
"AdapterDayjs": "link:@mui/x-date-pickers/AdapterDayjs", "AdapterDayjs": "link:@mui/x-date-pickers/AdapterDayjs",

File diff suppressed because it is too large Load diff

View file

@ -45,7 +45,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({ open, handl
onSubmit: handleSubmit(onSubmit), onSubmit: handleSubmit(onSubmit),
}} }}
> >
<DialogTitle>{editRow ? "Edit" : 'Add'} Category</DialogTitle> <DialogTitle>{editRow ? "Editwefwefwe" : 'Add'} Category</DialogTitle>
<DialogContent> <DialogContent>
<Controller <Controller
name="category" name="category"

View file

@ -45,7 +45,7 @@ const AddEditTagsModal: React.FC<AddEditTagsModalProps> = ({ open, handleClose,e
onSubmit: handleSubmit(onSubmit), onSubmit: handleSubmit(onSubmit),
}} }}
> >
<DialogTitle>{editRow ? "Edit" : 'Add'} Tag</DialogTitle> <DialogTitle>{editRow ? "Editsefwefwe" : 'Add'} Tag</DialogTitle>
<DialogContent> <DialogContent>
<Controller <Controller
name="tag" name="tag"

View file

@ -6,6 +6,7 @@ import ListItemText from '@mui/material/ListItemText';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import HomeRoundedIcon from '@mui/icons-material/HomeRounded'; import HomeRoundedIcon from '@mui/icons-material/HomeRounded';
import AnalyticsRoundedIcon from '@mui/icons-material/AnalyticsRounded'; import AnalyticsRoundedIcon from '@mui/icons-material/AnalyticsRounded';
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
const mainListItems = [ const mainListItems = [
@ -19,6 +20,12 @@ const mainListItems = [
icon: <AnalyticsRoundedIcon />, icon: <AnalyticsRoundedIcon />,
url: '/panel/vehicles', url: '/panel/vehicles',
}, },
//created by Eknnor and Jaanvi
{
text: 'Admin List',
icon: <FormatListBulletedIcon />,
url: '/panel/adminlist',
},
]; ];
type PropType = { type PropType = {

View file

@ -1,16 +1,45 @@
import axios from 'axios'; // import axios from 'axios';
const http = axios.create({ // const http = axios.create({
// 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;
// });
// export default http;
import axios, { AxiosInstance } from 'axios';
// Axios instance for the production backend
const backendHttp = 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; // Axios instance for the local API
const apiHttp = axios.create({
baseURL: "http://localhost:5000/api",
}); });
export default http;
// Add interceptors to both instances
const addAuthInterceptor = (instance: AxiosInstance) => {
instance.interceptors.request.use((config) => {
const authToken = localStorage.getItem('authToken');
if (authToken) {
config.headers.Authorization = authToken;
}
return config;
});
};
addAuthInterceptor(backendHttp);
addAuthInterceptor(apiHttp);
export { backendHttp, apiHttp };

View file

@ -0,0 +1,115 @@
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
// Sample data for categories
export default function AdminList() {
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 dispatch = useDispatch<AppDispatch>();
// Fetching admin data from the Redux store
const admins = useSelector((state: RootState) => state.auth.admins);
console.log(admins, "woihfiuwhfownfownefoi")
// Dispatching the API call when the component mounts
useEffect(() => {
dispatch(adminList());
}, [dispatch]);
const handleClickOpen = () => {
setModalOpen(true)
setEditRow(null)
}
const handleCloseModal = () => {
setModalOpen(false)
reset()
}
const handleDelete = () => {
setDeleteModal(false)
}
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: any; role: any }, index: number) => ({
srno: index + 1,
name: admin?.name,
role: admin.role,
})) : []
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}
/>
</>
)
}

View file

@ -1,19 +1,26 @@
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit" import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"
import axios from "axios" import axios from "axios"
import http from "../../lib/https" import { backendHttp, apiHttp } from "../../lib/https"
import { toast } from "react-toastify" import { toast } from "react-toastify"
// Define types for state // Define types for state
interface User { interface User {
map(arg0: (admin: { name: any; role: any }, index: number) => { srno: number; name: any; role: any }): unknown
id: string id: string
email: string email: string
} }
interface Admin {
id: string,
name: string,
role: string
}
interface AuthState { interface AuthState {
user: User | null user: User | null;
isAuthenticated: boolean admins: Admin[];
isLoading: boolean isAuthenticated: boolean;
error: string | null isLoading: boolean;
error: string | null;
} }
// Async thunk for login // Async thunk for login
@ -23,7 +30,7 @@ export const loginUser = createAsyncThunk<
{ rejectValue: string } { rejectValue: string }
>("auth/login", async ({ email, password }, { rejectWithValue }) => { >("auth/login", async ({ email, password }, { rejectWithValue }) => {
try { try {
const response = await http.post("admin/login", { email, password }) const response = await backendHttp.post("admin/login", { email, password })
localStorage.setItem("authToken", response.data?.data?.token) // Save token localStorage.setItem("authToken", response.data?.data?.token) // Save token
toast.success(response.data?.message) toast.success(response.data?.message)
return response.data return response.data
@ -53,12 +60,33 @@ export const registerUser = createAsyncThunk<
} }
}) })
export const adminList = createAsyncThunk<
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 || "N/A",
}));
console.log(response.data.data)
} catch (error: any) {
return rejectWithValue(error.response?.data?.message || "An error occurred");
}
});
const initialState: AuthState = { const initialState: AuthState = {
user: null, user: null,
admins: [],
isAuthenticated: false, isAuthenticated: false,
isLoading: false, isLoading: false,
error: null, error: null,
} };
const authSlice = createSlice({ const authSlice = createSlice({
name: "auth", name: "auth",
@ -111,6 +139,25 @@ const authSlice = createSlice({
state.error = action.payload || "An error occurred" state.error = action.payload || "An error occurred"
} }
) )
// 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"
}
)
}, },
}) })

View file

@ -1,54 +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 useAuth from "./hooks/useAuth";
import React, { Suspense } from 'react'; import React, { Suspense } from "react"
import LoadingComponent from './components/Loading'; import LoadingComponent from "./components/Loading"
import DashboardLayout from './layouts/DashboardLayout'; import DashboardLayout from "./layouts/DashboardLayout"
import Login from './pages/Auth/Login'; import Login from "./pages/Auth/Login"
import SignUp from './pages/Auth/SignUp'; import SignUp from "./pages/Auth/SignUp"
import Dashboard from './pages/Dashboard'; import Dashboard from "./pages/Dashboard"
import Vehicles from './pages/Vechiles'; import Vehicles from "./pages/Vechiles"
import AdminList from "./pages/AdminList"
function ProtectedRoute({ function ProtectedRoute({
caps, caps,
component, component,
}: { }: {
caps: string[]; caps: string[]
component: React.ReactNode; component: React.ReactNode
}) { }) {
if (!localStorage.getItem('authToken')) if (!localStorage.getItem("authToken"))
return <Navigate to={`/auth/login`} replace />; return <Navigate to={`/auth/login`} replace />
return component; return component
} }
export default function AppRouter() { export default function AppRouter() {
return ( return (
<Suspense fallback={<LoadingComponent />}> <Suspense fallback={<LoadingComponent />}>
<BaseRoutes> <BaseRoutes>
<Route element={<Navigate to="/auth/login" replace />} index /> <Route element={<Navigate to="/auth/login" replace />} index />
<Route path="/auth"> <Route path="/auth">
<Route <Route
path="" path=""
element={<Navigate to="/auth/login" replace />} element={<Navigate to="/auth/login" replace />}
index index
/> />
<Route path="login" element={<Login />} /> <Route path="login" element={<Login />} />
<Route path="signup" element={<SignUp />} /> <Route path="signup" element={<SignUp />} />
</Route> </Route>
<Route path="/panel" element={<DashboardLayout />}> <Route path="/panel" element={<DashboardLayout />}>
<Route <Route
path="dashboard" path="dashboard"
element={<ProtectedRoute caps={[]} component={<Dashboard />} />} element={
/> <ProtectedRoute
<Route caps={[]}
path="vehicles" component={<Dashboard />}
element={<ProtectedRoute caps={[]} component={<Vehicles />} />} />
/> }
<Route path="*" element={<>404</>} /> />
</Route> <Route
<Route path="*" element={<>404</>} /> path="vehicles"
</BaseRoutes> element={
</Suspense> <ProtectedRoute
); caps={[]}
component={<Vehicles />}
/>
}
/>
<Route
path="adminlist"
element={
<ProtectedRoute
caps={[]}
component={<AdminList />}
/>
}
/>
<Route path="*" element={<>404</>} />
</Route>
<Route path="*" element={<>404</>} />
</BaseRoutes>
</Suspense>
)
} }