diff --git a/src/components/MenuContent/index.tsx b/src/components/MenuContent/index.tsx index 794a33b..31207fd 100644 --- a/src/components/MenuContent/index.tsx +++ b/src/components/MenuContent/index.tsx @@ -13,10 +13,6 @@ import { RootState } from "../../redux/store/store"; import DashboardOutlinedIcon from "@mui/icons-material/DashboardOutlined"; import ManageAccountsOutlinedIcon from "@mui/icons-material/ManageAccountsOutlined"; -//Eknoor singh and Jaanvi -//date:- 12-Feb-2025 -//Made a different variable for super admin to access all the details. - type PropType = { hidden: boolean; }; @@ -26,6 +22,7 @@ export default function MenuContent({ hidden }: PropType) { const userRole = useSelector( (state: RootState) => state.profileReducer.user?.userType ); + const baseMenuItems = [ { text: "Dashboard", @@ -37,19 +34,25 @@ export default function MenuContent({ hidden }: PropType) { icon: , url: "/panel/admin-list", }, - userRole === "admin" && { - text: "Users", - icon: , - url: "/panel/user-list", - }, userRole === "superadmin" && { text: "Roles", icon: , url: "/panel/role-list", }, + userRole === "admin" && { + text: "Users", + icon: , + url: "/panel/user-list", + }, + userRole === "admin" && { + text: "Managers", + icon: , + url: "/panel/manager-list", // Placeholder for now + }, ]; const filteredMenuItems = baseMenuItems.filter(Boolean); + return ( @@ -59,7 +62,6 @@ export default function MenuContent({ hidden }: PropType) { disablePadding sx={{ display: "block", py: 1 }} > - {/* Wrap ListItemButton with Link to enable routing */} ); -} +} \ No newline at end of file diff --git a/src/components/Modals/ViewModal/ViewModal.tsx b/src/components/Modals/ViewModal/ViewModal.tsx deleted file mode 100644 index 8a1df15..0000000 --- a/src/components/Modals/ViewModal/ViewModal.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { Box, Button, Modal, Typography } from "@mui/material"; -import { AppDispatch, RootState } from "../../../redux/store/store"; -import { useDispatch, useSelector } from "react-redux"; -import { useEffect, useState } from "react"; - -type Props = { - open: boolean; - setViewModal: Function; - handleView: (id: string | undefined) => void; - id?: string | undefined; -}; -; - -const style = { - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - width: 330, - bgcolor: "background.paper", - borderRadius: 1.5, - boxShadow: 24, - p: 3, -}; - -const btnStyle = { py: 1, px: 5, width: "50%", textTransform: "capitalize", alignItems: "center" }; - -export default function ViewModal({ - open, - setViewModal, - id, // Selected user's ID -}: Props) { - const { admins } = useSelector((state: RootState) => state.adminReducer); - const [selectedAdmin, setSelectedAdmin] = useState(null); - - useEffect(() => { - if (id) { - const admin = admins.find((admin) => admin.id === id); - setSelectedAdmin(admin || null); - } - }, [id, admins]); - - return ( - - - - Details of {selectedAdmin?.name} - - {selectedAdmin ? ( - <> - Name: {selectedAdmin?.name} - Email: {selectedAdmin?.email} - Phone: {selectedAdmin?.phone} - Address: {selectedAdmin?.registeredAddress} - - ) : ( - No admin found with this ID - )} - - - - - - ); -} \ No newline at end of file diff --git a/src/pages/AddManagerModal/index.tsx b/src/pages/AddManagerModal/index.tsx new file mode 100644 index 0000000..b0d32f2 --- /dev/null +++ b/src/pages/AddManagerModal/index.tsx @@ -0,0 +1,126 @@ +import { useState } from "react"; +import { + Box, + Button, + Typography, + TextField, + Modal, + IconButton, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; + +export default function AddManagerModal({ open, handleClose, handleAddManager }) { + // State for input fields + const [managerName, setManagerName] = useState(""); + const [stationName, setStationName] = useState(""); + const [stationLocation, setStationLocation] = useState(""); + const [phoneNumber, setPhoneNumber] = useState(""); + + const handleSubmit = () => { + if (!managerName || !stationName || !stationLocation || !phoneNumber) { + alert("Please fill all fields"); + return; + } + + const newManager = { + managerName, + stationName, + stationLocation, + phoneNumber, + }; + + handleAddManager(newManager); // Add manager to table + handleClose(); // Close modal after adding + }; + + return ( + + + {/* Header */} + + + Add Managers + + + + + + + {/* Horizontal Line */} + + + {/* Input Fields */} + + {/* First Row - Two Inputs */} + + + Manager Name + setManagerName(e.target.value)} + /> + + + + Station Name + setStationName(e.target.value)} + /> + + + + {/* Second Row - Two Inputs */} + + + Station Location + setStationLocation(e.target.value)} + /> + + + + Phone Number + setPhoneNumber(e.target.value)} + /> + + + + + {/* Submit Button */} + + + + + + ); +} diff --git a/src/pages/EditUserModal/index.tsx b/src/pages/EditUserModal/index.tsx new file mode 100644 index 0000000..1e2468e --- /dev/null +++ b/src/pages/EditUserModal/index.tsx @@ -0,0 +1,175 @@ +import React, { useEffect } from "react"; +import { + Box, + Button, + Typography, + TextField, + Modal, + IconButton, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useForm, Controller } from "react-hook-form"; + +interface EditModalProps { + open: boolean; + handleClose: () => void; + handleCreate: (data: FormData) => void; + handleUpdate: (id: string, data: FormData) => void; + editRow: any; +} + +interface FormData { + managerName: string; + stationName: string; + stationLocation: string; + phoneNumber: string; +} + +const EditModal: React.FC = ({ + open, + handleClose, + handleCreate, + handleUpdate, + editRow, +}) => { + const { + control, + handleSubmit, + formState: { errors }, + setValue, + reset, + } = useForm({ + defaultValues: { + managerName: "", + stationName: "", + stationLocation: "", + phoneNumber: "", + }, + }); + + useEffect(() => { + if (editRow) { + setValue("managerName", editRow.managerName); + setValue("stationName", editRow.stationName); + setValue("stationLocation", editRow.stationLocation); + setValue("phoneNumber", editRow.phoneNumber); + } else { + reset(); + } + }, [editRow, setValue, reset]); + + const onSubmit = (data: FormData) => { + if (editRow) { + handleUpdate(editRow.id, data); + } else { + handleCreate(data); + } + handleClose(); + reset(); + }; + + return ( + + + {/* Header */} + + + {editRow ? "Edit Manager" : "Add Manager"} + + + + + + + {/* Horizontal Line */} + + + {/* Input Fields */} + + {/* First Row - Two Inputs */} + + + Manager Name + ( + + )} + /> + + + + Station Name + ( + + )} + /> + + + + {/* Second Row - Two Inputs */} + + + Station Location + ( + + )} + /> + + + + Phone Number + ( + + )} + /> + + + + + {/* Submit Button */} + + + + + + ); +}; + +export default EditModal; \ No newline at end of file diff --git a/src/pages/ManagerList/index.tsx b/src/pages/ManagerList/index.tsx new file mode 100644 index 0000000..50ed6dc --- /dev/null +++ b/src/pages/ManagerList/index.tsx @@ -0,0 +1,131 @@ +import React, { useState } from "react"; +import { Box, Button, Typography, TextField, InputAdornment, IconButton } from "@mui/material"; +import SearchIcon from "@mui/icons-material/Search"; +import EqualizerIcon from "@mui/icons-material/Tune"; +import CustomTable, { Column } from "../../components/CustomTable"; +import AddManagerModal from "../../pages/AddManagerModal"; +import EditUserModal from "../EditUserModal"; + +export default function ManagerList() { + const [search, setSearch] = useState(""); + const [addButtonModal, setAddButtonModal] = useState(false); + const [modalOpen, setModalOpen] = useState(false); + const [rowData, setRowData] = useState(null); + const [viewModal, setViewModal] = React.useState(false); + const [deleteModal, setDeleteModal] = React.useState(false); + + + const [managers, setManagers] = useState([ + { id: 1, srno: 1, managerName: "John Doe", stationName: "Station A", stationLocation: "Location X", phoneNumber: "123-456-7890" }, + { id: 2, srno: 2, managerName: "Jane Smith", stationName: "Station B", stationLocation: "Location Y", phoneNumber: "987-654-3210" }, + ]); + + const handleSearchChange = (event) => { + setSearch(event.target.value); + }; + + const handleClickOpen = () => { + setRowData(null); + setAddButtonModal(true); + }; + + const handleCloseModal = () => { + setAddButtonModal(false); + setModalOpen(false); + setRowData(null); + }; + + const handleUpdate = (id, updatedData) => { + setManagers((prevManagers) => + prevManagers.map((manager) => (manager.id === id ? { ...manager, ...updatedData } : manager)) + ); + handleCloseModal(); + }; + const handleAddManager = (newManager) => { + setManagers((prevManagers) => { + const newId = prevManagers.length > 0 ? prevManagers[prevManagers.length - 1].id + 1 : 1; + return [...prevManagers, { ...newManager, id: newId, srno: newId }]; + }); + setAddButtonModal(false); + }; + + + + const managerColumns: Column[] = [ + { id: "srno", label: "Sr No" }, + { id: "managerName", label: "Manager Name" }, + { id: "stationName", label: "Station Name" }, + { id: "stationLocation", label: "Station Location" }, + { id: "phoneNumber", label: "Phone Number" }, + { id: "action", label: "Action", align: "center" }, + ]; + + const filteredManagers = managers.filter((manager) => + Object.values(manager).some((value) => + typeof value === "string" && value.toLowerCase().includes(search.toLowerCase()) + ) + ); + + return ( + <> + + + Managers + + + + + + ), + }} + /> + + + + + + + + + + + + + + + + + ); +} diff --git a/src/redux/slices/managerSlice.ts b/src/redux/slices/managerSlice.ts new file mode 100644 index 0000000..48387c3 --- /dev/null +++ b/src/redux/slices/managerSlice.ts @@ -0,0 +1,103 @@ +import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; +import { toast } from "sonner"; + +// Interfaces +interface Manager { + id: string; + name: string; + email: string; + role: string; + phone: string; + registeredAddress: string; +} + +interface ManagerState { + managers: Manager[]; + isLoading: boolean; +} + +// Dummy API function placeholder +const dummyApiCall = async (response: any, delay = 500) => + new Promise((resolve) => setTimeout(() => resolve(response), delay)); + +// Fetch Manager List +export const fetchManagerList = createAsyncThunk( + "fetchManagerList", + async (_, { rejectWithValue }) => { + try { + const response: any = await dummyApiCall({ data: [{ id: "1", name: "John Doe", email: "john@example.com", role: "Manager", phone: "1234567890", registeredAddress: "Somewhere" }] }); + return response.data; + } catch (error: any) { + toast.error("Error fetching manager list: " + error); + return rejectWithValue("An error occurred"); + } + } +); + +// Delete Manager +export const deleteManager = createAsyncThunk( + "deleteManager", + async (id, { rejectWithValue }) => { + try { + await dummyApiCall(null);initialState +); + +// Add Manager +export const addManager = createAsyncThunk< + Manager, + { name: string; email: string; phone: string; registeredAddress: string }, + { rejectValue: string } +>("addManager", async (data, { rejectWithValue }) => { + try { + const response: any = await dummyApiCall({ id: "2", ...data }); + return response; + } catch (error: any) { + return rejectWithValue("An error occurred"); + } +}); + +const initialState: ManagerState = { + managers: [], + isLoading: false, +}; + +const managerSlice = createSlice({ + name: "manager", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchManagerList.pending, (state) => { + state.isLoading = true; + }) + .addCase(fetchManagerList.fulfilled, (state, action: PayloadAction) => { + state.isLoading = false; + state.managers = action.payload; + }) + .addCase(fetchManagerList.rejected, (state) => { + state.isLoading = false; + }) + .addCase(deleteManager.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteManager.fulfilled, (state, action) => { + state.isLoading = false; + state.managers = state.managers.filter((manager) => manager.id !== action.payload); + }) + .addCase(deleteManager.rejected, (state) => { + state.isLoading = false; + }) + .addCase(addManager.pending, (state) => { + state.isLoading = true; + }) + .addCase(addManager.fulfilled, (state, action) => { + state.isLoading = false; + state.managers.push(action.payload); + }) + .addCase(addManager.rejected, (state) => { + state.isLoading = false; + }); + }, +}); + +export default managerSlice.reducer; diff --git a/src/router.tsx b/src/router.tsx index d2ce56d..feffbfd 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -15,6 +15,8 @@ const ProfilePage = lazy(() => import("./pages/ProfilePage")); const NotFoundPage = lazy(() => import("./pages/NotFound")); const UserList = lazy(() => import("./pages/UserList")); const PermissionsTable = lazy(() => import("./pages/PermissionTable")); +const ManagerList = lazy(() => import("./pages/ManagerList")); + interface ProtectedRouteProps { caps: string[]; @@ -86,6 +88,18 @@ export default function AppRouter() { /> } /> + + } + /> + } + /> + + {children} + ); }