diff --git a/public/DigiEVLogo.png b/public/DigiEVLogo.png new file mode 100644 index 0000000..6b9434f Binary files /dev/null and b/public/DigiEVLogo.png differ diff --git a/public/Digilogo.png b/public/Digilogo.png new file mode 100644 index 0000000..1a7d127 Binary files /dev/null and b/public/Digilogo.png differ diff --git a/public/digimantra_labs_logo.jpeg b/public/digimantra_labs_logo.jpeg new file mode 100644 index 0000000..eb470ea Binary files /dev/null and b/public/digimantra_labs_logo.jpeg differ diff --git a/src/components/AddBookingModal/index.tsx b/src/components/AddBookingModal/index.tsx new file mode 100644 index 0000000..c28f93a --- /dev/null +++ b/src/components/AddBookingModal/index.tsx @@ -0,0 +1,358 @@ +import React, { useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { + Box, + Button, + Typography, + Modal, + IconButton, + MenuItem, + Select, + InputLabel, + FormControl, + TextField, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useDispatch } from "react-redux"; +import { + addBooking, + bookingList, + getCarNames, + getCarPorts, +} from "../../redux/slices/bookSlice"; +import { AppDispatch } from "../../redux/store/store"; +import { toast } from "sonner"; +import { + CustomIconButton, + CustomTextField, +} from "../AddEditUserModel/styled.css.tsx"; + +export default function AddBookingModal({ + open, + handleClose, +}: { + open: boolean; + handleClose: () => void; +}) { + const dispatch = useDispatch(); + const { + control, + register, + handleSubmit, + formState: { errors }, + reset, + } = useForm(); + const [carNames, setCarNames] = useState([]); // To hold the car names + const [carPorts, setCarPorts] = useState([]); // To hold the car ports + + useEffect(() => { + // Fetch car names and car ports + dispatch(getCarNames()).then((response: any) => { + const fetchedCarNames = response.payload || []; + setCarNames(fetchedCarNames); + }); + + dispatch(getCarPorts()).then((response: any) => { + const fetchedCarPorts = response.payload || []; + setCarPorts(fetchedCarPorts); + }); + + // Fetch the bookings after this + dispatch(bookingList()); + }, [dispatch]); + + // Get today's date in yyyy-mm-dd format + const today = new Date().toISOString().split("T")[0]; + + const onSubmit = async (data: any) => { + const bookingData = { + stationId: data.stationId, + date: data.date, + startTime: data.startTime, + endTime: data.endTime, + carName: data.carName, + carNumber: data.carNumber, + carPort: data.carPort, + }; + + try { + await dispatch(addBooking(bookingData)); + dispatch(bookingList()); + handleClose(); // Close modal after successful addition + reset(); // Reset form fields + } catch (error) { + console.error("Error adding booking:", error); + toast.error("Failed to add booking."); + } + }; + + return ( + { + if (reason === "backdropClick") return; + handleClose(); + }} + aria-labelledby="add-booking-modal" + > + + + + Add Booking + + + + + + + +
+ {/* Station ID and Car Name */} + + {/* Station ID */} + + + Station ID + + + + + + Date + + + value >= today || + "Date cannot be in the past", + })} + InputLabelProps={{ + shrink: true, + }} + // Setting minimum date to today + inputProps={{ min: today }} + /> + + + + {/* Car Port and Date */} + + {/* Car Name */} + + + Car Name + + ( + + Car Name + + {errors.carName && ( + + {errors.carName.message} + + )} + + )} + rules={{ required: "Car Name is required" }} + /> + + {/* Car Port */} + + + Car Port + + ( + + Car Port + + {errors.carPort && ( + + {errors.carPort.message} + + )} + + )} + rules={{ required: "Car Port is required" }} + /> + + + + {/* Start Time and End Time */} + + {/* Start Time */} + + + Start Time + + + + + {/* End Time */} + + + End Time + + + + + + {/* Car Number */} + + + + Car Number + + + + + + {/* Submit Button */} + + + +
+
+
+ ); +} diff --git a/src/components/AddEditUserModel/index.tsx b/src/components/AddEditUserModel/index.tsx index 1a84146..712b1f4 100644 --- a/src/components/AddEditUserModel/index.tsx +++ b/src/components/AddEditUserModel/index.tsx @@ -378,7 +378,5 @@ const AddUserModal: React.FC = ({ export default AddUserModal; -function setValue(arg0: string, name: any) { - throw new Error("Function not implemented."); -} + diff --git a/src/components/AddSlotModal/index.tsx b/src/components/AddSlotModal/index.tsx new file mode 100644 index 0000000..7eef16f --- /dev/null +++ b/src/components/AddSlotModal/index.tsx @@ -0,0 +1,130 @@ +import React, { useState } from "react"; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Button, + TextField, + Typography, + Box, +} from "@mui/material"; +import { useForm } from "react-hook-form"; + +const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => { + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm(); + const [isAvailable, setIsAvailable] = useState(true); // Default is available + + // Get today's date in the format yyyy-mm-dd + const today = new Date().toISOString().split("T")[0]; + + const onSubmit = (data: { + date: string; + startHour: string; + endHour: string; + }) => { + handleAddSlot({ ...data, isAvailable }); + reset(); + handleClose(); + }; + + return ( + + Add EV Slot + +
+ + value >= today || "Date cannot be in the past", + })} + label="Date" + type="date" + fullWidth + margin="normal" + InputLabelProps={{ + shrink: true, + }} + error={!!errors.date} + helperText={errors.date?.message} + // Set the min value to today's date + inputProps={{ min: today }} + /> + + + {/* Availability Toggle */} + + + + {isAvailable ? "Available" : "Not Available"} + + + + + + + + + +
+
+ ); +}; + +export default AddSlotModal; diff --git a/src/components/CustomTable/index.tsx b/src/components/CustomTable/index.tsx index 75acf87..2090518 100644 --- a/src/components/CustomTable/index.tsx +++ b/src/components/CustomTable/index.tsx @@ -11,7 +11,7 @@ import { adminList, deleteAdmin } from "../../redux/slices/adminSlice"; import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice"; import { deleteManager, managerList } from "../../redux/slices/managerSlice"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { Box, Button, @@ -24,7 +24,7 @@ import { } from "@mui/material"; import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded"; import DeleteModal from "../Modals/DeleteModal"; -import { AppDispatch } from "../../redux/store/store"; +import { AppDispatch, RootState } from "../../redux/store/store"; import ViewModal from "../Modals/ViewModal"; import VehicleViewModal from "../Modals/VehicleViewModal"; @@ -36,6 +36,11 @@ 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 { + deleteSlot, + fetchAvailableSlots, +} from "../../redux/slices/slotSlice.ts"; +import { bookingList } from "../../redux/slices/bookSlice.ts"; // Styled components for customization const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -103,21 +108,16 @@ const CustomTable: React.FC = ({ const [searchQuery, setSearchQuery] = React.useState(""); const [currentPage, setCurrentPage] = React.useState(1); const usersPerPage = 10; - + const { user, isLoading } = useSelector( + (state: RootState) => state?.profileReducer + ); const open = Boolean(anchorEl); - + console.log("Rows", rows); const handleClick = (event: React.MouseEvent, row: Row) => { setAnchorEl(event.currentTarget); setSelectedRow(row); setRowData(row); }; - // const handleViewButton = (id: string | undefined) => { - // if (!id) { - // console.error("ID not found for viewing."); - // return; - // } - // setViewModal(true); - // }; const handleClose = () => { setAnchorEl(null); @@ -131,9 +131,13 @@ const CustomTable: React.FC = ({ }; const handleDeleteButton = (id: string | undefined) => { - if (!id) console.error("ID not found", id); + if (!id) { + console.error("ID not found", id); + return; + } switch (tableType) { + case "admin": dispatch(deleteAdmin(id || "")); break; @@ -149,6 +153,9 @@ const CustomTable: React.FC = ({ case "station": dispatch(deleteStation(id || "")); break; + case "slots": + dispatch(deleteSlot(id || "")); + break; default: console.error("Unknown table type:", tableType); return; @@ -159,23 +166,29 @@ 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 "booking": + dispatch(bookingList()); + break; + case "slots": + dispatch(fetchAvailableSlots()); + break; + default: + console.error("Unknown table type:", tableType); + return; + } setViewModal(false); }; @@ -238,6 +251,10 @@ const CustomTable: React.FC = ({ ? "Vehicles" : tableType === "station" ? "Charging Station" + : tableType === "booking" + ? "Booking" + : tableType === "slots" + ? "Slot" : "List"} @@ -288,31 +305,37 @@ const CustomTable: React.FC = ({ width: "100%", }} > - + {!(user?.userType === "user" && tableType === "slots") && ( + + )}