Charging station new updates in api integration and mangerModal bookingModal changes
This commit is contained in:
parent
fdff9c1dd9
commit
4df93ec1d9
|
@ -13,19 +13,20 @@ import {
|
|||
TextField,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
addBooking,
|
||||
bookingList,
|
||||
getCarNames,
|
||||
getCarPorts,
|
||||
} from "../../redux/slices/bookSlice";
|
||||
import { AppDispatch } from "../../redux/store/store";
|
||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
CustomIconButton,
|
||||
CustomTextField,
|
||||
} from "../AddEditUserModel/styled.css.tsx";
|
||||
import { stationList } from "../../redux/slices/stationSlice.ts";
|
||||
|
||||
export default function AddBookingModal({
|
||||
open,
|
||||
|
@ -44,6 +45,13 @@ export default function AddBookingModal({
|
|||
} = useForm();
|
||||
const [carNames, setCarNames] = useState<any[]>([]); // To hold the car names
|
||||
const [carPorts, setCarPorts] = useState<any[]>([]); // To hold the car ports
|
||||
const stations = useSelector(
|
||||
(state: RootState) => state?.stationReducer.stations
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(stationList());
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch car names and car ports
|
||||
|
@ -66,7 +74,7 @@ export default function AddBookingModal({
|
|||
|
||||
const onSubmit = async (data: any) => {
|
||||
const bookingData = {
|
||||
stationId: data.stationId,
|
||||
stationId: data.stationId, // Using stationId here for the backend
|
||||
date: data.date,
|
||||
startTime: data.startTime,
|
||||
endTime: data.endTime,
|
||||
|
@ -130,23 +138,34 @@ export default function AddBookingModal({
|
|||
{/* Station ID */}
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Station ID
|
||||
Select Station
|
||||
</Typography>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
placeholder="Enter Station Id"
|
||||
size="small"
|
||||
error={!!errors.stationId}
|
||||
helperText={
|
||||
errors.stationId
|
||||
? errors.stationId.message
|
||||
: ""
|
||||
}
|
||||
{...register("stationId", {
|
||||
required: "Station ID is required",
|
||||
})}
|
||||
/>
|
||||
<FormControl fullWidth error={!!errors.stationName}>
|
||||
<InputLabel>Select Station</InputLabel>
|
||||
<Select
|
||||
{...register("stationId", {
|
||||
required: "Station Name is required", // Change to stationId
|
||||
})}
|
||||
defaultValue=""
|
||||
size="small"
|
||||
>
|
||||
{stations.map((station) => (
|
||||
<MenuItem
|
||||
key={station.id}
|
||||
value={station.id}
|
||||
>
|
||||
{station.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.stationName && (
|
||||
<Typography color="error" variant="body2">
|
||||
{errors.stationName.message}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Date
|
||||
|
@ -190,7 +209,6 @@ export default function AddBookingModal({
|
|||
size="small"
|
||||
error={!!errors.carName}
|
||||
>
|
||||
<InputLabel>Car Name</InputLabel>
|
||||
<Select
|
||||
{...field}
|
||||
label="Car Name"
|
||||
|
|
|
@ -6,21 +6,28 @@ import {
|
|||
Modal,
|
||||
IconButton,
|
||||
InputAdornment,
|
||||
Select,
|
||||
MenuItem,
|
||||
InputLabel,
|
||||
FormControl,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { addManager, managerList } from "../../redux/slices/managerSlice";
|
||||
import {
|
||||
CustomIconButton,
|
||||
CustomTextField,
|
||||
} from "../AddEditUserModel/styled.css.tsx";
|
||||
import React, { useState, useRef } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { RootState } from "../../redux/reducers.ts";
|
||||
import { stationList } from "../../redux/slices/stationSlice.ts";
|
||||
|
||||
export default function AddManagerModal({
|
||||
open,
|
||||
handleClose,
|
||||
handleAddManager,
|
||||
// Assume the stations prop contains a list of station objects with 'id' and 'name'
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
|
@ -31,16 +38,26 @@ export default function AddManagerModal({
|
|||
reset,
|
||||
} = useForm();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const stations = useSelector(
|
||||
(state: RootState) => state?.stationReducer.stations
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(stationList());
|
||||
}, [dispatch]);
|
||||
|
||||
// Handle form submission
|
||||
const onSubmit = async (data: any) => {
|
||||
// Retrieve the stationId based on the stationName selected
|
||||
const selectedStation = stations.find(
|
||||
(station) => station.name === data.stationName
|
||||
);
|
||||
const managerData = {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
phone: data.phone,
|
||||
password: data.password,
|
||||
stationId: data.stationId, // Send stationId here
|
||||
|
||||
stationId: selectedStation?.id, // Send stationId here
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -131,33 +148,48 @@ export default function AddManagerModal({
|
|||
"Maximum 30 characters allowed",
|
||||
},
|
||||
pattern: {
|
||||
value: /^[A-Za-z\s]+$/, // Only letters and spaces are allowed
|
||||
value: /^[A-Za-z\s]+$/,
|
||||
message:
|
||||
"Manager Name must only contain letters and spaces",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Station Dropdown */}
|
||||
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Station Id
|
||||
Select Station
|
||||
</Typography>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
placeholder="Enter Station Id"
|
||||
size="small"
|
||||
error={!!errors.stationId}
|
||||
helperText={
|
||||
errors.stationId
|
||||
? errors.stationId.message
|
||||
: ""
|
||||
}
|
||||
{...register("stationId", {
|
||||
required: "Station Id is required",
|
||||
})}
|
||||
/>
|
||||
<FormControl fullWidth error={!!errors.stationName}>
|
||||
<InputLabel>Select Station</InputLabel>
|
||||
<Select
|
||||
{...register("stationName", {
|
||||
required: "Station Name is required",
|
||||
})}
|
||||
defaultValue=""
|
||||
size="small"
|
||||
>
|
||||
{stations.map((station) => (
|
||||
<MenuItem
|
||||
key={station.id}
|
||||
value={station.name}
|
||||
>
|
||||
{station.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.stationName && (
|
||||
<Typography color="error" variant="body2">
|
||||
{errors.stationName.message}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Email and Password */}
|
||||
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||
{/* Email */}
|
||||
|
@ -219,7 +251,6 @@ export default function AddManagerModal({
|
|||
: "primary"
|
||||
}
|
||||
size="small"
|
||||
// onMouseDown={togglePasswordVisibility}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
|
@ -247,9 +278,8 @@ export default function AddManagerModal({
|
|||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Phone and Registered Address */}
|
||||
{/* Phone Number */}
|
||||
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||
{/* Phone */}
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Phone Number
|
||||
|
@ -272,7 +302,6 @@ export default function AddManagerModal({
|
|||
})}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
|
||||
{/* Submit Button */}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
import { useForm } from "react-hook-form";
|
||||
import { Box, Button, Typography, Modal } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
Modal,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Select,
|
||||
MenuItem,
|
||||
Checkbox,
|
||||
ListItemText,
|
||||
InputLabel,
|
||||
} from "@mui/material";
|
||||
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 {
|
||||
CustomIconButton,
|
||||
CustomTextField,
|
||||
|
@ -18,10 +34,49 @@ export default function AddStationModal({
|
|||
reset,
|
||||
} = useForm();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Get vehicle names from the Redux store
|
||||
const vehicles = useSelector(
|
||||
(state: RootState) => state.vehicleReducer.vehicles
|
||||
); // Adjust according to your actual state structure
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(vehicleList()); // Fetch vehicles when the component mounts
|
||||
}, [dispatch]);
|
||||
|
||||
const [selectedVehicles, setSelectedVehicles] = useState<string[]>([]);
|
||||
|
||||
// Handle the change in selected vehicles (checkboxes)
|
||||
const handleCheckboxChange = (
|
||||
event: React.ChangeEvent<{ value: unknown }>
|
||||
) => {
|
||||
const value = event.target.value as string[];
|
||||
setSelectedVehicles(value);
|
||||
};
|
||||
|
||||
// Function to map selected vehicle names to corresponding vehicle ids
|
||||
const getVehicleIds = () => {
|
||||
return vehicles
|
||||
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
|
||||
.map((vehicle) => vehicle.id); // Return an array of ids based on the selected names
|
||||
};
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
handleAddStation(data); // Add station to the list
|
||||
const vehicleIds = getVehicleIds(); // Get the ids of the selected vehicles
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// Handle adding the station with the constructed payload
|
||||
handleAddStation(payload);
|
||||
handleClose(); // Close modal after adding
|
||||
reset();
|
||||
setSelectedVehicles([]); // Reset selected vehicles after submission
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -77,7 +132,6 @@ export default function AddStationModal({
|
|||
gap: 2,
|
||||
}}
|
||||
>
|
||||
{/* First Row - Two Inputs */}
|
||||
<Box sx={{ display: "flex", gap: 2 }}>
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -175,6 +229,53 @@ export default function AddStationModal({
|
|||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Vehicle Name Dropdown with Checkboxes */}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Vehicle Name
|
||||
</Typography>
|
||||
|
||||
{/* 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>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Submit Button */}
|
||||
|
@ -202,4 +303,4 @@ export default function AddStationModal({
|
|||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -145,7 +145,7 @@ export default function AddVehicleModal({
|
|||
{...register("company", {
|
||||
required: "Company is required",
|
||||
minLength: {
|
||||
value: 5,
|
||||
value: 3,
|
||||
message:
|
||||
"Company must be at least 5 characters long",
|
||||
},
|
||||
|
|
108
src/components/AvailableSlotModal/index.tsx
Normal file
108
src/components/AvailableSlotModal/index.tsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
Box,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import { styled } from "@mui/system";
|
||||
import {
|
||||
fetchAvailableSlots,
|
||||
availableSlots,
|
||||
} from "../../redux/slices/slotSlice"; // Update with the correct import path
|
||||
|
||||
const SlotButton = styled(Button)<{ selected: boolean }>(({ selected }) => ({
|
||||
backgroundColor: selected ? "#1976d2" : "#333",
|
||||
color: "#fff",
|
||||
border: "1px solid #555",
|
||||
width: "120px",
|
||||
height: "40px",
|
||||
margin: "5px",
|
||||
"&:hover": {
|
||||
backgroundColor: selected ? "#1565c0" : "#444",
|
||||
},
|
||||
}));
|
||||
|
||||
const AvailableSlotsModal = ({
|
||||
open,
|
||||
onClose,
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Fetch slots from the Redux store
|
||||
const { availableSlots, loading, error } = useSelector(
|
||||
(state: any) => state.slotReducer.availableSlots
|
||||
); // Adjust selector path
|
||||
const [selectedSlot, setSelectedSlot] = useState<availableSlots | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
// Fetch available slots when the modal opens
|
||||
dispatch(fetchAvailableSlots());
|
||||
}
|
||||
}, [open, dispatch]);
|
||||
|
||||
const handleSlotSelect = (slot: availableSlots) => {
|
||||
setSelectedSlot(slot); // Update the selected slot
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
// Save the selected slot (you can dispatch an action here if needed)
|
||||
console.log("Selected Slot: ", selectedSlot);
|
||||
onClose(); // Close the modal after saving
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle sx={{ color: "#fff", background: "#222" }}>
|
||||
Available Slots
|
||||
</DialogTitle>
|
||||
<Box
|
||||
sx={{
|
||||
background: "#111",
|
||||
padding: "20px",
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<CircularProgress color="primary" />
|
||||
) : error ? (
|
||||
<div style={{ color: "red" }}>Error: {error}</div>
|
||||
) : Array.isArray(availableSlots) &&
|
||||
availableSlots.length > 0 ? (
|
||||
availableSlots.map((slot: availableSlots) => (
|
||||
<SlotButton
|
||||
key={slot?.id}
|
||||
onClick={() => handleSlotSelect(slot)}
|
||||
selected={selectedSlot?.id === slot?.id}
|
||||
>
|
||||
{`${slot?.startTime} - ${slot?.endTime}`}
|
||||
</SlotButton>
|
||||
))
|
||||
) : (
|
||||
<div>No available slots</div>
|
||||
)}
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
sx={{ marginTop: "10px" }}
|
||||
onClick={handleSave}
|
||||
disabled={!selectedSlot}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AvailableSlotsModal;
|
|
@ -1,5 +1,16 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Box, Button, Typography, Modal } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
Modal,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
Checkbox,
|
||||
ListItemText,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import {
|
||||
|
@ -7,6 +18,15 @@ import {
|
|||
CustomTextField,
|
||||
} from "../AddEditUserModel/styled.css.tsx";
|
||||
|
||||
// Define the types for your form data
|
||||
interface FormData {
|
||||
name: string;
|
||||
registeredAddress: string;
|
||||
totalSlots: number;
|
||||
status: number;
|
||||
allowedCarIds: string[]; // Assuming allowedCarIds are the vehicle IDs
|
||||
}
|
||||
|
||||
interface EditStationModalProps {
|
||||
open: boolean;
|
||||
handleClose: () => void;
|
||||
|
@ -15,16 +35,10 @@ interface EditStationModalProps {
|
|||
name: string,
|
||||
registeredAddress: string,
|
||||
totalSlots: number,
|
||||
status: number
|
||||
allowedCarIds: string[]
|
||||
) => void;
|
||||
editRow: any;
|
||||
}
|
||||
|
||||
interface FormData {
|
||||
name: string;
|
||||
registeredAddress: string;
|
||||
totalSlots: number;
|
||||
status: number;
|
||||
editRow?: any;
|
||||
vehicles: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||
|
@ -32,34 +46,42 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
handleClose,
|
||||
handleUpdate,
|
||||
editRow,
|
||||
vehicles,
|
||||
}) => {
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
} = useForm<FormData>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
registeredAddress: "",
|
||||
totalSlots: 0,
|
||||
status: 1,
|
||||
},
|
||||
});
|
||||
const { control, handleSubmit, setValue, reset, watch } = useForm<FormData>(
|
||||
{
|
||||
defaultValues: {
|
||||
name: "",
|
||||
registeredAddress: "",
|
||||
totalSlots: 0,
|
||||
status: 1,
|
||||
allowedCarIds: [],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Set values if editRow is provided
|
||||
// Watch allowedCarIds from the form state
|
||||
const allowedCarIds = watch("allowedCarIds");
|
||||
|
||||
// Set values when editRow is provided
|
||||
useEffect(() => {
|
||||
if (editRow) {
|
||||
setValue("name", editRow.name);
|
||||
setValue("registeredAddress", editRow.registeredAddress);
|
||||
setValue("totalSlots", editRow.totalSlots);
|
||||
setValue("status", editRow.number);
|
||||
setValue("status", editRow.status);
|
||||
|
||||
// Set the allowedCarIds with the previously selected vehicle IDs
|
||||
setValue(
|
||||
"allowedCarIds",
|
||||
editRow.allowedCarIds?.map((car: any) => car.id) || []
|
||||
);
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}, [editRow, setValue, reset]);
|
||||
|
||||
// Handle form submit
|
||||
const onSubmit = (data: FormData) => {
|
||||
if (editRow) {
|
||||
handleUpdate(
|
||||
|
@ -67,10 +89,10 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
data.name,
|
||||
data.registeredAddress,
|
||||
data.totalSlots,
|
||||
data.status
|
||||
data.allowedCarIds
|
||||
);
|
||||
}
|
||||
handleClose(); // Close the modal
|
||||
handleClose(); // Close the modal after update
|
||||
reset(); // Reset the form fields
|
||||
};
|
||||
|
||||
|
@ -140,27 +162,12 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Station Name is required",
|
||||
minLength: {
|
||||
value: 3,
|
||||
message:
|
||||
"Minimum 3 characters required",
|
||||
},
|
||||
maxLength: {
|
||||
value: 30,
|
||||
message:
|
||||
"Maximum 30 characters allowed",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<CustomTextField
|
||||
{...field}
|
||||
fullWidth
|
||||
placeholder="Enter Station Name"
|
||||
size="small"
|
||||
error={!!errors.name}
|
||||
helperText={errors.name?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -183,19 +190,12 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
<Controller
|
||||
name="registeredAddress"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Registered Address is required",
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<CustomTextField
|
||||
{...field}
|
||||
fullWidth
|
||||
placeholder="Enter Registered Address"
|
||||
size="small"
|
||||
error={!!errors.registeredAddress}
|
||||
helperText={
|
||||
errors.registeredAddress?.message
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -221,13 +221,6 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
<Controller
|
||||
name="totalSlots"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Total Slots are required",
|
||||
min: {
|
||||
value: 1,
|
||||
message: "At least 1 slot is required",
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<CustomTextField
|
||||
{...field}
|
||||
|
@ -235,14 +228,62 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
|||
placeholder="Enter Total Slots"
|
||||
size="small"
|
||||
type="number"
|
||||
error={!!errors.totalSlots}
|
||||
helperText={errors.totalSlots?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Vehicle Dropdown with Checkboxes */}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" fontWeight={500}>
|
||||
Vehicle Names
|
||||
</Typography>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Choose Vehicles</InputLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={allowedCarIds || []} // Watch the allowedCarIds to reflect selected values
|
||||
onChange={(e) => {
|
||||
// Update the allowedCarIds when the selection changes
|
||||
setValue(
|
||||
"allowedCarIds",
|
||||
e.target.value as string[]
|
||||
); // Update allowedCarIds on change
|
||||
}}
|
||||
renderValue={(selected) => {
|
||||
return (selected as string[])
|
||||
.map((id) => {
|
||||
const vehicle = vehicles?.find(
|
||||
(vehicle) => vehicle.id === id
|
||||
);
|
||||
return vehicle ? vehicle.name : "";
|
||||
})
|
||||
.join(", ");
|
||||
}}
|
||||
>
|
||||
{vehicles?.map((vehicle) => (
|
||||
<MenuItem
|
||||
key={vehicle.id}
|
||||
value={vehicle.id}
|
||||
>
|
||||
<Checkbox
|
||||
checked={allowedCarIds?.includes(
|
||||
vehicle.id
|
||||
)}
|
||||
/>
|
||||
<ListItemText primary={vehicle.name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Submit Button */}
|
||||
|
|
|
@ -16,9 +16,6 @@ http.interceptors.response.use(
|
|||
(error) => {
|
||||
|
||||
if (error.response && error.response.status === 401) {
|
||||
|
||||
|
||||
|
||||
// window.location.href = "/login";
|
||||
|
||||
// const history = useHistory();
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import CustomTable, { Column } from "../../components/CustomTable";
|
||||
import { RootState } from "../../redux/reducers";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AppDispatch } from "../../redux/store/store";
|
||||
import { Chip } from "@mui/material";
|
||||
import AddStationModal from "../../components/AddStationModal";
|
||||
import CustomTable, { Column } from "../../components/CustomTable";
|
||||
import EditStationModal from "../../components/EditStationModal";
|
||||
import {
|
||||
createStation,
|
||||
stationList,
|
||||
toggleStatus,
|
||||
updateStation,
|
||||
} from "../../redux/slices/stationSlice";
|
||||
import { Chip, Switch } from "@mui/material";
|
||||
import { createStation, stationList, toggleStatus, updateStation } from "../../redux/slices/stationSlice";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../redux/reducers";
|
||||
import { AppDispatch } from "../../redux/store/store";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
export default function StationList() {
|
||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||
|
@ -28,6 +23,10 @@ export default function StationList() {
|
|||
const stations = useSelector(
|
||||
(state: RootState) => state.stationReducer.stations
|
||||
);
|
||||
const vehicles = useSelector(
|
||||
(state: RootState) => state.vehicleReducer.vehicles
|
||||
);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(stationList());
|
||||
|
@ -63,7 +62,8 @@ export default function StationList() {
|
|||
id: string,
|
||||
name: string,
|
||||
registeredAddress: string,
|
||||
totalSlots: string
|
||||
totalSlots: string,
|
||||
allowedCarIds: number[]
|
||||
) => {
|
||||
try {
|
||||
await dispatch(
|
||||
|
@ -72,7 +72,8 @@ export default function StationList() {
|
|||
name,
|
||||
registeredAddress,
|
||||
totalSlots,
|
||||
|
||||
status: 0,
|
||||
allowedCarIds, // Pass the updated allowedCarIds
|
||||
})
|
||||
);
|
||||
await dispatch(stationList());
|
||||
|
@ -82,56 +83,44 @@ export default function StationList() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleStatusToggle = async(id: string, newStatus: number) => {
|
||||
await dispatch(toggleStatus({ id, status: newStatus }));
|
||||
|
||||
|
||||
const handleStatusToggle = async (id: string, newStatus: number) => {
|
||||
await dispatch(toggleStatus({ id, status: newStatus }));
|
||||
};
|
||||
// Toggle station status
|
||||
// const handleStatusToggle = async (id: string, currentStatus: number) => {
|
||||
// try {
|
||||
// const newStatus = currentStatus === 1 ? 0 : 1; // Toggle between Active(1) and Inactive(0)
|
||||
// await dispatch(
|
||||
// updateStation({
|
||||
// id,
|
||||
// status: newStatus,
|
||||
// name: stations.name,
|
||||
// registeredAddress: stations.registeredAddress,
|
||||
// totalSlots: stations.totalSlots,
|
||||
// })
|
||||
// );
|
||||
// await dispatch(stationList());
|
||||
// } catch (error) {
|
||||
// console.error("Error toggling status", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
const filterStations = stations?.filter((station) =>
|
||||
station.name.toLocaleLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// Mapping and formatting vehicles
|
||||
const categoryRows = filterStations?.length
|
||||
? filterStations?.map((station: Station, index: number) => ({
|
||||
id: station.id,
|
||||
srno: index + 1,
|
||||
name: station.name,
|
||||
registeredAddress:station.registeredAddress,
|
||||
totalSlots:station.totalSlots,
|
||||
status: (
|
||||
<Chip
|
||||
label={
|
||||
station.status === 1 ? "Available" : "Not Available"
|
||||
}
|
||||
color={station.status === 1 ? "primary" : "default"}
|
||||
variant="outlined"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
width: "80px",
|
||||
textAlign: "center",
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
/>
|
||||
),
|
||||
statusValue: station.status,
|
||||
}))
|
||||
? filterStations?.map((station: any, index: number) => {
|
||||
// Format the selected vehicles from the allowedCars array
|
||||
const formattedVehicles = station.allowedCars?.map(
|
||||
(car: any) => car.name
|
||||
);
|
||||
|
||||
// Format the vehicle list like "Tata Punch Electric, Royal" or similar
|
||||
const vehicleDisplay = formattedVehicles
|
||||
? formattedVehicles.length > 1
|
||||
? `${formattedVehicles.slice(0, 2).join(", ")} + ${
|
||||
formattedVehicles.length - 2
|
||||
}`
|
||||
: formattedVehicles.join(", ")
|
||||
: "No vehicles"; // In case there are no vehicles selected
|
||||
|
||||
return {
|
||||
id: station.id,
|
||||
srno: index + 1,
|
||||
name: station.name,
|
||||
registeredAddress: station.registeredAddress,
|
||||
totalSlots: station.totalSlots,
|
||||
vehicles: vehicleDisplay, // Add the formatted vehicle display here
|
||||
status:
|
||||
station.status === 1 ? "Available" : "Not Available", // Format status text
|
||||
statusValue: station.status, // Status value for toggling
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const categoryColumns: Column[] = [
|
||||
|
@ -140,35 +129,11 @@ export default function StationList() {
|
|||
{ id: "name", label: "Station Name" },
|
||||
{ id: "registeredAddress", label: "Station Location" },
|
||||
{ id: "totalSlots", label: "Total Slots" },
|
||||
//{ id: "status", label: "Status" },
|
||||
{ id: "vehicles", label: "Vehicles" }, // Add Vehicles column here
|
||||
{ id: "status", label: "Status" }, // Add Status column here
|
||||
{ id: "action", label: "Action", align: "center" },
|
||||
];
|
||||
|
||||
// Filter stations based on search term
|
||||
// const filterStations = stations?.filter((station) =>
|
||||
// station.name.toLocaleLowerCase().includes(searchTerm.toLowerCase())
|
||||
// );
|
||||
|
||||
// // Prepare categoryRows with toggle switch for status
|
||||
// const categoryRows = filterStations?.length
|
||||
// ? filterStations?.map((station: any, index: number) => ({
|
||||
// id: station.id,
|
||||
// srno: index + 1,
|
||||
// name: station.name,
|
||||
// status: (
|
||||
// <Switch
|
||||
// checked={station.status === 1}
|
||||
// onChange={() =>
|
||||
// handleStatusToggle(station.id, station.status)
|
||||
// }
|
||||
// color="primary"
|
||||
// inputProps={{ "aria-label": "station-status-toggle" }}
|
||||
// />
|
||||
// ),
|
||||
// statusValue: station.status,
|
||||
// }))
|
||||
// : [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<CustomTable
|
||||
|
@ -194,6 +159,7 @@ export default function StationList() {
|
|||
handleClose={handleCloseModal}
|
||||
handleUpdate={handleUpdate}
|
||||
editRow={rowData}
|
||||
vehicles={vehicles}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ interface Station {
|
|||
registeredAddress: string;
|
||||
totalSlots: string;
|
||||
status: number;
|
||||
allowedCarIds: number[];
|
||||
}
|
||||
|
||||
interface StationState {
|
||||
|
@ -54,6 +55,7 @@ export const createStation = createAsyncThunk<
|
|||
name: string;
|
||||
registeredAddress: string;
|
||||
totalSlots: string;
|
||||
allowedCarIds: number[];
|
||||
},
|
||||
{ rejectValue: string }
|
||||
>("Station/createStation", async (data, { rejectWithValue }) => {
|
||||
|
|
Loading…
Reference in a new issue