Booking Slots and EditModal for Availble slots Changes
This commit is contained in:
parent
4df93ec1d9
commit
e96759ef3b
|
@ -27,6 +27,8 @@ import {
|
||||||
CustomTextField,
|
CustomTextField,
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
} from "../AddEditUserModel/styled.css.tsx";
|
||||||
import { stationList } from "../../redux/slices/stationSlice.ts";
|
import { stationList } from "../../redux/slices/stationSlice.ts";
|
||||||
|
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
export default function AddBookingModal({
|
export default function AddBookingModal({
|
||||||
open,
|
open,
|
||||||
|
@ -48,8 +50,12 @@ export default function AddBookingModal({
|
||||||
const stations = useSelector(
|
const stations = useSelector(
|
||||||
(state: RootState) => state?.stationReducer.stations
|
(state: RootState) => state?.stationReducer.stations
|
||||||
);
|
);
|
||||||
|
const availableSlots = useSelector(
|
||||||
|
(state: RootState) => state.slotReducer.availableSlots
|
||||||
|
);
|
||||||
|
console.log("first", availableSlots);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
dispatch(fetchAvailableSlots());
|
||||||
dispatch(stationList());
|
dispatch(stationList());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
@ -284,7 +290,7 @@ export default function AddBookingModal({
|
||||||
|
|
||||||
{/* Start Time and End Time */}
|
{/* Start Time and End Time */}
|
||||||
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||||
{/* Start Time */}
|
|
||||||
<Box sx={{ flex: 1 }}>
|
<Box sx={{ flex: 1 }}>
|
||||||
<Typography variant="body2" fontWeight={500}>
|
<Typography variant="body2" fontWeight={500}>
|
||||||
Start Time
|
Start Time
|
||||||
|
@ -305,7 +311,7 @@ export default function AddBookingModal({
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* End Time */}
|
|
||||||
<Box sx={{ flex: 1 }}>
|
<Box sx={{ flex: 1 }}>
|
||||||
<Typography variant="body2" fontWeight={500}>
|
<Typography variant="body2" fontWeight={500}>
|
||||||
End Time
|
End Time
|
||||||
|
@ -346,6 +352,114 @@ export default function AddBookingModal({
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</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>
|
</Box>
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
|
|
|
@ -16,7 +16,10 @@ import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { RootState } from "../../redux/reducers.ts";
|
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 {
|
import {
|
||||||
CustomIconButton,
|
CustomIconButton,
|
||||||
CustomTextField,
|
CustomTextField,
|
||||||
|
@ -40,10 +43,18 @@ export default function AddStationModal({
|
||||||
const vehicles = useSelector(
|
const vehicles = useSelector(
|
||||||
(state: RootState) => state.vehicleReducer.vehicles
|
(state: RootState) => state.vehicleReducer.vehicles
|
||||||
); // Adjust according to your actual state structure
|
); // Adjust according to your actual state structure
|
||||||
|
const vehicleBrands = useSelector(
|
||||||
|
(state: RootState) => state.vehicleReducer.vehicleBrands
|
||||||
|
);
|
||||||
|
const [selectedBrand, setSelectedBrand] = useState<string | "">("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
dispatch(fetchVehicleBrands());
|
||||||
dispatch(vehicleList()); // Fetch vehicles when the component mounts
|
dispatch(vehicleList()); // Fetch vehicles when the component mounts
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
const filteredVehicles = vehicles.filter(
|
||||||
|
(vehicle) => vehicle.company === selectedBrand
|
||||||
|
);
|
||||||
|
|
||||||
const [selectedVehicles, setSelectedVehicles] = useState<string[]>([]);
|
const [selectedVehicles, setSelectedVehicles] = useState<string[]>([]);
|
||||||
|
|
||||||
|
@ -57,26 +68,36 @@ export default function AddStationModal({
|
||||||
|
|
||||||
// Function to map selected vehicle names to corresponding vehicle ids
|
// Function to map selected vehicle names to corresponding vehicle ids
|
||||||
const getVehicleIds = () => {
|
const getVehicleIds = () => {
|
||||||
|
console.log("Selected Vehicles: ", selectedVehicles);
|
||||||
|
console.log("Vehicles List: ", vehicles);
|
||||||
return vehicles
|
return vehicles
|
||||||
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
|
.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) => {
|
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
|
const vehicleIds = getVehicleIds(); // Get the ids of the selected vehicles
|
||||||
|
|
||||||
|
console.log("Vehicle IDs: ", vehicleIds);
|
||||||
// Prepare the data to be sent to the backend
|
// Prepare the data to be sent to the backend
|
||||||
const payload = {
|
const payload = {
|
||||||
...data,
|
...data,
|
||||||
status: 1, // Default status, can be adjusted if needed
|
status: 1, // Default status, can be adjusted if needed
|
||||||
allowedCarIds: vehicleIds, // Pass the vehicle ids to the backend
|
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
|
// Handle adding the station with the constructed payload
|
||||||
handleAddStation(payload);
|
handleAddStation(payload);
|
||||||
handleClose(); // Close modal after adding
|
handleClose(); // Close modal after adding
|
||||||
reset();
|
reset();
|
||||||
setSelectedVehicles([]); // Reset selected vehicles after submission
|
setSelectedVehicles([]);
|
||||||
|
setSelectedBrand(""); // Reset selected vehicles after submission
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -231,50 +252,103 @@ export default function AddStationModal({
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Vehicle Name Dropdown with Checkboxes */}
|
{/* Vehicle Name Dropdown with Checkboxes */}
|
||||||
<Box
|
<Box sx={{ display: "flex", gap: 2 }}>
|
||||||
sx={{
|
<Box
|
||||||
display: "flex",
|
sx={{
|
||||||
flexDirection: "column",
|
display: "flex",
|
||||||
width: "100%",
|
flexDirection: "column",
|
||||||
}}
|
width: "100%",
|
||||||
>
|
}}
|
||||||
<Typography variant="body2" fontWeight={500}>
|
>
|
||||||
Vehicle Name
|
<Typography variant="body2" fontWeight={500}>
|
||||||
</Typography>
|
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 */}
|
{/* Vehicle Name Dropdown with Checkboxes */}
|
||||||
<FormControl fullWidth>
|
<Box
|
||||||
<InputLabel>Choose Vehicles</InputLabel>
|
sx={{
|
||||||
<Select
|
display: "flex",
|
||||||
multiple
|
flexDirection: "column",
|
||||||
value={selectedVehicles}
|
width: "100%",
|
||||||
onChange={handleCheckboxChange}
|
}}
|
||||||
renderValue={(selected) =>
|
>
|
||||||
(selected as string[]).join(", ")
|
<Typography variant="body2" fontWeight={500}>
|
||||||
}
|
Vehicle Name
|
||||||
>
|
</Typography>
|
||||||
{vehicles?.map((vehicle) => (
|
|
||||||
<MenuItem
|
<FormControl fullWidth>
|
||||||
key={vehicle.id}
|
<InputLabel>Choose Vehicles</InputLabel>
|
||||||
value={vehicle.name}
|
<Select
|
||||||
>
|
multiple
|
||||||
<Checkbox
|
value={selectedVehicles}
|
||||||
checked={selectedVehicles.includes(
|
onChange={handleCheckboxChange}
|
||||||
vehicle.name
|
renderValue={(selected) =>
|
||||||
)}
|
(selected as string[]).join(", ")
|
||||||
/>
|
}
|
||||||
<ListItemText
|
>
|
||||||
primary={vehicle.name}
|
{filteredVehicles.length > 0 ? (
|
||||||
/>
|
filteredVehicles.map((vehicle) => (
|
||||||
</MenuItem>
|
<MenuItem
|
||||||
))}
|
key={vehicle.id}
|
||||||
</Select>
|
value={vehicle.name}
|
||||||
<FormHelperText>
|
>
|
||||||
{errors.vehicleName
|
<Checkbox
|
||||||
? errors.vehicleName.message
|
checked={selectedVehicles.includes(
|
||||||
: ""}
|
vehicle.name
|
||||||
</FormHelperText>
|
)}
|
||||||
</FormControl>
|
/>
|
||||||
|
<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>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
const [searchQuery, setSearchQuery] = React.useState("");
|
const [searchQuery, setSearchQuery] = React.useState("");
|
||||||
const [currentPage, setCurrentPage] = React.useState(1);
|
const [currentPage, setCurrentPage] = React.useState(1);
|
||||||
const usersPerPage = 10;
|
const usersPerPage = 10;
|
||||||
const { user, isLoading } = useSelector(
|
const { user, isLoading } = useSelector(
|
||||||
(state: RootState) => state?.profileReducer
|
(state: RootState) => state?.profileReducer
|
||||||
);
|
);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
|
@ -137,7 +137,6 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
|
|
||||||
case "admin":
|
case "admin":
|
||||||
dispatch(deleteAdmin(id || ""));
|
dispatch(deleteAdmin(id || ""));
|
||||||
break;
|
break;
|
||||||
|
@ -484,168 +483,175 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{/* Menu Actions */}
|
{/* Menu Actions */}
|
||||||
{open && (
|
{open &&
|
||||||
<Menu
|
(
|
||||||
anchorEl={anchorEl}
|
<Menu
|
||||||
id="menu"
|
anchorEl={anchorEl}
|
||||||
open={open}
|
id="menu"
|
||||||
onClose={handleClose}
|
open={open}
|
||||||
onClick={handleClose}
|
onClose={handleClose}
|
||||||
transformOrigin={{ horizontal: "right", vertical: "top" }}
|
onClick={handleClose}
|
||||||
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
|
transformOrigin={{
|
||||||
sx={{
|
horizontal: "right",
|
||||||
[`& .${paperClasses.root}`]: {
|
vertical: "top",
|
||||||
padding: 0,
|
}}
|
||||||
},
|
anchorOrigin={{
|
||||||
"& .MuiList-root": {
|
horizontal: "right",
|
||||||
background: "#272727", // Remove any divider under menu items
|
vertical: "bottom",
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
variant="text"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
// setSelectedRow(row);
|
|
||||||
setViewModal(true);
|
|
||||||
}}
|
}}
|
||||||
color="primary"
|
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: "flex-start",
|
[`& .${paperClasses.root}`]: {
|
||||||
py: 0,
|
padding: 0,
|
||||||
fontWeight: "bold",
|
},
|
||||||
color: "#52ACDF",
|
"& .MuiList-root": {
|
||||||
|
background: "#272727", // Remove any divider under menu items
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
View
|
<Box
|
||||||
</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"
|
|
||||||
sx={{
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
py: 0,
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedRow?.statusValue === 1
|
<Button
|
||||||
? "Deactivate"
|
variant="text"
|
||||||
: "Activate"}
|
onClick={(e) => {
|
||||||
</Button>
|
e.stopPropagation();
|
||||||
)}
|
// setSelectedRow(row);
|
||||||
{tableType === "station" && (
|
setViewModal(true);
|
||||||
<Button
|
}}
|
||||||
variant="text"
|
color="primary"
|
||||||
onClick={(e) => {
|
sx={{
|
||||||
e.stopPropagation();
|
justifyContent: "flex-start",
|
||||||
handleToggleStatus();
|
py: 0,
|
||||||
}}
|
fontWeight: "bold",
|
||||||
color="secondary"
|
color: "#52ACDF",
|
||||||
sx={{
|
}}
|
||||||
justifyContent: "flex-start",
|
>
|
||||||
py: 0,
|
View
|
||||||
fontWeight: "bold",
|
</Button>
|
||||||
}}
|
{viewModal && tableType === "admin" && (
|
||||||
>
|
<ViewModal
|
||||||
{selectedRow?.statusValue === 1
|
handleView={() =>
|
||||||
? "Not Available"
|
handleViewButton(selectedRow?.id)
|
||||||
: "Available"}
|
}
|
||||||
</Button>
|
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
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={(e) => {
|
onClick={() => setModalOpen(true)}
|
||||||
e.stopPropagation();
|
color="primary"
|
||||||
setDeleteModal(true);
|
sx={{
|
||||||
}}
|
justifyContent: "flex-start",
|
||||||
color="error"
|
py: 0,
|
||||||
sx={{
|
textTransform: "capitalize",
|
||||||
justifyContent: "flex-start",
|
}}
|
||||||
py: 0,
|
>
|
||||||
fontWeight: "bold",
|
Edit
|
||||||
}}
|
</Button>
|
||||||
>
|
{tableType === "role" && (
|
||||||
Delete
|
<Button
|
||||||
</Button>
|
variant="text"
|
||||||
</Box>
|
onClick={(e) => {
|
||||||
</Menu>
|
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 */}
|
{/* Modals */}
|
||||||
{deleteModal && (
|
{deleteModal && (
|
||||||
<DeleteModal
|
<DeleteModal
|
||||||
|
|
|
@ -74,7 +74,9 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
|
||||||
email: data.email,
|
email: data.email,
|
||||||
phone: data.phone,
|
phone: data.phone,
|
||||||
stationId: data.stationId,
|
stationId: data.stationId,
|
||||||
|
Manager: undefined,
|
||||||
|
id: 0,
|
||||||
|
chargingStation: ""
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
).unwrap(); // Ensure that it throws an error if the update fails
|
).unwrap(); // Ensure that it throws an error if the update fails
|
||||||
|
|
263
src/components/EditSlotModal/index.tsx
Normal file
263
src/components/EditSlotModal/index.tsx
Normal 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;
|
|
@ -15,8 +15,8 @@ http.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
||||||
if (error.response && error.response.status === 401) {
|
if (error.response && error.response.status === 403 ) {
|
||||||
// window.location.href = "/login";
|
window.location.href = "/login";
|
||||||
|
|
||||||
// const history = useHistory();
|
// const history = useHistory();
|
||||||
// history.push("/login");
|
// history.push("/login");
|
||||||
|
|
|
@ -4,9 +4,15 @@ import CustomTable, { Column } from "../../components/CustomTable";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { RootState, AppDispatch } from "../../redux/store/store";
|
import { RootState, AppDispatch } from "../../redux/store/store";
|
||||||
import { useForm } from "react-hook-form";
|
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 AddSlotModal from "../../components/AddSlotModal";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import EditManagerModal from "../../components/EditManagerModal";
|
||||||
|
import EditSlotModal from "../../components/EditSlotModal";
|
||||||
export default function EVSlotList() {
|
export default function EVSlotList() {
|
||||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
||||||
|
@ -50,6 +56,31 @@ export default function EVSlotList() {
|
||||||
console.error("Error adding slot", error);
|
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[] = [
|
const slotColumns: Column[] = [
|
||||||
{ id: "srno", label: "Sr No" },
|
{ id: "srno", label: "Sr No" },
|
||||||
|
@ -66,25 +97,23 @@ export default function EVSlotList() {
|
||||||
|
|
||||||
const slotRows = availableSlots?.length
|
const slotRows = availableSlots?.length
|
||||||
? availableSlots.map((slot, index) => {
|
? availableSlots.map((slot, index) => {
|
||||||
const formattedDate = dayjs(slot?.date).format("YYYY-MM-DD");
|
const formattedDate = dayjs(slot?.date).format("YYYY-MM-DD");
|
||||||
const startTime = dayjs(slot?.startTime).format("HH:mm");
|
const startTime = dayjs(slot?.startTime).format("HH:mm");
|
||||||
const endTime = dayjs(slot?.endTime).format("HH:mm");
|
const endTime = dayjs(slot?.endTime).format("HH:mm");
|
||||||
|
console.log("availability", availableSlots.isAvailable);
|
||||||
console.log("first", startTime);
|
console.log("first", startTime);
|
||||||
return {
|
return {
|
||||||
srno: index + 1,
|
srno: index + 1,
|
||||||
id: slot?.id ?? "NA",
|
id: slot?.id ?? "NA",
|
||||||
stationId: slot?.stationId ?? "NA",
|
stationId: slot?.stationId ?? "NA",
|
||||||
name: slot?.ChargingStation?.name ?? "NA",
|
name: slot?.ChargingStation?.name ?? "NA",
|
||||||
date: formattedDate ?? "NA",
|
date: formattedDate ?? "NA",
|
||||||
startTime: startTime ?? "NA",
|
startTime: startTime ?? "NA",
|
||||||
endTime: endTime ?? "NA",
|
endTime: endTime ?? "NA",
|
||||||
isAvailable: slot?.isAvailable ? "Yes" : "No",
|
isAvailable: slot?.isAvailable ? "Yes" : "No",
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
console.log("Rows",slotRows)
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -105,6 +134,12 @@ console.log("Rows",slotRows)
|
||||||
handleClose={handleCloseModal}
|
handleClose={handleCloseModal}
|
||||||
handleAddSlot={handleAddSlot}
|
handleAddSlot={handleAddSlot}
|
||||||
/>
|
/>
|
||||||
|
<EditSlotModal
|
||||||
|
open={editModalOpen}
|
||||||
|
handleClose={handleCloseModal}
|
||||||
|
handleUpdate={handleUpdate}
|
||||||
|
editRow={rowData}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import http from "../../lib/https";
|
import http from "../../lib/https";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
interface VehicleBrand {
|
||||||
|
id: string;
|
||||||
|
company: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Vehicle {
|
interface Vehicle {
|
||||||
id: number;
|
brandId: string;
|
||||||
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
company: string;
|
company: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
@ -11,15 +16,36 @@ interface Vehicle {
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
}
|
}
|
||||||
interface VehicleState {
|
interface VehicleState {
|
||||||
|
vehicleBrands: VehicleBrand[];
|
||||||
vehicles: Vehicle[];
|
vehicles: Vehicle[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}
|
}
|
||||||
const initialState: VehicleState = {
|
const initialState: VehicleState = {
|
||||||
|
vehicleBrands: [],
|
||||||
vehicles: [],
|
vehicles: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
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<
|
export const vehicleList = createAsyncThunk<
|
||||||
Vehicle,
|
Vehicle,
|
||||||
|
@ -122,6 +148,21 @@ const vehicleSlice = createSlice({
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
state.error = action.error.message || "Failed to fetch users";
|
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) => {
|
.addCase(addVehicle.pending, (state) => {
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
// state.error = null;
|
// state.error = null;
|
||||||
|
|
|
@ -92,7 +92,10 @@ export const updateSlot = createAsyncThunk<
|
||||||
{ rejectValue: string }
|
{ rejectValue: string }
|
||||||
>("slots/updateSlot", async ({ id, ...slotData }, { rejectWithValue }) => {
|
>("slots/updateSlot", async ({ id, ...slotData }, { rejectWithValue }) => {
|
||||||
try {
|
try {
|
||||||
const response = await http.patch(`/slots/${id}`, slotData);
|
const response = await http.patch(
|
||||||
|
`/update-availability/${id}`,
|
||||||
|
slotData
|
||||||
|
);
|
||||||
toast.success("Slot updated successfully");
|
toast.success("Slot updated successfully");
|
||||||
return response.data.data; // Return updated slot data
|
return response.data.data; // Return updated slot data
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
Loading…
Reference in a new issue