Booking Slots and EditModal for Availble slots Changes

This commit is contained in:
jaanvi 2025-03-26 18:40:09 +05:30
parent 4df93ec1d9
commit e96759ef3b
9 changed files with 767 additions and 229 deletions

View file

@ -27,6 +27,8 @@ import {
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx";
import { stationList } from "../../redux/slices/stationSlice.ts";
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
import dayjs from "dayjs";
export default function AddBookingModal({
open,
@ -48,8 +50,12 @@ export default function AddBookingModal({
const stations = useSelector(
(state: RootState) => state?.stationReducer.stations
);
const availableSlots = useSelector(
(state: RootState) => state.slotReducer.availableSlots
);
console.log("first", availableSlots);
useEffect(() => {
dispatch(fetchAvailableSlots());
dispatch(stationList());
}, [dispatch]);
@ -284,7 +290,7 @@ export default function AddBookingModal({
{/* Start Time and End Time */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
{/* Start Time */}
<Box sx={{ flex: 1 }}>
<Typography variant="body2" fontWeight={500}>
Start Time
@ -305,7 +311,7 @@ export default function AddBookingModal({
/>
</Box>
{/* End Time */}
<Box sx={{ flex: 1 }}>
<Typography variant="body2" fontWeight={500}>
End Time
@ -346,6 +352,114 @@ export default function AddBookingModal({
})}
/>
</Box>
{/* <Box sx={{ flex: 1 }}>
<Typography variant="body2" fontWeight={500}>
{" Time Slot "}
</Typography>
<Controller
control={control}
name="timeSlot"
render={({ field }) => (
<FormControl
fullWidth
size="small"
error={!!errors.timeSlot}
>
<InputLabel>
Select Time Slot
</InputLabel>
<Select
{...field}
label="Time Slot"
multiple // Allow multiple selections
value={field.value || []} // Ensure the value is an array, even if it's empty
onChange={(e) =>
field.onChange(e.target.value)
} // Ensure the selected value is updated properly
>
{availableSlots.map(
(slot, index) => {
const start = dayjs(
slot.startTime
);
const end = dayjs(
slot.endTime
);
// Function to generate half-hour time slots between start and end time
const generateHalfHourSlots =
(
startTime: dayjs.Dayjs,
endTime: dayjs.Dayjs
) => {
const slots = [];
let currentTime =
startTime;
while (
currentTime.isBefore(
endTime
)
) {
const nextTime =
currentTime.add(
30,
"minute"
);
slots.push({
id: `${currentTime.format(
"HH:mm"
)}-${nextTime.format(
"HH:mm"
)}`,
label: `${currentTime.format(
"hh:mm A"
)} - ${nextTime.format(
"hh:mm A"
)}`,
});
currentTime =
nextTime;
}
return slots;
};
// Generate half-hour slots for the current available slot
const halfHourSlots =
generateHalfHourSlots(
start,
end
);
return halfHourSlots.map(
(slot, slotIndex) => (
<MenuItem
key={`${index}-${slotIndex}`}
value={slot.id}
>
{slot.label}
</MenuItem>
)
);
}
)}
</Select>
{errors.timeSlot && (
<Typography
color="error"
variant="body2"
sx={{ mt: 1 }}
>
{errors.timeSlot.message}
</Typography>
)}
</FormControl>
)}
rules={{ required: "Time Slot is required" }}
/>
</Box> */}
</Box>
{/* Submit Button */}

View file

@ -16,7 +16,10 @@ import CloseIcon from "@mui/icons-material/Close";
import { useSelector, useDispatch } from "react-redux";
import { useEffect, useState } from "react";
import { RootState } from "../../redux/reducers.ts";
import { vehicleList } from "../../redux/slices/VehicleSlice"; // Adjust this import path accordingly
import {
fetchVehicleBrands,
vehicleList,
} from "../../redux/slices/VehicleSlice"; // Adjust this import path accordingly
import {
CustomIconButton,
CustomTextField,
@ -40,10 +43,18 @@ export default function AddStationModal({
const vehicles = useSelector(
(state: RootState) => state.vehicleReducer.vehicles
); // Adjust according to your actual state structure
const vehicleBrands = useSelector(
(state: RootState) => state.vehicleReducer.vehicleBrands
);
const [selectedBrand, setSelectedBrand] = useState<string | "">("");
useEffect(() => {
dispatch(fetchVehicleBrands());
dispatch(vehicleList()); // Fetch vehicles when the component mounts
}, [dispatch]);
const filteredVehicles = vehicles.filter(
(vehicle) => vehicle.company === selectedBrand
);
const [selectedVehicles, setSelectedVehicles] = useState<string[]>([]);
@ -57,26 +68,36 @@ export default function AddStationModal({
// Function to map selected vehicle names to corresponding vehicle ids
const getVehicleIds = () => {
console.log("Selected Vehicles: ", selectedVehicles);
console.log("Vehicles List: ", vehicles);
return vehicles
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
.map((vehicle) => vehicle.id); // Return an array of ids based on the selected names
.map((vehicle) => vehicle.id);
};
const onSubmit = (data: any) => {
// Log the data before sending to backend
console.log("Payload being sent to hfgghfhbackend:", data);
const vehicleIds = getVehicleIds(); // Get the ids of the selected vehicles
console.log("Vehicle IDs: ", vehicleIds);
// Prepare the data to be sent to the backend
const payload = {
...data,
status: 1, // Default status, can be adjusted if needed
allowedCarIds: vehicleIds, // Pass the vehicle ids to the backend
totalSlots: Number(data.totalSlots), // Ensure this is a number
};
console.log("Payload to backend:", payload); // Log the final payload
// Handle adding the station with the constructed payload
handleAddStation(payload);
handleClose(); // Close modal after adding
reset();
setSelectedVehicles([]); // Reset selected vehicles after submission
setSelectedVehicles([]);
setSelectedBrand(""); // Reset selected vehicles after submission
};
return (
@ -231,50 +252,103 @@ export default function AddStationModal({
</Box>
{/* Vehicle Name Dropdown with Checkboxes */}
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Vehicle Name
</Typography>
<Box sx={{ display: "flex", gap: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Select Vehicle Brand
</Typography>
<FormControl fullWidth>
<InputLabel>Choose Brand</InputLabel>
<Select
value={selectedBrand}
onChange={(e) =>
setSelectedBrand(e.target.value)
}
label="Choose Brand"
>
{Array.isArray(vehicleBrands) &&
vehicleBrands.length > 0 ? (
vehicleBrands.map((brand) => (
<MenuItem
key={brand.id}
value={brand.id}
>
{brand.name}{" "}
{/* Make sure 'brand.id' is set as value */}
</MenuItem>
))
) : (
<MenuItem disabled>
No vehicle brands available
</MenuItem>
)}
</Select>
<FormHelperText>
{errors.vehicleBrand
? errors.vehicleBrand.message
: ""}
</FormHelperText>
</FormControl>
</Box>
{/* Dropdown with Checkboxes */}
<FormControl fullWidth>
<InputLabel>Choose Vehicles</InputLabel>
<Select
multiple
value={selectedVehicles}
onChange={handleCheckboxChange}
renderValue={(selected) =>
(selected as string[]).join(", ")
}
>
{vehicles?.map((vehicle) => (
<MenuItem
key={vehicle.id}
value={vehicle.name}
>
<Checkbox
checked={selectedVehicles.includes(
vehicle.name
)}
/>
<ListItemText
primary={vehicle.name}
/>
</MenuItem>
))}
</Select>
<FormHelperText>
{errors.vehicleName
? errors.vehicleName.message
: ""}
</FormHelperText>
</FormControl>
{/* Vehicle Name Dropdown with Checkboxes */}
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Vehicle Name
</Typography>
<FormControl fullWidth>
<InputLabel>Choose Vehicles</InputLabel>
<Select
multiple
value={selectedVehicles}
onChange={handleCheckboxChange}
renderValue={(selected) =>
(selected as string[]).join(", ")
}
>
{filteredVehicles.length > 0 ? (
filteredVehicles.map((vehicle) => (
<MenuItem
key={vehicle.id}
value={vehicle.name}
>
<Checkbox
checked={selectedVehicles.includes(
vehicle.name
)}
/>
<ListItemText
primary={vehicle.name}
/>
</MenuItem>
))
) : (
<MenuItem disabled>
No vehicles available for this
brand
</MenuItem>
)}
</Select>
<FormHelperText>
{errors.vehicleName
? errors.vehicleName.message
: ""}
</FormHelperText>
</FormControl>
</Box>
</Box>
</Box>
@ -303,4 +377,4 @@ export default function AddStationModal({
</Box>
</Modal>
);
}
}

View file

@ -108,7 +108,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
const [searchQuery, setSearchQuery] = React.useState("");
const [currentPage, setCurrentPage] = React.useState(1);
const usersPerPage = 10;
const { user, isLoading } = useSelector(
const { user, isLoading } = useSelector(
(state: RootState) => state?.profileReducer
);
const open = Boolean(anchorEl);
@ -137,7 +137,6 @@ const CustomTable: React.FC<CustomTableProps> = ({
}
switch (tableType) {
case "admin":
dispatch(deleteAdmin(id || ""));
break;
@ -484,168 +483,175 @@ const CustomTable: React.FC<CustomTableProps> = ({
/>
</Box>
{/* Menu Actions */}
{open && (
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
sx={{
[`& .${paperClasses.root}`]: {
padding: 0,
},
"& .MuiList-root": {
background: "#272727", // Remove any divider under menu items
},
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
}}
>
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
// setSelectedRow(row);
setViewModal(true);
{open &&
(
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
onClick={handleClose}
transformOrigin={{
horizontal: "right",
vertical: "top",
}}
anchorOrigin={{
horizontal: "right",
vertical: "bottom",
}}
color="primary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
color: "#52ACDF",
[`& .${paperClasses.root}`]: {
padding: 0,
},
"& .MuiList-root": {
background: "#272727", // Remove any divider under menu items
},
}}
>
View
</Button>
{viewModal && tableType === "admin" && (
<ViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "vehicle" && (
<VehicleViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "manager" && (
<ManagerViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "user" && (
<UserViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "station" && (
<StationViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
<Button
variant="text"
onClick={() => setModalOpen(true)}
color="primary"
sx={{
justifyContent: "flex-start",
py: 0,
textTransform: "capitalize",
}}
>
Edit
</Button>
{tableType === "role" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1
? "Deactivate"
: "Activate"}
</Button>
)}
{tableType === "station" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1
? "Not Available"
: "Available"}
</Button>
)}
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
// setSelectedRow(row);
setViewModal(true);
}}
color="primary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
color: "#52ACDF",
}}
>
View
</Button>
{viewModal && tableType === "admin" && (
<ViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "vehicle" && (
<VehicleViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "manager" && (
<ManagerViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "user" && (
<UserViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "station" && (
<StationViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
setDeleteModal(true);
}}
color="error"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
Delete
</Button>
</Box>
</Menu>
)}
<Button
variant="text"
onClick={() => setModalOpen(true)}
color="primary"
sx={{
justifyContent: "flex-start",
py: 0,
textTransform: "capitalize",
}}
>
Edit
</Button>
{tableType === "role" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1
? "Deactivate"
: "Activate"}
</Button>
)}
{tableType === "station" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1
? "Not Available"
: "Available"}
</Button>
)}
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
setDeleteModal(true);
}}
color="error"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
Delete
</Button>
</Box>
</Menu>
)}
{/* Modals */}
{deleteModal && (
<DeleteModal

View file

@ -74,7 +74,9 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
email: data.email,
phone: data.phone,
stationId: data.stationId,
Manager: undefined,
id: 0,
chargingStation: ""
},
})
).unwrap(); // Ensure that it throws an error if the update fails

View file

@ -0,0 +1,263 @@
import React, { useEffect, useState } from "react";
import {
Box,
Button,
Typography,
Modal,
CircularProgress,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useForm, Controller } from "react-hook-form";
import { useDispatch } from "react-redux";
import { updateSlot, fetchAvailableSlots } from "../../redux/slices/slotSlice"; // Update with correct action
import {
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; // Custom styled components
interface EditSlotModalProps {
open: boolean;
handleClose: () => void;
editRow: any; // Slot data including id
}
interface FormData {
date: string;
startTime: string;
endTime: string;
isAvailable: boolean;
}
const EditSlotModal: React.FC<EditSlotModalProps> = ({
open,
handleClose,
editRow,
}) => {
const dispatch = useDispatch(); // Use dispatch to send Redux actions
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>({
defaultValues: {
date: "",
startTime: "",
endTime: "",
isAvailable: false,
},
});
const [loading, setLoading] = useState(false);
const [isAvailable, setIsAvailable] = useState<boolean>(
editRow?.isAvailable || false
); // Default to editRow availability
// Set values if editRow is provided
useEffect(() => {
if (editRow) {
setValue("date", editRow.date);
setValue("startTime", editRow.startTime);
setValue("endTime", editRow.endTime);
setIsAvailable(editRow.isAvailable); // Set the initial availability correctly
} else {
reset();
}
}, [editRow, setValue, reset]);
const onSubmit = async (data: FormData) => {
if (editRow) {
try {
// Convert boolean availability to 1/0
const availabilityStatus = isAvailable ? true : false;
await dispatch(
updateSlot({
id: editRow.id, // Slot ID
slotData: {
date: data.date,
startTime: data.startTime,
endTime: data.endTime,
isAvailable: availabilityStatus,
},
})
).unwrap(); // Ensure that it throws an error if the update fails
dispatch(fetchAvailableSlots()); // Assuming this action fetches the updated slot list
handleClose(); // Close modal on success
reset(); // Reset form fields after submit
} catch (error) {
console.error(error);
// Handle the error or show a toast
} finally {
setLoading(false); // Stop loading state
}
}
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
}
handleClose(); // Close modal when clicking cross or cancel
}}
aria-labelledby="edit-slot-modal"
>
<Box
component="form"
onSubmit={handleSubmit(onSubmit)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
Edit Slot
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Input Fields */}
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
{/* Date */}
<Box sx={{ flex: "1 1 100%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Date
</Typography>
<Controller
name="date"
control={control}
rules={{ required: "Date is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="date"
fullWidth
size="small"
error={!!errors.date}
helperText={errors.date?.message}
/>
)}
/>
</Box>
{/* Start Time */}
<Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Start Time
</Typography>
<Controller
name="startTime"
control={control}
rules={{ required: "Start Time is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="time"
fullWidth
size="small"
error={!!errors.startTime}
helperText={errors.startTime?.message}
/>
)}
/>
</Box>
{/* End Time */}
<Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
End Time
</Typography>
<Controller
name="endTime"
control={control}
rules={{ required: "End Time is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="time"
fullWidth
size="small"
error={!!errors.endTime}
helperText={errors.endTime?.message}
/>
)}
/>
</Box>
{/* Availability Toggle */}
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
gap={2}
sx={{ flex: "1 1 100%" }}
>
<Button
onClick={() => {
const newAvailability = !isAvailable;
setIsAvailable(newAvailability); // Update local state
setValue("isAvailable", newAvailability); // Update form value for isAvailable
}}
variant={isAvailable ? "contained" : "outlined"}
color="primary"
>
{isAvailable ? "Available" : "Not Available"}
</Button>
<Typography>
{isAvailable ? "Available" : "Not Available"}
</Typography>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
disabled={loading} // Disable the button during loading state
>
{loading ? (
<CircularProgress size={24} color="inherit" />
) : (
"Update Slot"
)}
</Button>
</Box>
</Box>
</Modal>
);
};
export default EditSlotModal;

View file

@ -15,8 +15,8 @@ http.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
// window.location.href = "/login";
if (error.response && error.response.status === 403 ) {
window.location.href = "/login";
// const history = useHistory();
// history.push("/login");

View file

@ -4,9 +4,15 @@ import CustomTable, { Column } from "../../components/CustomTable";
import { useDispatch, useSelector } from "react-redux";
import { RootState, AppDispatch } from "../../redux/store/store";
import { useForm } from "react-hook-form";
import { createSlot, fetchAvailableSlots } from "../../redux/slices/slotSlice";
import {
createSlot,
fetchAvailableSlots,
updateSlot,
} from "../../redux/slices/slotSlice";
import AddSlotModal from "../../components/AddSlotModal";
import dayjs from "dayjs";
import EditManagerModal from "../../components/EditManagerModal";
import EditSlotModal from "../../components/EditSlotModal";
export default function EVSlotList() {
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
@ -50,6 +56,31 @@ export default function EVSlotList() {
console.error("Error adding slot", error);
}
};
console.log("isAvailable type:", typeof isAvailable);
const handleUpdate = async (
id: string,
date: string,
startTime: string,
endTime: string,
isAvailable: boolean
) => {
try {
// Update manager with stationId
await dispatch(
updateSlot({
id,
date,
startTime,
endTime,
isAvailable,
})
);
await dispatch(fetchAvailableSlots()); // Refresh the list after update
handleCloseModal(); // Close modal after update
} catch (error) {
console.error("Update failed", error);
}
};
const slotColumns: Column[] = [
{ id: "srno", label: "Sr No" },
@ -66,25 +97,23 @@ export default function EVSlotList() {
const slotRows = availableSlots?.length
? availableSlots.map((slot, index) => {
const formattedDate = dayjs(slot?.date).format("YYYY-MM-DD");
const startTime = dayjs(slot?.startTime).format("HH:mm");
const endTime = dayjs(slot?.endTime).format("HH:mm");
console.log("first", startTime);
return {
srno: index + 1,
id: slot?.id ?? "NA",
stationId: slot?.stationId ?? "NA",
name: slot?.ChargingStation?.name ?? "NA",
date: formattedDate ?? "NA",
startTime: startTime ?? "NA",
endTime: endTime ?? "NA",
isAvailable: slot?.isAvailable ? "Yes" : "No",
};
})
const formattedDate = dayjs(slot?.date).format("YYYY-MM-DD");
const startTime = dayjs(slot?.startTime).format("HH:mm");
const endTime = dayjs(slot?.endTime).format("HH:mm");
console.log("availability", availableSlots.isAvailable);
console.log("first", startTime);
return {
srno: index + 1,
id: slot?.id ?? "NA",
stationId: slot?.stationId ?? "NA",
name: slot?.ChargingStation?.name ?? "NA",
date: formattedDate ?? "NA",
startTime: startTime ?? "NA",
endTime: endTime ?? "NA",
isAvailable: slot?.isAvailable ? "Yes" : "No",
};
})
: [];
console.log("Rows",slotRows)
return (
<>
@ -105,6 +134,12 @@ console.log("Rows",slotRows)
handleClose={handleCloseModal}
handleAddSlot={handleAddSlot}
/>
<EditSlotModal
open={editModalOpen}
handleClose={handleCloseModal}
handleUpdate={handleUpdate}
editRow={rowData}
/>
</>
);
}

View file

@ -1,9 +1,14 @@
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import http from "../../lib/https";
import { toast } from "sonner";
interface VehicleBrand {
id: string;
company: string;
}
interface Vehicle {
id: number;
brandId: string;
id: string;
name: string;
company: string;
modelName: string;
@ -11,15 +16,36 @@ interface Vehicle {
imageUrl: string;
}
interface VehicleState {
vehicleBrands: VehicleBrand[];
vehicles: Vehicle[];
loading: boolean;
error: string | null;
}
const initialState: VehicleState = {
vehicleBrands: [],
vehicles: [],
loading: false,
error: null,
};
export const fetchVehicleBrands = createAsyncThunk<
VehicleBrand[],
void,
{ rejectValue: string }
>("vehicle/fetchVehicleBrands", async (_, { rejectWithValue }) => {
try {
const response = await http.get("/get-vehicle-brand");
if (!response.data || !Array.isArray(response.data.data)) {
throw new Error("Expected array of vehicle brands");
}
// Assuming that 'data' contains an array of objects with a 'company' field
return response.data.data.map((item: any) => ({
id: item.company, // You can use 'company' as the unique identifier
name: item.company, // The name field will be used in the dropdown
}));
} catch (error: any) {
return rejectWithValue("Failed to fetch vehicle brands");
}
});
export const vehicleList = createAsyncThunk<
Vehicle,
@ -122,6 +148,21 @@ const vehicleSlice = createSlice({
state.loading = false;
state.error = action.error.message || "Failed to fetch users";
})
.addCase(fetchVehicleBrands.pending, (state) => {
state.loading = true;
})
.addCase(
fetchVehicleBrands.fulfilled,
(state, action: PayloadAction<VehicleBrand[]>) => {
state.loading = false;
state.vehicleBrands = action.payload;
}
)
.addCase(fetchVehicleBrands.rejected, (state, action) => {
state.loading = false;
state.error =
action.payload || "Failed to fetch vehicle brands";
})
.addCase(addVehicle.pending, (state) => {
state.loading = true;
// state.error = null;

View file

@ -92,7 +92,10 @@ export const updateSlot = createAsyncThunk<
{ rejectValue: string }
>("slots/updateSlot", async ({ id, ...slotData }, { rejectWithValue }) => {
try {
const response = await http.patch(`/slots/${id}`, slotData);
const response = await http.patch(
`/update-availability/${id}`,
slotData
);
toast.success("Slot updated successfully");
return response.data.data; // Return updated slot data
} catch (error: any) {