diff --git a/src/components/AddManagerStationModal/addmanagerStationModal.tsx b/src/components/AddManagerStationModal/addmanagerStationModal.tsx index 671ce82..ece8e23 100644 --- a/src/components/AddManagerStationModal/addmanagerStationModal.tsx +++ b/src/components/AddManagerStationModal/addmanagerStationModal.tsx @@ -23,16 +23,16 @@ const AddManagerStationModal = ({ open, handleClose }: any) => { formState: { errors }, } = useForm(); - const [isAvailable, setIsAvailable] = useState(true); + const [available, setavailable] = useState(true); const onSubmit = (data: any) => { const { connectorType, power, price } = data; const payload = { connectorType, - power, + power, price, - isAvailable, + available, }; dispatch(addStationDetails(payload)); @@ -128,11 +128,11 @@ const AddManagerStationModal = ({ open, handleClose }: any) => { setIsAvailable((prev) => !prev)} + checked={available} + onChange={() => setavailable((prev) => !prev)} /> } - label={isAvailable ? "Available" : "Not Available"} + label={available ? "Available" : "Not Available"} sx={{ mt: 2 }} /> diff --git a/src/components/CustomTable/customTable.tsx b/src/components/CustomTable/customTable.tsx index 09a3e17..1ad9980 100644 --- a/src/components/CustomTable/customTable.tsx +++ b/src/components/CustomTable/customTable.tsx @@ -106,6 +106,7 @@ interface CustomTableProps { handleStatusToggle?: (id: string, currentStatus: number) => void; tableType: string; // Adding tableType prop to change header text dynamically handleClickOpen?: () => void; + } const CustomTable: React.FC = ({ diff --git a/src/components/EditManagerStationModal/editManagerStationModal.tsx b/src/components/EditManagerStationModal/editManagerStationModal.tsx index 061c1f5..2507a40 100644 --- a/src/components/EditManagerStationModal/editManagerStationModal.tsx +++ b/src/components/EditManagerStationModal/editManagerStationModal.tsx @@ -5,31 +5,34 @@ import { Typography, Modal, CircularProgress, + FormControlLabel, + Switch, } from "@mui/material"; import CloseIcon from "@mui/icons-material/Close"; import { useForm, Controller } from "react-hook-form"; import { useDispatch } from "react-redux"; import { - updateSlot, - fetchManagersSlots, -} from "../../redux/slices/slotSlice.ts"; // Update with correct action -import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components -import { AppDispatch } from "../../redux/store/store.ts"; + updateStationDetails, + stationDetailList, +} from "../../redux/slices/managerStationSlice"; // <-- Update path if needed +import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; +import { AppDispatch } from "../../redux/store/store"; +import { toast } from "sonner"; -// Defining props for the modal -interface EditManagerStationModalProp { +interface EditStationModalProps { open: boolean; handleClose: () => void; editRow: any; // Slot data including id } interface FormData { - startTime: string; - endTime: string; - isAvailable: boolean; + connectorType: string; + power: number; // Changed to number + price: number; // Changed to number + available: boolean; } -const EditSlotModal: React.FC = ({ +const EditManagerStationModal: React.FC = ({ open, handleClose, editRow, @@ -43,57 +46,56 @@ const EditSlotModal: React.FC = ({ reset, } = useForm({ defaultValues: { - startTime: "", - endTime: "", - isAvailable: false, + connectorType: "", + power: 0, // Default to 0 + price: 0, // Default to 0 + available: false, }, }); const [loading, setLoading] = useState(false); - const [isAvailable, setIsAvailable] = useState( - editRow?.isAvailable || false + const [available, setAvailable] = useState( + editRow?.available || false ); - // Effect to prepopulate the form when the modal is opened useEffect(() => { if (editRow) { - setValue("startTime", editRow.startTime); - setValue("endTime", editRow.endTime); - setIsAvailable(editRow.isAvailable); + setValue("connectorType", editRow.connectorType); + setValue("power", Number(editRow.power)); + setValue("price", Number(editRow.price)); + setAvailable(editRow.available); } else { reset(); } }, [editRow, setValue, reset]); - // Handle form submission const onSubmit = async (data: FormData) => { if (editRow) { setLoading(true); - try { - const availabilityStatus = isAvailable ? true : false; - - // Dispatching the update action to the Redux slice - await dispatch( - updateSlot({ - id: editRow.id, // Slot ID from the editRow object - startTime: data.startTime, - endTime: data.endTime, - isAvailable: availabilityStatus, + console.log("Updating station with data:", data); + const availabilityStatus = available ? true : false; + const response = await dispatch( + updateStationDetails({ + id: editRow.id, + connectorType: data.connectorType, + power: Number(data.power), + price: Number(data.price), + available: availabilityStatus, }) ).unwrap(); - // Fetch the updated slots after updating the slot - dispatch(fetchManagersSlots()); + console.log("Update response:", response); - // Close the modal after successful submission + dispatch(stationDetailList()); handleClose(); - reset(); // Reset the form + reset(); + toast.success("Station details updated successfully"); } catch (error) { - console.error("Error updating slot:", error); - // Handle error if needed (e.g., show toast notification) + console.error("Update failed", error); + toast.error("Failed to update station details"); } finally { - setLoading(false); // Stop loading state after completion + setLoading(false); } } }; @@ -102,12 +104,10 @@ const EditSlotModal: React.FC = ({ { - if (reason === "backdropClick") { - return; - } - handleClose(); // Close modal when clicking cross or cancel + if (reason === "backdropClick") return; + handleClose(); }} - aria-labelledby="edit-slot-modal" + aria-labelledby="edit-station-modal" > = ({ alignItems: "center", }} > - - Edit Slot + + Edit Station Details - {/* Horizontal Line */} {/* Input Fields */} - {/* Start Time */} - + {/* Connector Type */} + - Start Time + Connector Type ( )} /> - {/* End Time */} + {/* Power */} - End Time + Power ( )} /> - {/* Availability Toggle */} + {/* Price */} + + + Price + + ( + + )} + /> + + + {/* Available Toggle */} - + { + const toggle = !available; + setAvailable(toggle); + setValue("available", toggle); + }} + /> + } + label={available ? "Available" : "Not Available"} + sx={{ mt: 1 }} + /> @@ -225,12 +247,12 @@ const EditSlotModal: React.FC = ({ width: "117px", "&:hover": { backgroundColor: "#439BC1" }, }} - disabled={loading} // Disable the button during loading state + disabled={loading} > {loading ? ( ) : ( - "Update Slot" + "Update" )} @@ -239,4 +261,4 @@ const EditSlotModal: React.FC = ({ ); }; -export default EditSlotModal; +export default EditManagerStationModal; diff --git a/src/components/MainGrid/mainGrid.tsx b/src/components/MainGrid/mainGrid.tsx index 444aead..1bcd4af 100644 --- a/src/components/MainGrid/mainGrid.tsx +++ b/src/components/MainGrid/mainGrid.tsx @@ -46,13 +46,19 @@ export default function MainGrid() { {/* Dashboard Header */} - + Dashboard diff --git a/src/components/SlotPickerModal/slotPickerModal.tsx b/src/components/SlotPickerModal/slotPickerModal.tsx new file mode 100644 index 0000000..a3869ee --- /dev/null +++ b/src/components/SlotPickerModal/slotPickerModal.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import { + Box, + Button, + Dialog, + DialogTitle, + DialogContent, + Tabs, + Tab, + Typography, +} from "@mui/material"; + +import { useSelector } from "react-redux"; +import { RootState } from "../../redux/reducers"; +type Slot = { + id: string; + startTime: string; + endTime: string; + isAvailable?: boolean; +}; + +interface SlotPickerModalProps { + open: boolean; + handleClose: () => void; + selectedSlotId: string | null; + onSelect: (slot: Slot) => any; +} + + +export default function SlotPickerModal({ + open, + handleClose, + + selectedSlotId, + onSelect, +}: SlotPickerModalProps) { + const availableSlots = useSelector( + (state: RootState) => state.slotReducer.availableSlots || [] + ); +// eslint-disable-next-line @typescript-eslint/no-redeclare + + + + return ( + + Select a Time Slot + + + {availableSlots.map((slot) => { + const isDisabled = !slot?.isAvailable; + const label = `${slot?.startTime} - ${slot?.endTime}`; + return ( + + ); + })} + + + + ); +} diff --git a/src/pages/ManagerStationDetails/index.tsx b/src/pages/ManagerStationDetails/index.tsx index 5a3ada1..c7a32cf 100644 --- a/src/pages/ManagerStationDetails/index.tsx +++ b/src/pages/ManagerStationDetails/index.tsx @@ -1,14 +1,7 @@ import { useEffect, useState } from "react"; import CustomTable, { Column } from "../../components/CustomTable/customTable"; -import AddManagerModal from "../../components/AddManagerModal/addManagerModal"; -import EditManagerModal from "../../components/EditManagerModal/editManagerModal"; import { useDispatch, useSelector } from "react-redux"; import { RootState, AppDispatch } from "../../redux/store/store"; -import { - managerList, - addManager, - updateManager, -} from "../../redux/slices/managerSlice"; import { useForm } from "react-hook-form"; import { addStationDetails, @@ -22,12 +15,11 @@ export default function ManagerStationDetails() { const [addModalOpen, setAddModalOpen] = useState(false); const [editModalOpen, setEditModalOpen] = useState(false); const { reset } = useForm(); - const [deleteModal, setDeleteModal] = useState(false); const [viewModal, setViewModal] = useState(false); const [rowData, setRowData] = useState(null); const dispatch = useDispatch(); - const managerStationDetails = useSelector( + const stationDetails = useSelector( (state: RootState) => state.managerStationReducer.stationDetails ); @@ -47,75 +39,79 @@ export default function ManagerStationDetails() { reset(); }; - const handleAddManager = async (data: { + const handleAddStationDetails = async (data: { stationId: string; connectorType: string; - power: string; - price: string; + power: number; + price: number; + available: boolean; }) => { try { - // Add manager with stationId - await dispatch(addStationDetails(data)); // Dispatch action to add manager - await dispatch(stationDetailList()); // Fetch the updated list - handleCloseModal(); // Close the modal + await dispatch(addStationDetails(data)); + await dispatch(stationDetailList()); // Fetch updated station list + handleCloseModal(); // Close modal } catch (error) { console.error("Error adding manager", error); } }; - // Handle updating an existing manager const handleUpdate = async ( id: number, connectorType: string, - power: string, - price: string + power: number, + price: number, + available: boolean ) => { try { + console.log("Updating station with data:", { id, connectorType, power, price, available }) + + if (!id) { + console.error("Error: id is missing!"); + return; + } await dispatch( updateStationDetails({ id, connectorType, power, price, - isAvailable: false, + available, }) - ); - await dispatch(stationDetailList()); - handleCloseModal(); + ).unwrap(); + await dispatch(stationDetailList()); // Fetch updated station list + handleCloseModal(); // Close modal } catch (error) { console.error("Update failed", error); } }; + // Columns for the table const categoryColumns: Column[] = [ { id: "srno", label: "Sr No" }, { id: "stationName", label: "Station Name" }, - { id: "registeredAddress", label: "Station Location" }, + { id: "stationAddress", label: "Station Location" }, { id: "connectorType", label: "Connector Type" }, { id: "power", label: "Max Power(KW)" }, { id: "price", label: "Price" }, - { id: "isAvailable", label: "Is Available", align: "center" }, - { id: "action", label: "Action", align: "center" }, + { id: "available", label: "Is Available", align: "center" }, + { id: "action", label: "Action", align: "center" }, // Action column for Edit and Delete ]; - const categoryRows = managerStationDetails?.length - ? managerStationDetails.map((managerStation, index) => { - return { - id: managerStation.id, - srno: index + 1, - stationName: managerStation?.stationName ?? "NA", - registeredAddress: managerStation.registeredAddress, - connectorType: managerStation.connectorType, - power: managerStation.power, - price: managerStation.price ?? "NA", - isAvailable: managerStation?.isAvailable ? "Yes" : "No", - }; - }) - : []; + // Rows for the table + const categoryRows = stationDetails.map((station, index) => ({ + ...station, // Include all station properties + srno: index + 1, + stationName: station.stationName ?? "NA", + stationAddress: station.stationAddress ?? "NA", + connectorType: station.connectorType ?? "NA", + power: station.power ?? "NA", + price: station.price ?? "NA", + available: station.available ? "Yes" : "No", + })); return ( <> - {/* Custom Table to show manager list */} + {/* Custom Table to show station details */} setEditModalOpen(true)} + setModalOpen={() => setEditModalOpen(true)} // Open edit modal when row is clicked tableType="manager-station" - handleClickOpen={handleClickOpen} + handleClickOpen={handleClickOpen} // Open add modal /> - {/* Add Manager Modal */} + + {/* Add Manager Station Modal */} - {/* Edit Manager Modal */} + + {/* Edit Manager Station Modal */} ); diff --git a/src/redux/slices/managerStationSlice.ts b/src/redux/slices/managerStationSlice.ts index 528a5e5..1c32574 100644 --- a/src/redux/slices/managerStationSlice.ts +++ b/src/redux/slices/managerStationSlice.ts @@ -1,17 +1,16 @@ import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; import http from "../../lib/https"; import { toast } from "sonner"; - - - interface StationDetails { - id: number; + stationAddress: string; stationName: string; - registeredAddress: string; + id: number; + managerId?: number; + stationId?: number; connectorType: string; - power: string; - price: string; - isAvailable: boolean; + power: number; + price: number; + available: boolean; } interface StationDetailState { @@ -20,7 +19,6 @@ interface StationDetailState { error: string | null; } -// Initial state const initialState: StationDetailState = { stationDetails: [], loading: false, @@ -37,11 +35,11 @@ export const stationDetailList = createAsyncThunk< const token = localStorage?.getItem("authToken"); if (!token) throw new Error("No token found"); - const response = await http.get("/manager-station-details"); + const response = await http.get("/get-station-details"); if (!response.data?.data) throw new Error("Invalid API response"); return response.data.data; } catch (error: any) { - toast.error("Error Fetching Managers: " + error.message); + toast.error("Error Fetching Station Details: " + error.message); return rejectWithValue( error?.response?.data?.message || "An error occurred" ); @@ -53,21 +51,20 @@ export const addStationDetails = createAsyncThunk< StationDetails, { connectorType: string; - power: string; - price: string; - isAvailable: boolean; + power: number; // Changed to number + price: number; // Changed to number + available: boolean; }, { rejectValue: string } >("addManager", async (data, { rejectWithValue }) => { try { - const response = await http.post( - "create-manager-station-details", - data - ); + const response = await http.post("add-station-details", data); toast.success("Station details created successfully"); return response.data?.data; } catch (error: any) { - toast.error("Error creating manager: " + error.response?.data?.message); + toast.error( + "Error creating Station details: " + error.response?.data?.message + ); return rejectWithValue( error.response?.data?.message || "An error occurred" ); @@ -80,26 +77,23 @@ export const updateStationDetails = createAsyncThunk< { id: number; connectorType: string; - power: string; - price: string; - isAvailable: boolean; + power: number; + price: number; + available: boolean; }, { rejectValue: string } >( "updateManagerStationDetails", async ({ id, ...managerStationData }, { rejectWithValue }) => { - if (!id) { - return rejectWithValue("Manager ID is required."); - } try { - const response = await http.put( - `/update-manager-station-details/${id}`, - { ...managerStationData } + const response = await http.patch( + `update-station-details/${id}`, + managerStationData ); toast.success("Station Details updated successfully"); - return response?.data; + return response.data; // Return the updated data } catch (error: any) { - toast.error("Error updating manager: " + error.message); + toast.error("Error updating station details: " + error.message); return rejectWithValue( error.response?.data?.message || "An error occurred" ); @@ -114,7 +108,7 @@ export const deleteStationDetails = createAsyncThunk< { rejectValue: string } >("deleteManager", async (id, { rejectWithValue }) => { try { - await http.delete(`/delete-manager/${id}`); + await http.delete(`remove-station-details/${id}`); toast.success("Station details deleted successfully!"); return id; } catch (error: any) { @@ -132,7 +126,7 @@ const managerStationSlice = createSlice({ reducers: {}, extraReducers: (builder) => { builder - // Fetch Managers + // Fetch Station Details .addCase(stationDetailList.pending, (state) => { state.loading = true; state.error = null; @@ -146,10 +140,11 @@ const managerStationSlice = createSlice({ ) .addCase(stationDetailList.rejected, (state, action) => { state.loading = false; - state.error = action.payload || "Failed to fetch managers"; + state.error = + action.payload || "Failed to fetch station details"; }) - // Add Station details + // Add Station Details .addCase(addStationDetails.pending, (state) => { state.loading = true; }) @@ -162,30 +157,39 @@ const managerStationSlice = createSlice({ ) .addCase(addStationDetails.rejected, (state, action) => { state.loading = false; - state.error = action.payload || "Failed to add manager"; + state.error = action.payload || "Failed to add station details"; }) - // Update Manager + // Update Station Details .addCase(updateStationDetails.pending, (state) => { state.loading = true; }) - .addCase(updateStationDetails.fulfilled, (state, action) => { - state.loading = false; - const updateStationDetail = action.payload; - const index = state.stationDetails.findIndex( - (stationDetail) => - stationDetail.id === updateStationDetail.id - ); - if (index !== -1) { - state.stationDetails[index] = updateStationDetail; // Update the manager station in the state + .addCase( + updateStationDetails.fulfilled, + (state, action: PayloadAction) => { + state.loading = false; + + // Update the station details in the array + const index = state.stationDetails.findIndex( + (station) => station.id === action.payload.id + ); + + if (index !== -1) { + // Only update the fields that have changed + state.stationDetails[index] = { + ...state.stationDetails[index], + ...action.payload, // Merge the updated fields + }; + } } - }) + ) .addCase(updateStationDetails.rejected, (state, action) => { state.loading = false; - state.error = action.payload || "Failed to update manager"; + state.error = + action.payload || "Failed to update station details"; }) - // Delete Manager + // Delete Station Details .addCase(deleteStationDetails.pending, (state) => { state.loading = true; }) @@ -198,7 +202,8 @@ const managerStationSlice = createSlice({ }) .addCase(deleteStationDetails.rejected, (state, action) => { state.loading = false; - state.error = action.payload || "Failed to delete manager"; + state.error = + action.payload || "Failed to delete station details"; }); }, }); diff --git a/src/redux/slices/slotSlice.ts b/src/redux/slices/slotSlice.ts index 9a28d2a..8fba6c0 100644 --- a/src/redux/slices/slotSlice.ts +++ b/src/redux/slices/slotSlice.ts @@ -246,7 +246,7 @@ const slotSlice = createSlice({ } } ) - + .addCase(updateSlot.rejected, (state, action) => { state.loading = false; state.error = action.payload || "Failed to update slot"; diff --git a/src/shared-theme/AppTheme.tsx b/src/shared-theme/AppTheme.tsx index 5da299e..9e7f76c 100644 --- a/src/shared-theme/AppTheme.tsx +++ b/src/shared-theme/AppTheme.tsx @@ -23,6 +23,7 @@ export default function AppTheme(props: AppThemeProps) { palette: { mode: "dark", background: { + // default: "#ECF4FA", default: "#111111", paper: "#1e1e1e", }, @@ -33,7 +34,6 @@ export default function AppTheme(props: AppThemeProps) { }, typography: { fontFamily: "Gilroy", - }, cssVariables: { colorSchemeSelector: "data-mui-color-scheme", @@ -49,7 +49,6 @@ export default function AppTheme(props: AppThemeProps) { ...surfacesCustomizations, ...themeComponents, }, - }); }, [disableCustomTheme, themeComponents]);