From 690af22199eeab36ad0b5588b1c8ee899ca607be Mon Sep 17 00:00:00 2001 From: jaanvi Date: Thu, 13 Mar 2025 16:25:46 +0530 Subject: [PATCH] Create Charging Station Ui and Updation in Managers --- src/components/AddManagerModal/index.tsx | 91 +++--- src/components/AddStationModal/index.tsx | 205 +++++++++++++ src/components/CustomTable/index.tsx | 38 +++ src/components/EditManagerModal/index.tsx | 73 ++--- src/components/EditStationModal/index.tsx | 270 ++++++++++++++++++ src/components/MenuContent/index.tsx | 9 +- .../Modals/StationViewModal/index.tsx | 127 ++++++++ src/pages/ManagerList/index.tsx | 22 +- src/pages/StationList/index.tsx | 192 +++++++++++++ src/redux/reducers.ts | 2 + src/redux/slices/VehicleSlice.ts | 4 +- src/redux/slices/adminSlice.ts | 4 +- src/redux/slices/managerSlice.ts | 6 +- src/redux/slices/stationSlice.ts | 246 ++++++++++++++++ src/redux/slices/userSlice.ts | 6 +- src/router.tsx | 66 ++--- 16 files changed, 1211 insertions(+), 150 deletions(-) create mode 100644 src/components/AddStationModal/index.tsx create mode 100644 src/components/EditStationModal/index.tsx create mode 100644 src/components/Modals/StationViewModal/index.tsx create mode 100644 src/pages/StationList/index.tsx create mode 100644 src/redux/slices/stationSlice.ts diff --git a/src/components/AddManagerModal/index.tsx b/src/components/AddManagerModal/index.tsx index d7c0588..db71397 100644 --- a/src/components/AddManagerModal/index.tsx +++ b/src/components/AddManagerModal/index.tsx @@ -31,7 +31,6 @@ export default function AddManagerModal({ reset, } = useForm(); const [showPassword, setShowPassword] = useState(false); - // Handle form submission const onSubmit = async (data: any) => { @@ -41,6 +40,7 @@ export default function AddManagerModal({ phone: data.phone, registeredAddress: data.registeredAddress, password: data.password, + stationId: data.stationId, // Send stationId here roleName: "Manager", // You can replace this with dynamic role if needed }; @@ -55,11 +55,10 @@ export default function AddManagerModal({ } }; - - const togglePasswordVisibility = (e: React.MouseEvent) => { + const togglePasswordVisibility = (e: React.MouseEvent) => { e.preventDefault(); // Prevent focus loss setShowPassword((prev) => !prev); - }; + }; return ( {/* Manager Name */} - - - Manager Name - - + + + + Manager Name + + + + + + Station Id + + + - {/* Email and Password */} {/* Email */} @@ -256,7 +277,7 @@ export default function AddManagerModal({ {/* Registered Address */} - Registered Address + Station Location { + handleAddStation(data); // Add station to the list + handleClose(); // Close modal after adding + reset(); + }; + + return ( + { + if (reason === "backdropClick") { + return; + } + handleClose(); // Close modal when clicking cross or cancel + }} + aria-labelledby="add-station-modal" + > + + {/* Header */} + + + Add Charging Station + + + + + + + {/* Horizontal Line */} + + + {/* Form */} +
+ {/* Input Fields */} + + {/* First Row - Two Inputs */} + + + + Station Name + + + + + + + Station Location + + + + + + {/* Second Row - Total Slots */} + + + + Total Slots + + + + + + + {/* Submit Button */} + + + +
+
+
+ ); +} diff --git a/src/components/CustomTable/index.tsx b/src/components/CustomTable/index.tsx index b00b1fe..1481d1f 100644 --- a/src/components/CustomTable/index.tsx +++ b/src/components/CustomTable/index.tsx @@ -34,6 +34,8 @@ import { CustomIconButton } from "../AddUserModel/styled.css.tsx"; import ManagerViewModal from "../Modals/ViewManagerModal"; import UserViewModal from "../Modals/UserViewModal/index.tsx"; import { deleteUser, userList } from "../../redux/slices/userSlice.ts"; +import { deleteStation } from "../../redux/slices/stationSlice.ts"; +import StationViewModal from "../Modals/StationViewModal/index.tsx"; // Styled components for customization const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -144,6 +146,9 @@ const CustomTable: React.FC = ({ case "user": dispatch(deleteUser(id || "")); break; + case "station": + dispatch(deleteStation(id || "")); + break; default: console.error("Unknown table type:", tableType); return; @@ -231,6 +236,8 @@ const CustomTable: React.FC = ({ ? "Managers" : tableType === "vehicle" ? "Vehicles" + : tableType === "station" + ? "Charging Station" : "List"} @@ -302,6 +309,8 @@ const CustomTable: React.FC = ({ ? "Manager" : tableType === "vehicle" ? "Vehicle" + : tableType === "station" + ? "Charging Station" : "Item"}
@@ -519,6 +528,16 @@ const CustomTable: React.FC = ({ id={selectedRow?.id} /> )} + {viewModal && tableType === "station" && ( + + handleViewButton(selectedRow?.id) + } + open={viewModal} + setViewModal={setViewModal} + id={selectedRow?.id} + /> + )} )} + {tableType === "station" && ( + + )} +
+
+
+ ); +}; + +export default EditStationModal; diff --git a/src/components/MenuContent/index.tsx b/src/components/MenuContent/index.tsx index acb72fa..8884e48 100644 --- a/src/components/MenuContent/index.tsx +++ b/src/components/MenuContent/index.tsx @@ -43,17 +43,24 @@ export default function MenuContent({ hidden }: PropType) { text: "Users", icon: , url: "/panel/user-list", + }, + userRole === "admin" && { + text: "Charging Stations", + icon: , + url: "/panel/station-list", // Placeholder for now }, userRole === "admin" && { text: "Managers", icon: , url: "/panel/manager-list", // Placeholder for now }, + userRole === "admin" && { text: "Vehicles", icon: , url: "/panel/vehicle-list", // Placeholder for now }, + ]; const filteredMenuItems = baseMenuItems.filter(Boolean); @@ -99,4 +106,4 @@ export default function MenuContent({ hidden }: PropType) { ); -} \ No newline at end of file +} diff --git a/src/components/Modals/StationViewModal/index.tsx b/src/components/Modals/StationViewModal/index.tsx new file mode 100644 index 0000000..b47ac08 --- /dev/null +++ b/src/components/Modals/StationViewModal/index.tsx @@ -0,0 +1,127 @@ +import React, { useEffect, useState } from "react"; +import { Box, Modal, Typography, Divider, Grid } from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useSelector } from "react-redux"; +import { RootState } from "../../../redux/reducers"; + +type Props = { + open: boolean; + setViewModal: Function; + handleView: (id: string | undefined) => void; + id?: number | undefined; +}; + +const style = { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: 400, + bgcolor: "background.paper", + borderRadius: 2, + boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)", + p: 4, + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: 2, +}; + +export default function StationViewModal({ open, setViewModal, id }: Props) { + const { stations } = useSelector( + (state: RootState) => state.stationReducer + ); + const [selectedStation, setSelectedStation] = useState(null); + + useEffect(() => { + if (id) { + const station = stations.find((station) => station.id === id); + setSelectedStation(station || null); + } + }, [id, stations]); + + return ( + + + + + + {selectedStation?.name || "Station"}'s Details + + setViewModal(false)} + sx={{ + cursor: "pointer", + display: "flex", + alignItems: "center", + }} + > + + + + + + + + {selectedStation ? ( + + + + Station Name:{" "} + + {selectedStation.name} + + + + + + Station Location:{" "} + + {selectedStation.registeredAddress} + + + + + + Total Slots: + + {selectedStation.totalSlots} + + + + + + Status: + + {selectedStation.status === "available" + ? "Available" + : "Not Available"} + + + + + ) : ( + + No station found with this ID + + )} + + + ); +} diff --git a/src/pages/ManagerList/index.tsx b/src/pages/ManagerList/index.tsx index aeedbbc..e7db51b 100644 --- a/src/pages/ManagerList/index.tsx +++ b/src/pages/ManagerList/index.tsx @@ -29,15 +29,18 @@ export default function ManagerList() { (state: RootState) => state.managerReducer.managers ); + // Fetch manager list on component mount useEffect(() => { dispatch(managerList()); }, [dispatch]); + // Open Add Manager Modal const handleClickOpen = () => { setRowData(null); // Reset row data when opening for new manager setAddModalOpen(true); }; + // Close all modals const handleCloseModal = () => { setAddModalOpen(false); setEditModalOpen(false); @@ -45,13 +48,16 @@ export default function ManagerList() { reset(); }; + // Handle adding a new manager const handleAddManager = async (data: { name: string; email: string; phone: string; registeredAddress: string; + stationId: string; }) => { try { + // Add manager with stationId await dispatch(addManager(data)); // Dispatch action to add manager await dispatch(managerList()); // Fetch the updated list handleCloseModal(); // Close the modal @@ -60,14 +66,17 @@ export default function ManagerList() { } }; + // Handle updating an existing manager const handleUpdate = async ( id: number, name: string, email: string, phone: string, - registeredAddress: string + registeredAddress: string, + stationId: string ) => { try { + // Update manager with stationId await dispatch( updateManager({ id, @@ -75,6 +84,7 @@ export default function ManagerList() { email, phone, registeredAddress, + stationId, }) ); await dispatch(managerList()); // Refresh the list after update @@ -84,16 +94,18 @@ export default function ManagerList() { } }; - + // Columns for the manager table const categoryColumns: Column[] = [ { id: "srno", label: "Sr No" }, { id: "name", label: "Name" }, { id: "email", label: "Email" }, { id: "phone", label: "Phone" }, { id: "registeredAddress", label: "Station Location" }, + { id: "stationName", label: "Station Name" }, { id: "action", label: "Action", align: "center" }, ]; + // Filter managers based on search term const filteredManagers = managers?.filter( (manager) => manager.name?.toLowerCase().includes(searchTerm.toLowerCase()) || @@ -104,6 +116,7 @@ export default function ManagerList() { .includes(searchTerm.toLowerCase()) ); + // Format rows to display manager details const categoryRows = filteredManagers?.length ? filteredManagers?.map( ( @@ -113,6 +126,7 @@ export default function ManagerList() { email: string; phone: string; registeredAddress: string; + stationName: string; }, index: number ) => ({ @@ -122,12 +136,14 @@ export default function ManagerList() { email: manager?.email, phone: manager.phone ?? "NA", registeredAddress: manager?.registeredAddress ?? "NA", + stationName: manager?.stationName ?? "NA", }) ) : []; return ( <> + {/* Custom Table to show manager list */} + {/* Add Manager Modal */} + {/* Edit Manager Modal */} (false); + const [editModalOpen, setEditModalOpen] = useState(false); + const [editRow, setEditRow] = useState(null); + const { reset } = useForm(); + + const [deleteModal, setDeleteModal] = useState(false); + const [viewModal, setViewModal] = useState(false); + const [rowData, setRowData] = useState(null); + const [searchTerm, setSearchTerm] = useState(""); + const dispatch = useDispatch(); + const stations = useSelector( + (state: RootState) => state.stationReducer.stations + ); + + useEffect(() => { + dispatch(stationList()); + }, [dispatch]); + + const handleClickOpen = () => { + setRowData(null); // Reset row data when opening for new admin + setAddModalOpen(true); + }; + + const handleCloseModal = () => { + setAddModalOpen(false); + setEditModalOpen(false); + setRowData(null); + reset(); + }; + + const handleAddStation = async (data: { + name: string; + registeredAddress: string; + totalSlots: string; + }) => { + try { + await dispatch(createStation(data)); // Dispatch action to add Station + await dispatch(stationList()); // Fetch the updated list + handleCloseModal(); // Close the modal + } catch (error) { + console.error("Error adding Station", error); + } + }; + + const handleUpdate = async ( + id: string, + name: string, + registeredAddress: string, + totalSlots: string + ) => { + try { + await dispatch( + updateStation({ + id, + name, + registeredAddress, + totalSlots, + }) + ); + await dispatch(stationList()); + handleCloseModal(); + } catch (error) { + console.error("Update failed", error); + } + }; + + // Toggle station status + // const handleStatusToggle = async (id: string, currentStatus: number) => { + // try { + // const newStatus = currentStatus === 1 ? 0 : 1; // Toggle between Active(1) and Inactive(0) + // await dispatch(updateStation({ + // id, status: newStatus, + // name: "", + // registeredAddress: "", + // totalSlots: "" + // })); + // await dispatch(stationList()); + // } catch (error) { + // console.error("Error toggling status", error); + // } + // }; + const filterStations = stations?.filter((station) => + station.name.toLocaleLowerCase().includes(searchTerm.toLowerCase()) + ); + + const categoryRows = filterStations?.length + ? filterStations?.map((station: Station, index: number) => ({ + id: station.id, + srno: index + 1, + name: station.name, + status: ( + + ), + statusValue: station.status, + })) + : []; + + const categoryColumns: Column[] = [ + { id: "srno", label: "Sr No" }, + { id: "name", label: "Station Name" }, + { id: "registeredAddress", label: "Station Location" }, + { id: "totalSlots", label: "Total Slots" }, + { id: "status", label: "Status" }, + { id: "action", label: "Action", align: "center" }, + ]; + + // Filter stations based on search term + // const filterStations = stations?.filter((station) => + // station.name.toLocaleLowerCase().includes(searchTerm.toLowerCase()) + // ); + + // // Prepare categoryRows with toggle switch for status + // const categoryRows = filterStations?.length + // ? filterStations?.map((station: any, index: number) => ({ + // id: station.id, + // srno: index + 1, + // name: station.name, + // status: ( + // + // handleStatusToggle(station.id, station.status) + // } + // color="primary" + // inputProps={{ "aria-label": "station-status-toggle" }} + // /> + // ), + // statusValue: station.status, + // })) + // : []; + + return ( + <> + setEditModalOpen(true)} + tableType="station" + handleClickOpen={handleClickOpen} + /> + + + + ); +} diff --git a/src/redux/reducers.ts b/src/redux/reducers.ts index 4b847ca..b732c03 100644 --- a/src/redux/reducers.ts +++ b/src/redux/reducers.ts @@ -7,6 +7,7 @@ import userReducer from "./slices/userSlice.ts"; import roleReducer from "./slices/roleSlice.ts"; import vehicleReducer from "./slices/VehicleSlice.ts"; import managerReducer from "../redux/slices/managerSlice.ts"; +import stationReducer from "../redux/slices/stationSlice.ts"; const rootReducer = combineReducers({ @@ -17,6 +18,7 @@ const rootReducer = combineReducers({ roleReducer, vehicleReducer, managerReducer, + stationReducer // Add other reducers here... }); diff --git a/src/redux/slices/VehicleSlice.ts b/src/redux/slices/VehicleSlice.ts index e637526..c4de897 100644 --- a/src/redux/slices/VehicleSlice.ts +++ b/src/redux/slices/VehicleSlice.ts @@ -71,7 +71,7 @@ export const updateVehicle = createAsyncThunk( async ({ id, ...vehicleData }: Vehicle, { rejectWithValue }) => { try { const response = await http.patch( - `${id}/update-vehicle`, + `/update-vehicle/${id}`, vehicleData ); toast.success("Vehicle Deatils updated successfully"); @@ -90,7 +90,7 @@ export const deleteVehicle = createAsyncThunk< { rejectValue: string } >("deleteVehicle", async (id, { rejectWithValue }) => { try { - const response = await http.delete(`/${id}/delete-vehicle`); + const response = await http.delete(`/delete-vehicle/${id}`); toast.success(response.data?.message); return id; } catch (error: any) { diff --git a/src/redux/slices/adminSlice.ts b/src/redux/slices/adminSlice.ts index b2c6928..00f306e 100644 --- a/src/redux/slices/adminSlice.ts +++ b/src/redux/slices/adminSlice.ts @@ -55,7 +55,7 @@ export const deleteAdmin = createAsyncThunk< { rejectValue: string } >("deleteAdmin", async (id, { rejectWithValue }) => { try { - const response = await http.delete(`/${id}/delete-admin`); + const response = await http.delete(`/delete-admin/${id}`); toast.success(response.data?.message); return id; } catch (error: any) { @@ -92,7 +92,7 @@ export const updateAdmin = createAsyncThunk( "updateAdmin", async ({ id, ...userData }: User, { rejectWithValue }) => { try { - const response = await http.put(`/${id}/update-admin`, userData); + const response = await http.put(`/update-admin/${id}`, userData); toast.success("Admin updated successfully"); return response?.data; } catch (error: any) { diff --git a/src/redux/slices/managerSlice.ts b/src/redux/slices/managerSlice.ts index 712f569..fa09e76 100644 --- a/src/redux/slices/managerSlice.ts +++ b/src/redux/slices/managerSlice.ts @@ -10,7 +10,7 @@ interface Manager { email: string; phone: string; registeredAddress: string; - roleId: number; + stationId: string; } interface ManagerState { @@ -74,7 +74,7 @@ export const updateManager = createAsyncThunk< return rejectWithValue("Manager ID is required."); } try { - const response = await http.put(`/${id}/update-manager`, managerData); + const response = await http.put(`/update-manager/${id}`, managerData); toast.success("Manager updated successfully"); return response?.data; } catch (error: any) { @@ -92,7 +92,7 @@ export const deleteManager = createAsyncThunk< { rejectValue: string } >("deleteManager", async (id, { rejectWithValue }) => { try { - await http.delete(`/${id}/delete-manager`); + await http.delete(`/delete-manager/${id}`); toast.success("Manager deleted successfully!"); return id; } catch (error: any) { diff --git a/src/redux/slices/stationSlice.ts b/src/redux/slices/stationSlice.ts new file mode 100644 index 0000000..2f6d91c --- /dev/null +++ b/src/redux/slices/stationSlice.ts @@ -0,0 +1,246 @@ +import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; +import axios from "axios"; +import http from "../../lib/https"; +import { toast } from "sonner"; + +// Define TypeScript types +interface Station { + id: string; + name: string; + registeredAddress: string; + totalSlots: string; + status: number; +} + +interface StationState { + stations: Station[]; + loading: boolean; + error: string | null; +} + +// Initial state +const initialState: StationState = { + stations: [], + loading: false, + error: null, +}; + +export const stationList = createAsyncThunk( + "fetchStations", + async (_, { rejectWithValue }) => { + try { + const token = localStorage?.getItem("authToken"); + if (!token) throw new Error("No token found"); + + const response = await http.get("/get-station"); + + if (!response.data) throw new Error("Invalid API response"); + + // Return the full response to handle in the reducer + return response.data; + } catch (error: any) { + toast.error("Error Fetching Stations: " + error.message); + return rejectWithValue( + error?.response?.data?.message || "An error occurred" + ); + } + } +); + +// Create Station +export const createStation = createAsyncThunk< + any, + { + name: string; + registeredAddress: string; + totalSlots: string; + }, + { rejectValue: string } +>("Station/createStation", async (data, { rejectWithValue }) => { + try { + const response = await http.post("/create-station", data); + toast.success("Station created successfully"); + return response.data; + } catch (error: any) { + toast.error( + "Failed to create Station: " + + (error.response?.data?.message || "Unknown error") + ); + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); + +// Update Station details +export const updateStation = createAsyncThunk( + "updateStation", + async ({ id, ...stationData }: Station, { rejectWithValue }) => { + try { + const response = await http.patch( + `/update-station/${id}`, + stationData + ); + toast.success("Station Deatils updated successfully"); + return response?.data; + } catch (error: any) { + toast.error("Error updating the user: " + error); + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } + } +); +export const deleteStation = createAsyncThunk< + string, + string, + { rejectValue: string } +>("deleteStation", async (id, { rejectWithValue }) => { + try { + const response = await http.delete(`/delete-station/${id}`); + toast.success(response.data?.message); + return id; + } catch (error: any) { + toast.error("Error deleting the Station" + error); + + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); + +export const toggleStatus = createAsyncThunk< + any, + { id: string; status: number }, + { rejectValue: string } +>("Station/toggleStatus", async ({ id, status }, { rejectWithValue }) => { + try { + const response = await http.patch(`${id}`, { status }); + + if (response.data.statusCode === 200) { + toast.success( + response.data.message || "Status updated successfully" + ); + // Return both the response data and the requested status for reliable state updates + return { + responseData: response.data, + id, + status, + }; + } else { + throw new Error(response.data.message || "Failed to update status"); + } + } catch (error: any) { + toast.error( + "Error updating status: " + (error.message || "Unknown error") + ); + return rejectWithValue( + error.response?.data?.message || + error.message || + "An error occurred" + ); + } +}); + +const stationSlice = createSlice({ + name: "stations", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(stationList.pending, (state) => { + state.loading = true; + state.error = null; + }) + .addCase( + stationList.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + // Properly extract stations from the response data structure + state.stations = + action.payload.data?.results || + action.payload.data || + []; + } + ) + .addCase(stationList.rejected, (state, action) => { + state.loading = false; + state.error = action.payload || "Failed to fetch stations"; + }) + .addCase(createStation.pending, (state) => { + state.loading = true; + }) + .addCase( + createStation.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + // Add the newly created station to the state if it exists in the response + if (action.payload.data) { + state.stations.push(action.payload.data); + } + } + ) + .addCase( + createStation.rejected, + (state, action: PayloadAction) => { + state.loading = false; + state.error = action.payload || "Failed to create station"; + } + ) + .addCase(toggleStatus.pending, (state) => { + state.loading = true; + }) + .addCase( + toggleStatus.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + + // Get the id and updated status from the action payload + const { id, status } = action.payload; + + // Find and update the station with the new status + const stationIndex = state.stations.findIndex( + (station) => station.id === id + ); + if (stationIndex !== -1) { + state.stations[stationIndex] = { + ...state.stations[stationIndex], + status: status, + }; + } + } + ) + .addCase( + toggleStatus.rejected, + (state, action: PayloadAction) => { + state.loading = false; + state.error = + action.payload || "Failed to toggle station status"; + } + ) + .addCase(updateStation.pending, (state) => { + state.loading = true; + }) + .addCase(updateStation.fulfilled, (state, action) => { + state.loading = false; + state.error = action.payload; + }) + .addCase(updateStation.rejected, (state) => { + state.loading = false; + }) + .addCase(deleteStation.pending, (state) => { + state.loading = true; + }) + .addCase(deleteStation.fulfilled, (state, action) => { + state.loading = false; + state.stations = state.stations.filter( + (station) => String(station.id) !== String(action.payload) + ); + }) + .addCase(deleteStation.rejected, (state) => { + state.loading = false; + }); + }, +}); + +export default stationSlice.reducer; diff --git a/src/redux/slices/userSlice.ts b/src/redux/slices/userSlice.ts index 20ab9b4..92950ac 100644 --- a/src/redux/slices/userSlice.ts +++ b/src/redux/slices/userSlice.ts @@ -60,7 +60,7 @@ export const createUser = createAsyncThunk< { rejectValue: string } >("/CreateUser", async (data, { rejectWithValue }) => { try { - const response = await http.post("create-user", data); + const response = await http.post("/create-user", data); return response.data; } catch (error: any) { return rejectWithValue( @@ -73,7 +73,7 @@ export const updateUser = createAsyncThunk( "updateUser", async ({ id, ...userData }: User, { rejectWithValue }) => { try { - const response = await http.put(`/${id}/update-user`, userData); + const response = await http.put(`/update-user/${id}`, userData); toast.success("User updated successfully"); return response?.data; } catch (error: any) { @@ -91,7 +91,7 @@ export const deleteUser = createAsyncThunk< { rejectValue: string } >("deleteUser", async (id, { rejectWithValue }) => { try { - const response = await http.delete(`/${id}/delete-user`); + const response = await http.delete(`/delete-user/${id}`); toast.success(response.data?.message); return id; } catch (error: any) { diff --git a/src/router.tsx b/src/router.tsx index fd15284..5b2cbdb 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -18,6 +18,7 @@ const UserList = lazy(() => import("./pages/UserList")); const AddEditRolePage = lazy(() => import("./pages/AddEditRolePage")); const RoleList = lazy(() => import("./pages/RoleList")); const ManagerList = lazy(() => import("./pages/ManagerList")); +const StationList = lazy(() => import("./pages/StationList")); interface ProtectedRouteProps { @@ -51,79 +52,44 @@ export default function AppRouter() { }> } - /> - } + element={} />} /> } - /> - } + element={} />} /> } - /> - } - /> - - } - /> - } + element={} />} /> + } />} + /> } - /> - } + element={} />} /> } - /> - } + element={} />} /> } - /> + } /> } /> + } />} + /> } - /> - } + element={} />} />