499 lines
11 KiB
TypeScript
499 lines
11 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import {
|
|
Box,
|
|
Button,
|
|
Typography,
|
|
Modal,
|
|
FormControl,
|
|
InputLabel,
|
|
Select,
|
|
MenuItem,
|
|
Checkbox,
|
|
ListItemText,
|
|
FormHelperText,
|
|
} from "@mui/material";
|
|
import CloseIcon from "@mui/icons-material/Close";
|
|
import { useForm, Controller } from "react-hook-form";
|
|
import { useSelector, useDispatch } from "react-redux";
|
|
import { RootState } from "../../redux/reducers.ts";
|
|
import {
|
|
fetchVehicleBrands,
|
|
vehicleList,
|
|
} from "../../redux/slices/VehicleSlice";
|
|
import {
|
|
CustomIconButton,
|
|
CustomTextField,
|
|
} from "../AddUserModal/styled.css"; // Assuming custom styled components
|
|
|
|
interface FormData {
|
|
name: string;
|
|
registeredAddress: string;
|
|
totalSlots: number;
|
|
allowedCarIds: string[];
|
|
status: number;
|
|
}
|
|
|
|
interface EditStationModalProps {
|
|
open: boolean;
|
|
handleClose: () => void;
|
|
handleUpdate: (
|
|
id: string,
|
|
name: string,
|
|
registeredAddress: string,
|
|
totalSlots: number,
|
|
allowedCarIds: number[]
|
|
) => void;
|
|
editRow?: any;
|
|
}
|
|
|
|
const EditStationModal: React.FC<EditStationModalProps> = ({
|
|
open,
|
|
handleClose,
|
|
handleUpdate,
|
|
editRow,
|
|
}) => {
|
|
const {
|
|
control,
|
|
handleSubmit,
|
|
setValue,
|
|
reset,
|
|
formState: { errors },
|
|
} = useForm<FormData>({
|
|
defaultValues: {
|
|
name: "",
|
|
registeredAddress: "",
|
|
totalSlots: 0,
|
|
status: 1,
|
|
allowedCarIds: [],
|
|
},
|
|
});
|
|
|
|
const dispatch = useDispatch();
|
|
const vehicles = useSelector(
|
|
(state: RootState) => state.vehicleReducer.vehicles
|
|
);
|
|
const vehicleBrands = useSelector(
|
|
(state: RootState) => state.vehicleReducer.vehicleBrands
|
|
);
|
|
|
|
const [selectedBrands, setSelectedBrands] = useState<string[]>([]);
|
|
const [selectedVehicles, setSelectedVehicles] = useState<string[]>([]);
|
|
|
|
useEffect(() => {
|
|
dispatch(fetchVehicleBrands());
|
|
dispatch(vehicleList()); // Fetch vehicles when the component mounts
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
if (editRow) {
|
|
setValue("name", editRow.name);
|
|
setValue("registeredAddress", editRow.registeredAddress);
|
|
setValue("totalSlots", editRow.totalSlots);
|
|
setValue("status", editRow.status);
|
|
setValue("allowedCarIds", editRow.allowedCarIds || []);
|
|
setSelectedVehicles(editRow.allowedCarIds || []);
|
|
} else {
|
|
reset();
|
|
}
|
|
}, [editRow, setValue, reset]);
|
|
|
|
// Filter vehicles based on selected brands
|
|
const filteredVehicles = vehicles.filter((vehicle) =>
|
|
selectedBrands.includes(vehicle.company)
|
|
);
|
|
|
|
// Handle changes in vehicle brand selection
|
|
const handleBrandChange = (
|
|
event: React.ChangeEvent<{ value: unknown }>
|
|
) => {
|
|
setSelectedBrands(event.target.value as string[]);
|
|
};
|
|
|
|
// Handle changes in vehicle selection
|
|
const handleCheckboxChange = (
|
|
event: React.ChangeEvent<{ value: unknown }>
|
|
) => {
|
|
const value = event.target.value as string[];
|
|
setSelectedVehicles(value);
|
|
setValue("allowedCarIds", value); // Update allowedCarIds in form state
|
|
};
|
|
|
|
const onSubmit = (data: FormData) => {
|
|
const vehicleIds = vehicles
|
|
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
|
|
.map((vehicle) => Number(vehicle.id));
|
|
|
|
handleUpdate(
|
|
editRow.id,
|
|
data.name,
|
|
data.registeredAddress,
|
|
data.totalSlots,
|
|
vehicleIds
|
|
);
|
|
handleClose();
|
|
reset();
|
|
//setSelectedBrands([]); // Reset brands after submit
|
|
setSelectedVehicles([]); // Reset selected vehicles
|
|
};
|
|
console.log("editRow:", editRow);
|
|
|
|
|
|
return (
|
|
<Modal
|
|
open={open}
|
|
onClose={(e, reason) => {
|
|
if (reason === "backdropClick") {
|
|
return;
|
|
}
|
|
handleClose();
|
|
}}
|
|
aria-labelledby="edit-station-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 Charging Station
|
|
</Typography>
|
|
<CustomIconButton onClick={handleClose}>
|
|
<CloseIcon />
|
|
</CustomIconButton>
|
|
</Box>
|
|
|
|
{/* Horizontal Line */}
|
|
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
|
|
|
{/* Form */}
|
|
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
|
{/* Station Name and Address */}
|
|
<Box sx={{ display: "flex", gap: 2 }}>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="body2"
|
|
fontWeight={500}
|
|
mb={0.5}
|
|
>
|
|
Station Name
|
|
</Typography>
|
|
<Controller
|
|
name="name"
|
|
control={control}
|
|
render={({ field }) => (
|
|
<CustomTextField
|
|
{...field}
|
|
fullWidth
|
|
placeholder="Enter Station Name"
|
|
size="small"
|
|
error={!!errors.name}
|
|
helperText={
|
|
errors.name
|
|
? errors.name.message
|
|
: ""
|
|
}
|
|
/>
|
|
)}
|
|
/>
|
|
</Box>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="body2"
|
|
fontWeight={500}
|
|
mb={0.5}
|
|
>
|
|
Station Location
|
|
</Typography>
|
|
<Controller
|
|
name="registeredAddress"
|
|
control={control}
|
|
render={({ field }) => (
|
|
<CustomTextField
|
|
{...field}
|
|
fullWidth
|
|
placeholder="Enter Registered Address"
|
|
size="small"
|
|
error={!!errors.registeredAddress}
|
|
helperText={
|
|
errors.registeredAddress
|
|
? errors.registeredAddress
|
|
.message
|
|
: ""
|
|
}
|
|
/>
|
|
)}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Total Slots */}
|
|
<Box sx={{ display: "flex", gap: 2 }}>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="body2"
|
|
fontWeight={500}
|
|
mb={0.5}
|
|
>
|
|
Total Slots
|
|
</Typography>
|
|
<Controller
|
|
name="totalSlots"
|
|
control={control}
|
|
render={({ field }) => (
|
|
<CustomTextField
|
|
{...field}
|
|
fullWidth
|
|
placeholder="Enter Total Slots"
|
|
size="small"
|
|
type="number"
|
|
error={!!errors.totalSlots}
|
|
helperText={
|
|
errors.totalSlots
|
|
? errors.totalSlots.message
|
|
: ""
|
|
}
|
|
/>
|
|
)}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Vehicle Brand Selection with Checkboxes */}
|
|
<Box sx={{ display: "flex", gap: 2 }}>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<Typography variant="body2" fontWeight={500}>
|
|
Select Vehicle Brands
|
|
</Typography>
|
|
<FormControl fullWidth>
|
|
<InputLabel>Choose Brand</InputLabel>
|
|
<Select
|
|
multiple
|
|
value={selectedBrands}
|
|
onChange={handleBrandChange}
|
|
label="Choose Brands"
|
|
renderValue={(selected) => {
|
|
const selectedArray =
|
|
selected as string[];
|
|
const displayNames =
|
|
selectedArray.slice(0, 1); // First 2 brand names
|
|
const moreCount =
|
|
selectedArray.length - 1; // Remaining brands
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 1,
|
|
}}
|
|
>
|
|
{displayNames.map(
|
|
(id, index) => {
|
|
const brand =
|
|
vehicleBrands.find(
|
|
(b) =>
|
|
b.id === id
|
|
);
|
|
return (
|
|
<Typography
|
|
key={index}
|
|
variant="body2"
|
|
>
|
|
{brand
|
|
? brand.name
|
|
: ""}
|
|
</Typography>
|
|
);
|
|
}
|
|
)}
|
|
{moreCount > 0 && (
|
|
<Typography
|
|
variant="body2"
|
|
color="textSecondary"
|
|
>
|
|
+{moreCount} more
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
);
|
|
}}
|
|
>
|
|
{vehicleBrands.length > 0 ? (
|
|
vehicleBrands.map((brand) => (
|
|
<MenuItem
|
|
key={brand.id}
|
|
value={brand.id}
|
|
>
|
|
<Checkbox
|
|
checked={selectedBrands.includes(
|
|
brand.id
|
|
)}
|
|
/>
|
|
<ListItemText
|
|
primary={brand.name}
|
|
/>
|
|
</MenuItem>
|
|
))
|
|
) : (
|
|
<MenuItem disabled>
|
|
No vehicle brands available
|
|
</MenuItem>
|
|
)}
|
|
</Select>
|
|
</FormControl>
|
|
</Box>
|
|
{/* </Box>
|
|
<Box sx={{ display: "flex", gap: 2 }}> */}
|
|
<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) => {
|
|
const selectedArray =
|
|
selected as string[];
|
|
const displayNames =
|
|
selectedArray.slice(0, 1); // First 2 names
|
|
const moreCount =
|
|
selectedArray.length - 1; // Count of remaining items
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 1,
|
|
}}
|
|
>
|
|
{displayNames.map(
|
|
(name, index) => (
|
|
<Typography
|
|
key={index}
|
|
variant="body2"
|
|
>
|
|
{name}
|
|
</Typography>
|
|
)
|
|
)}
|
|
{moreCount > 0 && (
|
|
<Typography
|
|
variant="body2"
|
|
color="textSecondary"
|
|
>
|
|
+{moreCount} more
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
);
|
|
}}
|
|
>
|
|
{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.allowedCarIds
|
|
? errors.allowedCarIds.message
|
|
: ""}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
</Box>
|
|
</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" },
|
|
}}
|
|
>
|
|
Update Station
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default EditStationModal;
|