From 80f603703ccf07e4ba7f59e2f445125c9ded1993 Mon Sep 17 00:00:00 2001 From: jaanvi Date: Wed, 19 Mar 2025 18:30:53 +0530 Subject: [PATCH] APi integration for slot maangement and add DigiEvLogo --- public/DigiEVLogo.png | Bin 0 -> 2000 bytes public/Digilogo.png | Bin 0 -> 1908 bytes public/digimantra_labs_logo.jpeg | Bin 0 -> 4320 bytes src/components/AddSlotModal/index.tsx | 316 ++++++++++++++++++++++++++ src/components/CustomTable/index.tsx | 38 ++-- src/components/MenuContent/index.tsx | 5 + src/components/SideMenu/index.tsx | 47 +++- src/pages/Auth/Login/index.tsx | 16 ++ src/pages/EVSlotManagement/index.tsx | 163 +++++++------ src/pages/EvSlotList/index.tsx | 147 ++++++++++++ src/redux/slices/slotSlice.ts | 120 +++++----- src/router.tsx | 7 + 12 files changed, 714 insertions(+), 145 deletions(-) create mode 100644 public/DigiEVLogo.png create mode 100644 public/Digilogo.png create mode 100644 public/digimantra_labs_logo.jpeg create mode 100644 src/components/AddSlotModal/index.tsx create mode 100644 src/pages/EvSlotList/index.tsx diff --git a/public/DigiEVLogo.png b/public/DigiEVLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9434f5e29c366b7c01fad3099328412fc6df35 GIT binary patch literal 2000 zcma)7`#Td17+uH~!`#}Ui=`5!Od_phHgfqa zT)uLR!Z)*s&`m;S%w6Hrf6#fK=bZP4^FHVO?c8v|o>WoNQ33z}Dh~D-HvnLR!usw5 zQe5Zvk+{NjQ4DlCi29smGLb-Kuz{aiklXlmVoM&tJWy`b0}CzPKjHkWJCzGY2ekI+3Wu* zIT-{BUO9iosBw6r^uy(6A0}sZMfS4}%}8QRzYi{rv@;~)P3yn>F>vVy-buGDApT?1 zX(tvI(YKD*PX$J@BTS6tX=wN5ta;kar0WKdtp5A1f(}h^zQ;1Bw;Ko8#vqs-G}qx< z$e&ihEd+#LsI`HDXHBP(Mu-fbFk@ z+K4nsZpL3xmo?lDJR9O1-z4x5IGSPUPy@RsquzoWw{4eHYaf5WyypE=lgmh9O7n)- zgfV4=()opvT~E?rb7i8h@NUXQkJTweq{*+Mf#$uj^^gn>_vsn;KuvtPYeb5?^x>QI z_@rFf3T`S14DCQ<vUeM$eE5A?VI|&4qiNOO!ZraJbQ3d9I%<3MTe$VCmiy&@tjw;twepEv1pg{6tzyY1* zL*32JX#N{3qVLwKGp~V!*9ZH=H68*7F`>5S?;eHQiM2HzA@^e^=uQ-&S6u+FQ|^{2 zQZQ3F8{L|SPG{H<92CLuQ_sEPQsDrc#z?M3azcaydt0>+VCav z3>Y;SsAW45QNP=S?9meRCB{6e@L46?d#)-p<~k>@tsVS|WJ#V96*N&xHD$ARMsI_+ zr07^>i)Zekr=fGaR2m`gbRDEP20(ark_&s}C`V^)IS?=!iKJh_*W@iwvPIusz z`)ultu#O+?aTWu9qO5q9^)NvfmXfeFKEpW^LlL3{2vqyr0iJtU4%{2@>^;5MS*qv- zMuis^gw_VX<@CnO=iCT&*F&0TR~%AAB!62j-UJ1sREpR5vbEIE#@r)_Tw_1aeOv2# zHuj!vepD&Si|B{=txSk06qCliWjzL3T{ZPY^dibxgj7ASOw9U}F=iY~|_gRLK*?D@{J=+wsD$zBUt7;_N939Ixh9-LOG80w5N zB9bPWj~LEhQ>h5X>0D3?eS7WmXJ^VK!O3dPf&;n@33ynd%dlqnX>Ky&)`<+3!nPEL z9b)LQk!-q^`{{1WB?7zL>og8xDPG?Fw#3P_7xF=Xm!$zSDufWFOzoSo_tTgxHWXD( z-8t!qFt-10Nr6_xt+JmISfeMuW~KDU6RG{0q@fL#sLMEZtPA##vAsu4Kl+OIh)Y;F zHut0&iD_NBQO56*3lXKSdEt2YMXEjZO0FA%h__Z^q6(5Zi6M1%61jl+9`ZRBGiGjrxbR? zDbI)B+5{%nlR6FODlg~aCNOX1h9AMn|MI5Nj2Jrrtv={yrbe{5K{(KZ8ytKm$qEBdYaU5y08b%F literal 0 HcmV?d00001 diff --git a/public/Digilogo.png b/public/Digilogo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7d127a25645a67968b998da6a3244130986a81 GIT binary patch literal 1908 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 aOV9-G_q~X7Ewnk(8N94gv>ckBj{OU((_Qrd literal 0 HcmV?d00001 diff --git a/src/components/AddSlotModal/index.tsx b/src/components/AddSlotModal/index.tsx new file mode 100644 index 0000000..9810e84 --- /dev/null +++ b/src/components/AddSlotModal/index.tsx @@ -0,0 +1,316 @@ +import React, { useEffect, useState } from "react"; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Button, + Typography, + IconButton, + Box, + Snackbar, + Stack, + Tabs, + Tab, + Card, +} from "@mui/material"; + +import { CustomTextField } from "../../components/AddEditUserModel/styled.css.tsx"; +import AddCircleIcon from "@mui/icons-material/AddCircle"; +import DeleteIcon from "@mui/icons-material/Delete"; +import CalendarTodayRoundedIcon from "@mui/icons-material/CalendarTodayRounded"; +import { LocalizationProvider, DatePicker } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs from "dayjs"; +import { useDispatch, useSelector } from "react-redux"; +import { + fetchAvailableSlots, + createSlot, + deleteSlot, +} from "../../redux/slices/slotSlice.ts"; + + +const days = [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +]; + +interface AddSlotModalProps { + open: boolean; + onClose: () => void; +} + +export default function AddSlotModal({ open, onClose }: AddSlotModalProps) { + const [selectedDay, setSelectedDay] = useState("Monday"); + const [openingTime, setOpeningTime] = useState(""); + const [closingTime, setClosingTime] = useState(""); + const [breakTime, setBreakTime] = useState([]); + const [error, setError] = useState(""); + const [successMessage, setSuccessMessage] = useState(null); + const [selectedDate, setSelectedDate] = useState( + dayjs() + ); + const dispatch = useDispatch(); + + // Fetch slots from the Redux state + const { + slots, + loading, + error: apiError, + } = useSelector((state: any) => state.slotReducer.slots); + + // useEffect(() => { + // if (selectedDay) { + // dispatch(fetchAvailableSlots(1)); // Replace with actual stationId if needed + // } + // }, [dispatch, selectedDay]); + + const addSlot = (start: string, end: string) => { + const selectedDateFormatted = selectedDate.format("YYYY-MM-DD"); + const startTime = start; + const endTime = end; + + dispatch( + createSlot({ + stationId: 1, + date: selectedDateFormatted, + startHour: startTime, + endHour: endTime, + isAvailable: true, + }) + ); + }; + + const addBreak = (start: string, end: string) => { + if (!start || !end) { + setError("Break Start and End times are required."); + return; + } + + setBreakTime([...breakTime, { start, end }]); + setError(""); + }; + + const deleteSlot = (start: string, end: string) => { + const updatedSlots = slots[selectedDay].filter( + (slot: any) => !(slot.start === start && slot.end === end) + ); + setSlots({ + ...slots, + [selectedDay]: updatedSlots, + }); + }; + + const deleteBreak = (start: string, end: string) => { + const updatedBreaks = breakTime.filter( + (breakItem: any) => + !(breakItem.start === start && breakItem.end === end) + ); + setBreakTime(updatedBreaks); + }; + + const saveData = () => { + if (!openingTime || !closingTime) { + setError("Operating hours are required."); + return; + } + + setSuccessMessage( + `Data for ${selectedDay} has been saved successfully!` + ); + setError(""); + }; + + const handleCloseSnackbar = () => { + setSuccessMessage(null); + }; + + return ( + + EV Station Slot Management + + {/* Date Picker */} + + + Select Date + + + setSelectedDate(newDate)} + renderInput={(props) => ( + + ), + }} + /> + )} + /> + + + + setSelectedDay(newValue)} + variant="scrollable" + scrollButtons="auto" + sx={{ mt: 3 }} + > + {days.map((day) => ( + + ))} + + + {/* Operating Hours */} + + + Set Operating Hours for {selectedDay} + + + setOpeningTime(e.target.value)} + fullWidth + /> + setClosingTime(e.target.value)} + fullWidth + /> + + + + {/* Slots */} + + Add Slots + + + + + + {error && ( + + {error} + + )} + + + {/* Break Time */} + + Break Time + + + + + + + + {/* Slots and Break Times Lists */} + {/* (Content for slots and breaks remains the same as in the original implementation) */} + + {/* Success Snackbar */} + + + + + + + + + ); +} + + diff --git a/src/components/CustomTable/index.tsx b/src/components/CustomTable/index.tsx index 75acf87..11e9866 100644 --- a/src/components/CustomTable/index.tsx +++ b/src/components/CustomTable/index.tsx @@ -36,6 +36,7 @@ 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"; +import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts"; // Styled components for customization const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -159,23 +160,26 @@ const CustomTable: React.FC = ({ const handleViewButton = (id: string | undefined) => { if (!id) console.error("ID not found", id); - // switch (tableType) { - // case "admin": - // dispatch(adminList()); - // break; - // case "vehicle": - // dispatch(vehicleList()); - // break; - // case "manager": - // dispatch(managerList()); - // break; - // case "user": - // dispatch(userList()); - // break; - // default: - // console.error("Unknown table type:", tableType); - // return; - // } + switch (tableType) { + case "admin": + dispatch(adminList()); + break; + case "vehicle": + dispatch(vehicleList()); + break; + case "manager": + dispatch(managerList()); + break; + case "user": + dispatch(userList()); + break; + case "slot": + dispatch(fetchAvailableSlots(1)); + break; + default: + console.error("Unknown table type:", tableType); + return; + } setViewModal(false); }; diff --git a/src/components/MenuContent/index.tsx b/src/components/MenuContent/index.tsx index afb0d33..becee06 100644 --- a/src/components/MenuContent/index.tsx +++ b/src/components/MenuContent/index.tsx @@ -65,6 +65,11 @@ export default function MenuContent({ hidden }: PropType) { icon: , url: "/panel/EVslots", // Placeholder for now }, + userRole === "manager" && { + text: "Slot List", + icon: , + url: "/panel/slot-list", // Placeholder for now + }, ]; const filteredMenuItems = baseMenuItems.filter(Boolean); diff --git a/src/components/SideMenu/index.tsx b/src/components/SideMenu/index.tsx index 0838f94..f5b2f2b 100644 --- a/src/components/SideMenu/index.tsx +++ b/src/components/SideMenu/index.tsx @@ -55,6 +55,52 @@ export default function SideMenu() { }, }} > + + + + + {/* Digi EV Text Section */} + + Digi EV + + + {user?.userType || "N/A"} + + + + +