Merge pull request 'fix the bugs and add NoteFoundPage' (#25) from frontend/apiIntegration into develop
Reviewed-on: DigiMantra/digiev_frontend#25
This commit is contained in:
commit
aafccd9c12
|
@ -1,139 +0,0 @@
|
||||||
// import React from "react";
|
|
||||||
// import {
|
|
||||||
// Button,
|
|
||||||
// Dialog,
|
|
||||||
// DialogActions,
|
|
||||||
// DialogContent,
|
|
||||||
// DialogTitle,
|
|
||||||
// TextField,
|
|
||||||
// } from "@mui/material";
|
|
||||||
// import { useForm, Controller } from "react-hook-form";
|
|
||||||
|
|
||||||
// interface AddAdminModalProps {
|
|
||||||
// open: boolean;
|
|
||||||
// handleClose: () => void;
|
|
||||||
// handleAdd: (name: string, email: string, phone: string, registeredAddress: string) => void;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface FormData {
|
|
||||||
// name: string;
|
|
||||||
// email: string;
|
|
||||||
// phone: string;
|
|
||||||
// registeredAddress: string;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const AddAdminModal: React.FC<AddAdminModalProps> = ({ open, handleClose, handleAdd }) => {
|
|
||||||
// const { control, handleSubmit, reset, formState: { errors } } = useForm<FormData>({
|
|
||||||
// defaultValues: {
|
|
||||||
// name: "",
|
|
||||||
// email: "",
|
|
||||||
// phone: "",
|
|
||||||
// registeredAddress: "",
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const onSubmit = (data: FormData) => {
|
|
||||||
// handleAdd(data.name, data.email, data.phone, data.registeredAddress);
|
|
||||||
// handleClose();
|
|
||||||
// reset();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Dialog
|
|
||||||
// open={open}
|
|
||||||
// onClose={handleClose}
|
|
||||||
// maxWidth="md"
|
|
||||||
// fullWidth
|
|
||||||
// PaperProps={{
|
|
||||||
// component: "form",
|
|
||||||
// onSubmit: handleSubmit(onSubmit),
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <DialogTitle>Add Admin</DialogTitle>
|
|
||||||
// <DialogContent>
|
|
||||||
// <Controller
|
|
||||||
// name="name"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Admin Name is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// autoFocus
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Admin Name"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.name}
|
|
||||||
// helperText={errors.name?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="email"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Email is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Email"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.email}
|
|
||||||
// helperText={errors.email?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="phone"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Phone number is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Phone Number"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.phone}
|
|
||||||
// helperText={errors.phone?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="registeredAddress"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Address is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Address"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.registeredAddress}
|
|
||||||
// helperText={errors.registeredAddress?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
// </DialogContent>
|
|
||||||
// <DialogActions>
|
|
||||||
// <Button onClick={handleClose}>Cancel</Button>
|
|
||||||
// <Button type="submit">Save</Button>
|
|
||||||
// </DialogActions>
|
|
||||||
// </Dialog>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default AddAdminModal;
|
|
340
src/components/AddAdminModal/addAdminModal.tsx
Normal file
340
src/components/AddAdminModal/addAdminModal.tsx
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Modal,
|
||||||
|
InputAdornment,
|
||||||
|
styled,
|
||||||
|
} from "@mui/material";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import Visibility from "@mui/icons-material/Visibility";
|
||||||
|
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
||||||
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
registeredAddress: string;
|
||||||
|
phone: string; // Added phone field
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddAdminModalProps {
|
||||||
|
open: boolean;
|
||||||
|
handleClose: () => void;
|
||||||
|
handleCreate: (data: FormData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddAdminModal: React.FC<AddAdminModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleClose,
|
||||||
|
handleCreate,
|
||||||
|
}) => {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
reset,
|
||||||
|
} = useForm<FormData>({
|
||||||
|
defaultValues: {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
registeredAddress: "",
|
||||||
|
phone: "", // Initialize phone field
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = (data: FormData) => {
|
||||||
|
handleCreate(data);
|
||||||
|
handleClose();
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
setShowPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={(e, reason) => {
|
||||||
|
if (reason === "backdropClick") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
aria-labelledby="add-admin-modal"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
width: 600,
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 3,
|
||||||
|
borderRadius: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" fontWeight={600}>
|
||||||
|
Add Admin
|
||||||
|
</Typography>
|
||||||
|
<CustomIconButton onClick={handleClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Horizontal Line */}
|
||||||
|
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
||||||
|
|
||||||
|
{/* Form */}
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{/* First Row - Admin Name & Email */}
|
||||||
|
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Admin Name
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Admin Name is required",
|
||||||
|
minLength: {
|
||||||
|
value: 3,
|
||||||
|
message:
|
||||||
|
"Minimum 3 characters required",
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 30,
|
||||||
|
message:
|
||||||
|
"Maximum 30 characters allowed",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Admin Name"
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
error={!!errors.name}
|
||||||
|
helperText={errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="email"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Email is required",
|
||||||
|
pattern: {
|
||||||
|
value: /\S+@\S+\.\S+/,
|
||||||
|
message:
|
||||||
|
"Please enter a valid email address.",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
error={!!errors.email}
|
||||||
|
helperText={errors.email?.message}
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Second Row - Password, Phone, Address */}
|
||||||
|
<Box sx={{ display: "flex", gap: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Password
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="password"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Password is required",
|
||||||
|
minLength: {
|
||||||
|
value: 6,
|
||||||
|
message:
|
||||||
|
"Password must be at least 6 characters",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Password"
|
||||||
|
type={
|
||||||
|
showPassword ? "text" : "password"
|
||||||
|
}
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
error={!!errors.password}
|
||||||
|
helperText={errors.password?.message}
|
||||||
|
slotProps={{
|
||||||
|
input: {
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<CustomIconButton
|
||||||
|
onClick={
|
||||||
|
togglePasswordVisibility
|
||||||
|
}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
{showPassword ? (
|
||||||
|
<VisibilityOff />
|
||||||
|
) : (
|
||||||
|
<Visibility />
|
||||||
|
)}
|
||||||
|
</CustomIconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Phone
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="phone"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Phone number is required",
|
||||||
|
pattern: {
|
||||||
|
value: /^[0-9]{10}$/,
|
||||||
|
message:
|
||||||
|
"Enter a valid 10-digit phone number",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Phone Number"
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
error={!!errors.phone}
|
||||||
|
helperText={errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Address
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="registeredAddress"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Address is required",
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Address"
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
error={!!errors.registeredAddress}
|
||||||
|
helperText={
|
||||||
|
errors.registeredAddress?.message
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</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" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Admin
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddAdminModal;
|
|
@ -5,12 +5,10 @@ import {
|
||||||
Button,
|
Button,
|
||||||
Typography,
|
Typography,
|
||||||
Modal,
|
Modal,
|
||||||
IconButton,
|
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Select,
|
Select,
|
||||||
InputLabel,
|
InputLabel,
|
||||||
FormControl,
|
FormControl,
|
||||||
TextField,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
@ -19,16 +17,12 @@ import {
|
||||||
bookingList,
|
bookingList,
|
||||||
getCarNames,
|
getCarNames,
|
||||||
getCarPorts,
|
getCarPorts,
|
||||||
} from "../../redux/slices/bookSlice";
|
} from "../../redux/slices/bookSlice.ts";
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
import { AppDispatch, RootState } from "../../redux/store/store.ts";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
CustomIconButton,
|
import { getAllStations } from "../../redux/slices/stationSlice.ts";
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
|
||||||
import { getAllStations, stationList } from "../../redux/slices/stationSlice.ts";
|
|
||||||
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
|
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
export default function AddBookingModal({
|
export default function AddBookingModal({
|
||||||
open,
|
open,
|
||||||
|
@ -53,7 +47,6 @@ export default function AddBookingModal({
|
||||||
const availableSlots = useSelector(
|
const availableSlots = useSelector(
|
||||||
(state: RootState) => state.slotReducer.availableSlots
|
(state: RootState) => state.slotReducer.availableSlots
|
||||||
);
|
);
|
||||||
console.log("first", availableSlots);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchAvailableSlots());
|
dispatch(fetchAvailableSlots());
|
||||||
dispatch(getAllStations());
|
dispatch(getAllStations());
|
||||||
|
@ -74,7 +67,7 @@ export default function AddBookingModal({
|
||||||
// Fetch the bookings after this
|
// Fetch the bookings after this
|
||||||
dispatch(bookingList());
|
dispatch(bookingList());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
console.log("Car Ports: ", carPorts);
|
console.log("Car Ports: ", carPorts);
|
||||||
// Get today's date in yyyy-mm-dd format
|
// Get today's date in yyyy-mm-dd format
|
||||||
const today = new Date().toISOString().split("T")[0];
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
|
@ -164,7 +157,7 @@ console.log("Car Ports: ", carPorts);
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
{errors.stationName && (
|
{errors.stationId && (
|
||||||
<Typography color="error" variant="body2">
|
<Typography color="error" variant="body2">
|
||||||
{errors.stationName.message}
|
{errors.stationName.message}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -190,11 +183,14 @@ console.log("Car Ports: ", carPorts);
|
||||||
value >= today ||
|
value >= today ||
|
||||||
"Date cannot be in the past",
|
"Date cannot be in the past",
|
||||||
})}
|
})}
|
||||||
InputLabelProps={{
|
slotProps={{
|
||||||
shrink: true,
|
inputLabel: {
|
||||||
|
shrink: true,
|
||||||
|
},
|
||||||
|
htmlInput: {
|
||||||
|
min: today,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
// Setting minimum date to today
|
|
||||||
inputProps={{ min: today }}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -350,114 +346,6 @@ console.log("Car Ports: ", carPorts);
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</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 */}
|
|
@ -1,20 +1,10 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {
|
import { Box, Button, Typography, Modal, InputAdornment } from "@mui/material";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Typography,
|
|
||||||
Modal,
|
|
||||||
InputAdornment,
|
|
||||||
|
|
||||||
} from "@mui/material";
|
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import Visibility from "@mui/icons-material/Visibility";
|
import Visibility from "@mui/icons-material/Visibility";
|
||||||
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
CustomIconButton,
|
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
|
||||||
|
|
||||||
//By Jaanvi : Edit Model :: 11-feb-25
|
//By Jaanvi : Edit Model :: 11-feb-25
|
||||||
interface AddEditCategoryModalProps {
|
interface AddEditCategoryModalProps {
|
||||||
|
@ -54,6 +44,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
setValue,
|
setValue,
|
||||||
reset,
|
reset,
|
||||||
|
clearErrors,
|
||||||
} = useForm<FormData>({
|
} = useForm<FormData>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -63,7 +54,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
password: "",
|
password: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = (data: FormData) => {
|
const onSubmit = (data: FormData) => {
|
||||||
if (editRow) {
|
if (editRow) {
|
||||||
handleUpdate(
|
handleUpdate(
|
||||||
|
@ -81,9 +72,9 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
reset();
|
reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
const togglePasswordVisibility = () => {
|
const togglePasswordVisibility = () => {
|
||||||
setShowPassword((prev) => !prev);
|
setShowPassword((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editRow) {
|
if (editRow) {
|
||||||
|
@ -91,22 +82,29 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
setValue("email", editRow.email);
|
setValue("email", editRow.email);
|
||||||
setValue("phone", editRow.phone);
|
setValue("phone", editRow.phone);
|
||||||
setValue("registeredAddress", editRow.registeredAddress);
|
setValue("registeredAddress", editRow.registeredAddress);
|
||||||
|
clearErrors();
|
||||||
} else {
|
} else {
|
||||||
reset();
|
reset();
|
||||||
|
clearErrors();
|
||||||
}
|
}
|
||||||
}, [editRow, setValue, reset]);
|
}, [editRow, setValue, reset]);
|
||||||
|
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
reset();
|
||||||
|
clearErrors();
|
||||||
|
handleClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={open}
|
open={open}
|
||||||
|
key={open ? "open" : "closed"}
|
||||||
onClose={(e, reason) => {
|
onClose={(e, reason) => {
|
||||||
if (reason === "backdropClick") {
|
if (reason === "backdropClick") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleClose(); // Close modal when clicking cross or cancel
|
|
||||||
|
handleCloseModal();
|
||||||
}}
|
}}
|
||||||
aria-labelledby="add-edit-category-modal"
|
aria-labelledby="add-edit-category-modal"
|
||||||
>
|
>
|
||||||
|
@ -134,7 +132,7 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
<Typography variant="h6" fontWeight={600}>
|
<Typography variant="h6" fontWeight={600}>
|
||||||
{editRow ? "Edit Admin" : "Add Admin"}
|
{editRow ? "Edit Admin" : "Add Admin"}
|
||||||
</Typography>
|
</Typography>
|
||||||
<CustomIconButton onClick={handleClose}>
|
<CustomIconButton onClick={handleCloseModal}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</CustomIconButton>
|
</CustomIconButton>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -291,24 +289,26 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
: "primary"
|
: "primary"
|
||||||
}
|
}
|
||||||
size="small"
|
size="small"
|
||||||
InputProps={{
|
slotProps={{
|
||||||
endAdornment: (
|
input: {
|
||||||
<InputAdornment position="end">
|
endAdornment: (
|
||||||
<CustomIconButton
|
<InputAdornment position="end">
|
||||||
aria-label="toggle password visibility"
|
<CustomIconButton
|
||||||
onClick={
|
aria-label="toggle password visibility"
|
||||||
togglePasswordVisibility
|
onClick={
|
||||||
}
|
togglePasswordVisibility
|
||||||
edge="end"
|
}
|
||||||
>
|
edge="end"
|
||||||
{showPassword ? (
|
>
|
||||||
<VisibilityOff />
|
{showPassword ? (
|
||||||
) : (
|
<VisibilityOff />
|
||||||
<Visibility />
|
) : (
|
||||||
)}
|
<Visibility />
|
||||||
</CustomIconButton>
|
)}
|
||||||
</InputAdornment>
|
</CustomIconButton>
|
||||||
),
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
error={!!errors.password}
|
error={!!errors.password}
|
||||||
helperText={
|
helperText={
|
||||||
|
@ -334,19 +334,17 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
required: "Phone number is required",
|
required: "Phone number is required",
|
||||||
pattern: {
|
validate: (value) => {
|
||||||
value: /^[0-9]*$/,
|
if (!/^[0-9]*$/.test(value)) {
|
||||||
message: "Only numbers are allowed",
|
return "Only numbers are allowed";
|
||||||
},
|
}
|
||||||
minLength: {
|
if (value.length < 6) {
|
||||||
value: 6,
|
return "Phone number must be at least 6 digits";
|
||||||
message:
|
}
|
||||||
"Phone number must be at least 6 digits",
|
if (value.length > 14) {
|
||||||
},
|
return "Phone number must be at most 14 digits";
|
||||||
maxLength: {
|
}
|
||||||
value: 14,
|
return true; // No errors
|
||||||
message:
|
|
||||||
"Phone number must be at most 14 digits",
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
|
@ -1,222 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useForm, SubmitHandler } from "react-hook-form";
|
|
||||||
import { Dialog, DialogActions, DialogContent, DialogTitle, Button, TextField, MenuItem, Select, InputLabel, FormControl, FormHelperText, Box } from "@mui/material";
|
|
||||||
import { useDropzone } from 'react-dropzone';
|
|
||||||
|
|
||||||
// Define the types for form data
|
|
||||||
interface FormData {
|
|
||||||
exerciseName: string;
|
|
||||||
description: string;
|
|
||||||
primMuscleTargeted: string;
|
|
||||||
secMuscleTargeted?: string;
|
|
||||||
repsOrduration: string;
|
|
||||||
sets: string;
|
|
||||||
restBetweenSets?: string;
|
|
||||||
difficultyLevel: "beginner" | "intermediate" | "advanced";
|
|
||||||
formTips?: string;
|
|
||||||
modificationOptions?: string;
|
|
||||||
equipmentNeeded?: string;
|
|
||||||
videoLink?: string;
|
|
||||||
audioInstructions?: string;
|
|
||||||
restTimeAfterExercise?: string;
|
|
||||||
totalTimeForExercise?: string;
|
|
||||||
progressTracking?: string;
|
|
||||||
motivationalTips?: string;
|
|
||||||
exerciseImage?: File | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AddEditExerciseModalProps {
|
|
||||||
open: boolean;
|
|
||||||
handleClose: () => void;
|
|
||||||
editRow: any;
|
|
||||||
preview: string;
|
|
||||||
setPreview: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddEditExerciseModal: React.FC<AddEditExerciseModalProps> = ({ open, handleClose, editRow ,preview,setPreview}) => {
|
|
||||||
const { handleSubmit, register, formState: { errors }, setValue, reset, getValues} = useForm<FormData>();
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
|
||||||
accept: 'image/*, .gif',
|
|
||||||
onDrop: (acceptedFiles) => {
|
|
||||||
if (acceptedFiles && acceptedFiles.length > 0) {
|
|
||||||
setValue('exerciseImage', acceptedFiles[0]);
|
|
||||||
handlePreview(acceptedFiles[0])
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log("Imageeeee" , getValues('exerciseImage'))
|
|
||||||
// State to store the preview URL of the uploaded file
|
|
||||||
|
|
||||||
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (editRow) {
|
|
||||||
setValue('exerciseName', editRow.exerciseName);
|
|
||||||
setValue('description', editRow.description);
|
|
||||||
setValue('primMuscleTargeted', editRow.primMuscleTargeted);
|
|
||||||
setValue('secMuscleTargeted', editRow.secMuscleTargeted);
|
|
||||||
setValue('repsOrduration', editRow.repsOrduration);
|
|
||||||
setValue('sets', editRow.sets);
|
|
||||||
setValue('restBetweenSets', editRow.restBetweenSets);
|
|
||||||
setValue('difficultyLevel', editRow.difficultyLevel);
|
|
||||||
if (editRow.exerciseImage) {
|
|
||||||
setValue('exerciseImage', editRow.exerciseImage);
|
|
||||||
setPreview(editRow.exerciseImage);
|
|
||||||
setSelectedFile(editRow.exerciseImage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reset();
|
|
||||||
setPreview(null);
|
|
||||||
setSelectedFile(null);
|
|
||||||
}
|
|
||||||
}, [editRow, setValue, reset,setPreview]);
|
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<FormData> = (data: FormData) => {
|
|
||||||
console.log(data);
|
|
||||||
reset();
|
|
||||||
setPreview(null);
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handlePreview = (file: File | null) => {
|
|
||||||
if (file) {
|
|
||||||
setValue('exerciseImage', file);
|
|
||||||
setPreview(URL.createObjectURL(file));
|
|
||||||
setSelectedFile(file);
|
|
||||||
} else {
|
|
||||||
setPreview(null);
|
|
||||||
setSelectedFile(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleClearFile = () => {
|
|
||||||
setPreview(null);
|
|
||||||
setSelectedFile(null);
|
|
||||||
setValue('exerciseImage', null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="md">
|
|
||||||
<DialogTitle>Create Exercise</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<Box sx={{ display: "grid", gap: 2 }}>
|
|
||||||
{/* Exercise Name */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Exercise Name"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("exerciseName", { required: "Exercise name is required" })}
|
|
||||||
error={!!errors.exerciseName}
|
|
||||||
helperText={errors.exerciseName?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Description */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Description"
|
|
||||||
variant="outlined"
|
|
||||||
multiline
|
|
||||||
rows={4}
|
|
||||||
{...register("description", { required: "Description is required" })}
|
|
||||||
error={!!errors.description}
|
|
||||||
helperText={errors.description?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Primary Muscles Targeted */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Primary Muscles Targeted"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("primMuscleTargeted", { required: "Primary muscles are required" })}
|
|
||||||
error={!!errors.primMuscleTargeted}
|
|
||||||
helperText={errors.primMuscleTargeted?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Secondary Muscles Targeted */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Secondary Muscles Targeted"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("secMuscleTargeted")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Reps/Duration */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Reps/Duration"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("repsOrduration", { required: "Reps or duration is required" })}
|
|
||||||
error={!!errors.repsOrduration}
|
|
||||||
helperText={errors.repsOrduration?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Sets */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Sets"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("sets", { required: "Sets are required" })}
|
|
||||||
error={!!errors.sets}
|
|
||||||
helperText={errors.sets?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Rest Between Sets */}
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Rest Between Sets"
|
|
||||||
variant="outlined"
|
|
||||||
{...register("restBetweenSets")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Difficulty Level */}
|
|
||||||
<FormControl fullWidth error={!!errors.difficultyLevel}>
|
|
||||||
<InputLabel>Difficulty Level</InputLabel>
|
|
||||||
<Select
|
|
||||||
defaultValue={editRow?.difficultyLevel || ''}
|
|
||||||
label="Difficulty Level"
|
|
||||||
{...register("difficultyLevel", { required: "Difficulty level is required" })}
|
|
||||||
>
|
|
||||||
<MenuItem value="beginner">Beginner</MenuItem>
|
|
||||||
<MenuItem value="intermediate">Intermediate</MenuItem>
|
|
||||||
<MenuItem value="advanced">Advanced</MenuItem>
|
|
||||||
</Select>
|
|
||||||
{errors.difficultyLevel && <FormHelperText>{errors.difficultyLevel.message}</FormHelperText>}
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{/* Image/GIF Upload */}
|
|
||||||
<Box {...getRootProps()} sx={{ border: '2px dashed', padding: 2, width: '100%', marginBottom: 2 }}>
|
|
||||||
<input {...getInputProps()} onChange={(e) => handlePreview(e.target.files?.[0] || null)} />
|
|
||||||
<p>Drag & drop an image or GIF here, or click to select</p>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Preview the uploaded image or GIF */}
|
|
||||||
{preview && (
|
|
||||||
<Box sx={{ textAlign: 'center', marginBottom: 2 }}>
|
|
||||||
<p>Preview:</p>
|
|
||||||
<img src={preview} alt="Exercise Preview" style={{ maxWidth: '100%', maxHeight: 300, objectFit: 'contain' }} />
|
|
||||||
<p>{selectedFile?.name || selectedFile.split("/").pop()}</p>
|
|
||||||
|
|
||||||
<Button variant="outlined" color="secondary" onClick={handleClearFile} sx={{ marginTop: 1 }}>
|
|
||||||
Remove File
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</form>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleClose} color="secondary">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleSubmit(onSubmit)} color="primary" variant="contained">
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddEditExerciseModal;
|
|
|
@ -1,82 +0,0 @@
|
||||||
import React,{useEffect} from "react";
|
|
||||||
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@mui/material";
|
|
||||||
import { useForm, Controller } from "react-hook-form";
|
|
||||||
|
|
||||||
interface AddEditTagsModalProps {
|
|
||||||
open: boolean;
|
|
||||||
handleClose: () => void;
|
|
||||||
editRow:any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FormData {
|
|
||||||
tag: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddEditTagsModal: React.FC<AddEditTagsModalProps> = ({ open, handleClose,editRow }) => {
|
|
||||||
const { control, handleSubmit, formState: { errors },setValue,reset } = useForm<FormData>({
|
|
||||||
defaultValues: {
|
|
||||||
tag: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = (data: FormData) => {
|
|
||||||
console.log(data.tag);
|
|
||||||
handleClose();
|
|
||||||
reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (editRow) {
|
|
||||||
setValue('tag', editRow.name);
|
|
||||||
} else {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}, [editRow, setValue, reset]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Dialog
|
|
||||||
open={open}
|
|
||||||
onClose={handleClose}
|
|
||||||
maxWidth="md"
|
|
||||||
fullWidth
|
|
||||||
PaperProps={{
|
|
||||||
component: 'form',
|
|
||||||
onSubmit: handleSubmit(onSubmit),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DialogTitle>{editRow ? "Edit" : 'Add'} Tag</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<Controller
|
|
||||||
name="tag"
|
|
||||||
control={control}
|
|
||||||
rules={{
|
|
||||||
required: "Tag Name is required",
|
|
||||||
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<TextField
|
|
||||||
{...field}
|
|
||||||
autoFocus
|
|
||||||
required
|
|
||||||
margin="dense"
|
|
||||||
label="Add Tag Name"
|
|
||||||
type="text"
|
|
||||||
fullWidth
|
|
||||||
variant="standard"
|
|
||||||
error={!!errors.tag}
|
|
||||||
helperText={errors.tag?.message}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleClose}>Cancel</Button>
|
|
||||||
<Button type="submit">Save</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddEditTagsModal;
|
|
|
@ -1,382 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Typography,
|
|
||||||
TextField,
|
|
||||||
Modal,
|
|
||||||
IconButton,
|
|
||||||
InputAdornment,
|
|
||||||
styled,
|
|
||||||
} from "@mui/material";
|
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
|
||||||
import Visibility from "@mui/icons-material/Visibility";
|
|
||||||
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
|
||||||
import { useForm, Controller } from "react-hook-form";
|
|
||||||
import { CustomIconButton, CustomTextField } from "./styled.css.tsx";
|
|
||||||
|
|
||||||
|
|
||||||
interface FormData {
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
phone: string;
|
|
||||||
}
|
|
||||||
interface AddUserModalProps {
|
|
||||||
open: boolean;
|
|
||||||
handleClose: () => void;
|
|
||||||
handleCreate: (data: FormData) => void;
|
|
||||||
handleUpdate: (
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
email: string,
|
|
||||||
phone: string,
|
|
||||||
|
|
||||||
) => void;
|
|
||||||
editRow: any;
|
|
||||||
}
|
|
||||||
const AddUserModal: React.FC<AddUserModalProps> = ({
|
|
||||||
open,
|
|
||||||
handleClose,
|
|
||||||
handleCreate,
|
|
||||||
handleUpdate,
|
|
||||||
editRow,
|
|
||||||
}) => {
|
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
|
||||||
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
reset,
|
|
||||||
setValue,
|
|
||||||
} = useForm<FormData>({
|
|
||||||
defaultValues: {
|
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (editRow) {
|
|
||||||
setValue("name", editRow.name);
|
|
||||||
setValue("email", editRow.email);
|
|
||||||
setValue("phone", editRow.phone);
|
|
||||||
} else {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}, [editRow, setValue,reset]);
|
|
||||||
|
|
||||||
const onSubmit = (data: FormData) => {
|
|
||||||
if (editRow) {
|
|
||||||
handleUpdate(
|
|
||||||
editRow.id,
|
|
||||||
data.name,
|
|
||||||
data.email,
|
|
||||||
data.phone
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
handleCreate(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClose();
|
|
||||||
reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
const togglePasswordVisibility = () => {
|
|
||||||
setShowPassword((prev) => !prev);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={open}
|
|
||||||
onClose={(e, reason) => {
|
|
||||||
if (reason === "backdropClick") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handleClose(); // Close modal when clicking cross or cancel
|
|
||||||
}}
|
|
||||||
aria-labelledby="add-user-modal"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
width: 600, // Adjusted the width for a wider modal
|
|
||||||
bgcolor: "background.paper",
|
|
||||||
boxShadow: 24,
|
|
||||||
p: 3,
|
|
||||||
borderRadius: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Header */}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="h6" fontWeight={600}>
|
|
||||||
{editRow ? "Edit User" : "Add User"}
|
|
||||||
</Typography>
|
|
||||||
<CustomIconButton onClick={handleClose}>
|
|
||||||
<CloseIcon />
|
|
||||||
</CustomIconButton>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Horizontal Line */}
|
|
||||||
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
|
||||||
|
|
||||||
{/* Form */}
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
{/* Input Fields */}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* First Row - Two Inputs */}
|
|
||||||
<Box sx={{ display: "flex", gap: 2 }}>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="body2" fontWeight={500}>
|
|
||||||
User Name
|
|
||||||
</Typography>
|
|
||||||
<Controller
|
|
||||||
name="name"
|
|
||||||
control={control}
|
|
||||||
rules={{
|
|
||||||
required: "User Name is required",
|
|
||||||
minLength: {
|
|
||||||
value: 3,
|
|
||||||
message:
|
|
||||||
"Minimum 3 characters required",
|
|
||||||
},
|
|
||||||
maxLength: {
|
|
||||||
value: 30,
|
|
||||||
message:
|
|
||||||
"Maximum 30 characters allowed",
|
|
||||||
},
|
|
||||||
pattern: {
|
|
||||||
value: /^[A-Za-z\s]+$/, // Only letters and spaces are allowed
|
|
||||||
message:
|
|
||||||
"User Name must only contain letters and spaces",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomTextField
|
|
||||||
{...field}
|
|
||||||
required
|
|
||||||
placeholder="Enter User Name"
|
|
||||||
fullWidth
|
|
||||||
size="small"
|
|
||||||
error={!!errors.name}
|
|
||||||
helperText={errors.name?.message}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="body2" fontWeight={500}>
|
|
||||||
Email
|
|
||||||
</Typography>
|
|
||||||
<Controller
|
|
||||||
name="email"
|
|
||||||
control={control}
|
|
||||||
rules={{
|
|
||||||
required: "Email is required",
|
|
||||||
pattern: {
|
|
||||||
value: /\S+@\S+\.\S+/,
|
|
||||||
message:
|
|
||||||
"Please enter a valid email address.",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomTextField
|
|
||||||
{...field}
|
|
||||||
error={!!errors.email}
|
|
||||||
helperText={errors.email?.message}
|
|
||||||
id="email"
|
|
||||||
type="email"
|
|
||||||
placeholder="Email"
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
color={
|
|
||||||
errors.email
|
|
||||||
? "error"
|
|
||||||
: "primary"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Second Row - Two Inputs */}
|
|
||||||
<Box sx={{ display: "flex", gap: 2 }}>
|
|
||||||
{!editRow && ( <Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="body2" fontWeight={500}>
|
|
||||||
Password
|
|
||||||
</Typography>
|
|
||||||
<Controller
|
|
||||||
name="password"
|
|
||||||
control={control}
|
|
||||||
rules={{
|
|
||||||
required: "Password is required",
|
|
||||||
minLength: {
|
|
||||||
value: 6,
|
|
||||||
message:
|
|
||||||
"Password must be at least 6 characters long.",
|
|
||||||
},
|
|
||||||
pattern: {
|
|
||||||
value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$/,
|
|
||||||
message:
|
|
||||||
"Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomTextField
|
|
||||||
{...field}
|
|
||||||
required
|
|
||||||
placeholder="Enter Password"
|
|
||||||
type={
|
|
||||||
showPassword
|
|
||||||
? "text"
|
|
||||||
: "password"
|
|
||||||
}
|
|
||||||
id="password"
|
|
||||||
fullWidth
|
|
||||||
color={
|
|
||||||
errors.password
|
|
||||||
? "error"
|
|
||||||
: "primary"
|
|
||||||
}
|
|
||||||
size="small"
|
|
||||||
InputProps={{
|
|
||||||
endAdornment: (
|
|
||||||
<InputAdornment position="end">
|
|
||||||
<CustomIconButton
|
|
||||||
aria-label="toggle password visibility"
|
|
||||||
onClick={
|
|
||||||
togglePasswordVisibility
|
|
||||||
}
|
|
||||||
edge="end"
|
|
||||||
>
|
|
||||||
{showPassword ? (
|
|
||||||
<VisibilityOff />
|
|
||||||
) : (
|
|
||||||
<Visibility />
|
|
||||||
)}
|
|
||||||
</CustomIconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
error={!!errors.password}
|
|
||||||
helperText={
|
|
||||||
errors.password?.message
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Box>)}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="body2" fontWeight={500}>
|
|
||||||
Phone Number
|
|
||||||
</Typography>
|
|
||||||
<Controller
|
|
||||||
name="phone"
|
|
||||||
control={control}
|
|
||||||
rules={{
|
|
||||||
required: "Phone number is required",
|
|
||||||
pattern: {
|
|
||||||
value: /^[0-9]*$/,
|
|
||||||
message: "Only numbers are allowed",
|
|
||||||
},
|
|
||||||
minLength: {
|
|
||||||
value: 6,
|
|
||||||
message:
|
|
||||||
"Phone number must be at least 6 digits",
|
|
||||||
},
|
|
||||||
maxLength: {
|
|
||||||
value: 14,
|
|
||||||
message:
|
|
||||||
"Phone number must be at most 14 digits",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomTextField
|
|
||||||
{...field}
|
|
||||||
required
|
|
||||||
placeholder="Enter Phone Number"
|
|
||||||
size="small"
|
|
||||||
error={!!errors.phone}
|
|
||||||
helperText={errors.phone?.message}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Submit Button */}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
width: "100%",
|
|
||||||
mt: 3,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
sx={{
|
|
||||||
backgroundColor: "#52ACDF",
|
|
||||||
color: "white",
|
|
||||||
borderRadius: "8px",
|
|
||||||
width: "117px",
|
|
||||||
"&:hover": { backgroundColor: "#439BC1" },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{editRow ? "Update User" : "Add User"}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</form>
|
|
||||||
</Box>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddUserModal;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const AddEditWorkoutModal = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AddEditWorkoutModal
|
|
|
@ -14,11 +14,8 @@ import {
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { addManager, managerList } from "../../redux/slices/managerSlice";
|
import { addManager, managerList } from "../../redux/slices/managerSlice.ts";
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
CustomIconButton,
|
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { RootState } from "../../redux/reducers.ts";
|
import { RootState } from "../../redux/reducers.ts";
|
||||||
import { stationList } from "../../redux/slices/stationSlice.ts";
|
import { stationList } from "../../redux/slices/stationSlice.ts";
|
||||||
|
@ -38,13 +35,13 @@ export default function AddManagerModal({
|
||||||
reset,
|
reset,
|
||||||
} = useForm();
|
} = useForm();
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const stations = useSelector(
|
const stations = useSelector(
|
||||||
(state: RootState) => state?.stationReducer.stations
|
(state: RootState) => state?.stationReducer.stations
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(stationList());
|
dispatch(stationList());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
const onSubmit = async (data: any) => {
|
const onSubmit = async (data: any) => {
|
||||||
|
@ -258,24 +255,26 @@ useEffect(() => {
|
||||||
: "primary"
|
: "primary"
|
||||||
}
|
}
|
||||||
size="small"
|
size="small"
|
||||||
InputProps={{
|
slotProps={{
|
||||||
endAdornment: (
|
input: {
|
||||||
<InputAdornment position="end">
|
endAdornment: (
|
||||||
<CustomIconButton
|
<InputAdornment position="end">
|
||||||
aria-label="toggle password visibility"
|
<CustomIconButton
|
||||||
onClick={
|
aria-label="toggle password visibility"
|
||||||
togglePasswordVisibility
|
onClick={
|
||||||
}
|
togglePasswordVisibility
|
||||||
edge="end"
|
}
|
||||||
>
|
edge="end"
|
||||||
{showPassword ? (
|
>
|
||||||
<VisibilityOff />
|
{showPassword ? (
|
||||||
) : (
|
<VisibilityOff />
|
||||||
<Visibility />
|
) : (
|
||||||
)}
|
<Visibility />
|
||||||
</CustomIconButton>
|
)}
|
||||||
</InputAdornment>
|
</CustomIconButton>
|
||||||
),
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
error={!!errors.password}
|
error={!!errors.password}
|
||||||
helperText={errors.password?.message}
|
helperText={errors.password?.message}
|
|
@ -48,8 +48,10 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
|
||||||
type="date"
|
type="date"
|
||||||
fullWidth
|
fullWidth
|
||||||
margin="normal"
|
margin="normal"
|
||||||
InputLabelProps={{
|
slotProps={{
|
||||||
shrink: true,
|
inputLabel: {
|
||||||
|
shrink: true,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
error={!!errors.date}
|
error={!!errors.date}
|
||||||
helperText={errors.date?.message}
|
helperText={errors.date?.message}
|
||||||
|
@ -64,8 +66,10 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
|
||||||
type="time"
|
type="time"
|
||||||
fullWidth
|
fullWidth
|
||||||
margin="normal"
|
margin="normal"
|
||||||
InputLabelProps={{
|
slotProps={{
|
||||||
shrink: true,
|
inputLabel: {
|
||||||
|
shrink: true,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
error={!!errors.startHour}
|
error={!!errors.startHour}
|
||||||
helperText={errors.startHour?.message}
|
helperText={errors.startHour?.message}
|
||||||
|
@ -106,20 +110,19 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
|
||||||
<Button onClick={handleClose} color="secondary">
|
<Button onClick={handleClose} color="secondary">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#52ACDF",
|
backgroundColor: "#52ACDF",
|
||||||
color: "white",
|
color: "white",
|
||||||
borderRadius: "8px",
|
borderRadius: "8px",
|
||||||
width: "100px",
|
width: "100px",
|
||||||
"&:hover": { backgroundColor: "#439BC1" },
|
"&:hover": { backgroundColor: "#439BC1" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add Booking
|
Add Booking
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
|
@ -19,11 +19,8 @@ import { RootState } from "../../redux/reducers.ts";
|
||||||
import {
|
import {
|
||||||
fetchVehicleBrands,
|
fetchVehicleBrands,
|
||||||
vehicleList,
|
vehicleList,
|
||||||
} from "../../redux/slices/VehicleSlice"; // Adjust this import path accordingly
|
} from "../../redux/slices/VehicleSlice.ts"; // Adjust this import path accordingly
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";// Assuming custom styled components
|
||||||
CustomIconButton,
|
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx"; // Assuming custom styled components
|
|
||||||
|
|
||||||
export default function AddStationModal({
|
export default function AddStationModal({
|
||||||
open,
|
open,
|
||||||
|
@ -262,7 +259,7 @@ export default function AddStationModal({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="body2" fontWeight={500}>
|
<Typography variant="body2" fontWeight={500}>
|
||||||
Select Vehicle Brands
|
Vehicle Brand
|
||||||
</Typography>
|
</Typography>
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<InputLabel>Choose Brands</InputLabel>
|
<InputLabel>Choose Brands</InputLabel>
|
||||||
|
@ -270,10 +267,53 @@ export default function AddStationModal({
|
||||||
multiple
|
multiple
|
||||||
value={selectedBrands}
|
value={selectedBrands}
|
||||||
onChange={handleBrandChange}
|
onChange={handleBrandChange}
|
||||||
renderValue={(selected) =>
|
renderValue={(selected) => {
|
||||||
(selected as string[]).join(", ")
|
const selectedArray =
|
||||||
}
|
selected as string[];
|
||||||
label="Choose Brands"
|
const displayNames =
|
||||||
|
selectedArray.slice(0, 1); // First 2 brands
|
||||||
|
const moreCount =
|
||||||
|
selectedArray.length - 1;
|
||||||
|
|
||||||
|
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.length > 0 ? (
|
||||||
vehicleBrands.map((brand) => (
|
vehicleBrands.map((brand) => (
|
||||||
|
@ -304,9 +344,7 @@ export default function AddStationModal({
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -317,16 +355,49 @@ export default function AddStationModal({
|
||||||
<Typography variant="body2" fontWeight={500}>
|
<Typography variant="body2" fontWeight={500}>
|
||||||
Vehicle Name
|
Vehicle Name
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<InputLabel>Choose Vehicles</InputLabel>
|
<InputLabel>Choose Vehicles</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
multiple
|
multiple
|
||||||
value={selectedVehicles}
|
value={selectedVehicles}
|
||||||
onChange={handleVehicleChange}
|
onChange={handleVehicleChange}
|
||||||
renderValue={(selected) =>
|
renderValue={(selected) => {
|
||||||
(selected as string[]).join(", ")
|
const selectedArray =
|
||||||
}
|
selected as string[];
|
||||||
|
const displayNames =
|
||||||
|
selectedArray.slice(0, 1); // First 2 vehicles
|
||||||
|
const moreCount =
|
||||||
|
selectedArray.length - 1;
|
||||||
|
|
||||||
|
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.length > 0 ? (
|
||||||
filteredVehicles.map((vehicle) => (
|
filteredVehicles.map((vehicle) => (
|
||||||
|
@ -341,7 +412,7 @@ export default function AddStationModal({
|
||||||
/>
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={vehicle.name}
|
primary={vehicle.name}
|
||||||
/>
|
/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
324
src/components/AddUserModal/addUserModal.tsx
Normal file
324
src/components/AddUserModal/addUserModal.tsx
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Modal,
|
||||||
|
InputAdornment,
|
||||||
|
styled,
|
||||||
|
} from "@mui/material";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import Visibility from "@mui/icons-material/Visibility";
|
||||||
|
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
||||||
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
import { CustomIconButton, CustomTextField } from "./styled.css.tsx";
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddUserModalProps {
|
||||||
|
open: boolean;
|
||||||
|
handleClose: () => void;
|
||||||
|
handleCreate: (data: FormData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddUserModal: React.FC<AddUserModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleClose,
|
||||||
|
handleCreate,
|
||||||
|
}) => {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
reset,
|
||||||
|
} = useForm<FormData>({
|
||||||
|
defaultValues: {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
phone: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = (data: FormData) => {
|
||||||
|
handleCreate(data);
|
||||||
|
handleClose();
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
setShowPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={(e, reason) => {
|
||||||
|
if (reason === "backdropClick") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
aria-labelledby="add-user-modal"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
width: 600,
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 3,
|
||||||
|
borderRadius: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" fontWeight={600}>
|
||||||
|
Add User
|
||||||
|
</Typography>
|
||||||
|
<CustomIconButton onClick={handleClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Horizontal Line */}
|
||||||
|
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
||||||
|
|
||||||
|
{/* Form */}
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{/* First Row - User Name & Email */}
|
||||||
|
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
User Name
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "User Name is required",
|
||||||
|
minLength: {
|
||||||
|
value: 3,
|
||||||
|
message:
|
||||||
|
"Minimum 3 characters required",
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 30,
|
||||||
|
message:
|
||||||
|
"Maximum 30 characters allowed",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter User Name"
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
error={!!errors.name}
|
||||||
|
helperText={errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="email"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Email is required",
|
||||||
|
pattern: {
|
||||||
|
value: /\S+@\S+\.\S+/,
|
||||||
|
message:
|
||||||
|
"Please enter a valid email address.",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
error={!!errors.email}
|
||||||
|
helperText={errors.email?.message}
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
color={
|
||||||
|
errors.email ? "error" : "primary"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Second Row - Password & Phone Number */}
|
||||||
|
<Box sx={{ display: "flex", gap: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Password
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="password"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Password is required",
|
||||||
|
minLength: {
|
||||||
|
value: 6,
|
||||||
|
message:
|
||||||
|
"Password must be at least 6 characters long.",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Password"
|
||||||
|
type={
|
||||||
|
showPassword ? "text" : "password"
|
||||||
|
}
|
||||||
|
fullWidth
|
||||||
|
color={
|
||||||
|
errors.password
|
||||||
|
? "error"
|
||||||
|
: "primary"
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
slotProps={{
|
||||||
|
input: {
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<CustomIconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={
|
||||||
|
togglePasswordVisibility
|
||||||
|
}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
{showPassword ? (
|
||||||
|
<VisibilityOff />
|
||||||
|
) : (
|
||||||
|
<Visibility />
|
||||||
|
)}
|
||||||
|
</CustomIconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
error={!!errors.password}
|
||||||
|
helperText={errors.password?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" fontWeight={500}>
|
||||||
|
Phone Number
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="phone"
|
||||||
|
control={control}
|
||||||
|
rules={{
|
||||||
|
required: "Phone number is required",
|
||||||
|
pattern: {
|
||||||
|
value: /^[0-9]*$/,
|
||||||
|
message: "Only numbers are allowed",
|
||||||
|
},
|
||||||
|
minLength: {
|
||||||
|
value: 6,
|
||||||
|
message:
|
||||||
|
"Phone number must be at least 6 digits",
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 14,
|
||||||
|
message:
|
||||||
|
"Phone number must be at most 14 digits",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
required
|
||||||
|
placeholder="Enter Phone Number"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.phone}
|
||||||
|
helperText={errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Submit Button */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
width: "100%",
|
||||||
|
mt: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
width: "117px",
|
||||||
|
"&:hover": { backgroundColor: "#439BC1" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add User
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddUserModal;
|
|
@ -6,10 +6,7 @@ import {
|
||||||
Modal,
|
Modal,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
CustomIconButton,
|
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
|
||||||
export default function AddVehicleModal({
|
export default function AddVehicleModal({
|
||||||
open,
|
open,
|
||||||
handleClose,
|
handleClose,
|
|
@ -11,7 +11,6 @@ import DashboardRoundedIcon from "@mui/icons-material/DashboardRounded";
|
||||||
import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown";
|
import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown";
|
||||||
import MenuButton from "../MenuButton";
|
import MenuButton from "../MenuButton";
|
||||||
import SideMenuMobile from "../SideMenuMobile";
|
import SideMenuMobile from "../SideMenuMobile";
|
||||||
import NotificationsRoundedIcon from "@mui/icons-material/NotificationsRounded";
|
|
||||||
|
|
||||||
const Toolbar = styled(MuiToolbar)({
|
const Toolbar = styled(MuiToolbar)({
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
import { styled } from "@mui/system";
|
import { styled } from "@mui/system";
|
||||||
import {
|
import {
|
||||||
fetchAvailableSlots,
|
fetchAvailableSlots,
|
||||||
availableSlots,
|
|
||||||
} from "../../redux/slices/slotSlice"; // Update with the correct import path
|
} from "../../redux/slices/slotSlice"; // Update with the correct import path
|
||||||
|
|
||||||
const SlotButton = styled(Button)<{ selected: boolean }>(({ selected }) => ({
|
const SlotButton = styled(Button)<{ selected: boolean }>(({ selected }) => ({
|
||||||
|
@ -38,7 +37,7 @@ const AvailableSlotsModal = ({
|
||||||
const { availableSlots, loading, error } = useSelector(
|
const { availableSlots, loading, error } = useSelector(
|
||||||
(state: any) => state.slotReducer.availableSlots
|
(state: any) => state.slotReducer.availableSlots
|
||||||
); // Adjust selector path
|
); // Adjust selector path
|
||||||
const [selectedSlot, setSelectedSlot] = useState<availableSlots | null>(
|
const [selectedSlot, setSelectedSlot] = useState<typeof availableSlots | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ const AvailableSlotsModal = ({
|
||||||
}
|
}
|
||||||
}, [open, dispatch]);
|
}, [open, dispatch]);
|
||||||
|
|
||||||
const handleSlotSelect = (slot: availableSlots) => {
|
const handleSlotSelect = (slot: typeof availableSlots) => {
|
||||||
setSelectedSlot(slot); // Update the selected slot
|
setSelectedSlot(slot); // Update the selected slot
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +78,7 @@ const AvailableSlotsModal = ({
|
||||||
<div style={{ color: "red" }}>Error: {error}</div>
|
<div style={{ color: "red" }}>Error: {error}</div>
|
||||||
) : Array.isArray(availableSlots) &&
|
) : Array.isArray(availableSlots) &&
|
||||||
availableSlots.length > 0 ? (
|
availableSlots.length > 0 ? (
|
||||||
availableSlots.map((slot: availableSlots) => (
|
availableSlots.map((slot: availableSlots) => (
|
||||||
<SlotButton
|
<SlotButton
|
||||||
key={slot?.id}
|
key={slot?.id}
|
||||||
onClick={() => handleSlotSelect(slot)}
|
onClick={() => handleSlotSelect(slot)}
|
|
@ -1,25 +1,28 @@
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import Card from '@mui/material/Card';
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from '@mui/material/CardContent';
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Button from '@mui/material/Button';
|
import Button from "@mui/material/Button";
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from "@mui/material/Typography";
|
||||||
import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded';
|
import AutoAwesomeRoundedIcon from "@mui/icons-material/AutoAwesomeRounded";
|
||||||
|
|
||||||
export default function CardAlert() {
|
export default function CardAlert() {
|
||||||
return (
|
return (
|
||||||
<Card variant="outlined" sx={{ m: 1.5, p: 1.5 }}>
|
<Card variant="outlined" sx={{ m: 1.5, p: 1.5 }}>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<AutoAwesomeRoundedIcon fontSize="small" />
|
<AutoAwesomeRoundedIcon fontSize="small" />
|
||||||
<Typography gutterBottom sx={{ fontWeight: 600 }}>
|
<Typography gutterBottom sx={{ fontWeight: 600 }}>
|
||||||
Plan about to expire
|
Plan about to expire
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" sx={{ mb: 2, color: 'text.secondary' }}>
|
<Typography
|
||||||
Enjoy 10% off when renewing your plan today.
|
variant="body2"
|
||||||
</Typography>
|
sx={{ mb: 2, color: "text.secondary" }}
|
||||||
<Button variant="contained" size="small" fullWidth>
|
>
|
||||||
Get the discount
|
Enjoy 10% off when renewing your plan today.
|
||||||
</Button>
|
</Typography>
|
||||||
</CardContent>
|
<Button variant="contained" size="small" fullWidth>
|
||||||
</Card>
|
Get the discount
|
||||||
);
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ import TableContainer from "@mui/material/TableContainer";
|
||||||
import TableHead from "@mui/material/TableHead";
|
import TableHead from "@mui/material/TableHead";
|
||||||
import TableRow from "@mui/material/TableRow";
|
import TableRow from "@mui/material/TableRow";
|
||||||
import Paper, { paperClasses } from "@mui/material/Paper";
|
import Paper, { paperClasses } from "@mui/material/Paper";
|
||||||
import { adminList, deleteAdmin } from "../../redux/slices/adminSlice";
|
import { adminList, deleteAdmin } from "../../redux/slices/adminSlice.ts";
|
||||||
import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice";
|
import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice.ts";
|
||||||
|
|
||||||
import { deleteManager, managerList } from "../../redux/slices/managerSlice";
|
import { deleteManager, managerList } from "../../redux/slices/managerSlice.ts";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
@ -23,15 +23,15 @@ import {
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded";
|
import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded";
|
||||||
import DeleteModal from "../Modals/DeleteModal";
|
import DeleteModal from "../Modals/DeleteModal/index.tsx";
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
import { AppDispatch, RootState } from "../../redux/store/store.ts";
|
||||||
import ViewModal from "../Modals/ViewModal";
|
import ViewModal from "../Modals/ViewModal/index.tsx";
|
||||||
import VehicleViewModal from "../Modals/VehicleViewModal";
|
import VehicleViewModal from "../Modals/VehicleViewModal/index.tsx";
|
||||||
|
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
import TuneIcon from "@mui/icons-material/Tune";
|
import TuneIcon from "@mui/icons-material/Tune";
|
||||||
import { CustomIconButton } from "../AddEditUserModel/styled.css.tsx";
|
import { CustomIconButton } from "../AddUserModal/styled.css";
|
||||||
import ManagerViewModal from "../Modals/ViewManagerModal";
|
import ManagerViewModal from "../Modals/ViewManagerModal/index.tsx";
|
||||||
import UserViewModal from "../Modals/UserViewModal/index.tsx";
|
import UserViewModal from "../Modals/UserViewModal/index.tsx";
|
||||||
import { deleteUser, userList } from "../../redux/slices/userSlice.ts";
|
import { deleteUser, userList } from "../../redux/slices/userSlice.ts";
|
||||||
import { deleteStation, stationList } from "../../redux/slices/stationSlice.ts";
|
import { deleteStation, stationList } from "../../redux/slices/stationSlice.ts";
|
||||||
|
@ -299,12 +299,14 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
InputProps={{
|
slotProps={{
|
||||||
startAdornment: (
|
input: {
|
||||||
<InputAdornment position="start">
|
startAdornment: (
|
||||||
<SearchIcon sx={{ color: "#52ACDF" }} />
|
<InputAdornment position="start">
|
||||||
</InputAdornment>
|
<SearchIcon sx={{ color: "#52ACDF" }} />
|
||||||
),
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
@ -502,36 +504,22 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
id="menu"
|
id="menu"
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onClick={handleClose}
|
transformOrigin={{ horizontal: "right", vertical: "top" }}
|
||||||
transformOrigin={{
|
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
|
||||||
horizontal: "right",
|
|
||||||
vertical: "top",
|
|
||||||
}}
|
|
||||||
anchorOrigin={{
|
|
||||||
horizontal: "right",
|
|
||||||
vertical: "bottom",
|
|
||||||
}}
|
|
||||||
sx={{
|
sx={{
|
||||||
[`& .${paperClasses.root}`]: {
|
[`& .${paperClasses.root}`]: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
},
|
},
|
||||||
"& .MuiList-root": {
|
"& .MuiList-root": {
|
||||||
background: "#272727", // Remove any divider under menu items
|
background: "#272727",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
// setSelectedRow(row);
|
|
||||||
setViewModal(true);
|
setViewModal(true);
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -544,6 +532,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{viewModal && tableType === "admin" && (
|
{viewModal && tableType === "admin" && (
|
||||||
<ViewModal
|
<ViewModal
|
||||||
handleView={() =>
|
handleView={() =>
|
||||||
|
@ -554,16 +543,6 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
id={selectedRow?.id}
|
id={selectedRow?.id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{viewModal && tableType === "vehicle" && (
|
|
||||||
<VehicleViewModal
|
|
||||||
handleView={() =>
|
|
||||||
handleViewButton(selectedRow?.id)
|
|
||||||
}
|
|
||||||
open={viewModal}
|
|
||||||
setViewModal={setViewModal}
|
|
||||||
id={selectedRow?.id}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{viewModal && tableType === "manager" && (
|
{viewModal && tableType === "manager" && (
|
||||||
<ManagerViewModal
|
<ManagerViewModal
|
||||||
handleView={() =>
|
handleView={() =>
|
||||||
|
@ -574,8 +553,9 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
id={selectedRow?.id}
|
id={selectedRow?.id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{viewModal && tableType === "user" && (
|
|
||||||
<UserViewModal
|
{viewModal && tableType === "vehicle" && (
|
||||||
|
<VehicleViewModal
|
||||||
handleView={() =>
|
handleView={() =>
|
||||||
handleViewButton(selectedRow?.id)
|
handleViewButton(selectedRow?.id)
|
||||||
}
|
}
|
||||||
|
@ -594,10 +574,28 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
id={selectedRow?.id}
|
id={selectedRow?.id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{viewModal && tableType === "user" && (
|
||||||
|
<UserViewModal
|
||||||
|
handleView={() =>
|
||||||
|
handleViewButton(selectedRow?.id)
|
||||||
|
}
|
||||||
|
open={viewModal}
|
||||||
|
setViewModal={setViewModal}
|
||||||
|
id={selectedRow?.id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Edit Button */}
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={() => setModalOpen(true)}
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setModalOpen(true);
|
||||||
|
if (selectedRow) {
|
||||||
|
setModalOpen(true); // Only open if a row is selected
|
||||||
|
setRowData(selectedRow);
|
||||||
|
}
|
||||||
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
|
@ -607,6 +605,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{tableType === "role" && (
|
{tableType === "role" && (
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
|
@ -626,6 +625,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
: "Activate"}
|
: "Activate"}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{tableType === "station" && (
|
{tableType === "station" && (
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
|
@ -646,6 +646,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Delete Button */}
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
@ -661,7 +662,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</div>
|
||||||
</Menu>
|
</Menu>
|
||||||
)}
|
)}
|
||||||
{/* Modals */}
|
{/* Modals */}
|
|
@ -1,153 +0,0 @@
|
||||||
// import React, { useEffect } from "react";
|
|
||||||
// import {
|
|
||||||
// Button,
|
|
||||||
// Dialog,
|
|
||||||
// DialogActions,
|
|
||||||
// DialogContent,
|
|
||||||
// DialogTitle,
|
|
||||||
// TextField,
|
|
||||||
// } from "@mui/material";
|
|
||||||
// import { useForm, Controller } from "react-hook-form";
|
|
||||||
|
|
||||||
// interface EditAdminModalProps {
|
|
||||||
// open: boolean;
|
|
||||||
// handleClose: () => void;
|
|
||||||
// handleUpdate: (id: string, name: string, email: string, phone: string, registeredAddress: string) => void;
|
|
||||||
// editRow: any;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface FormData {
|
|
||||||
// name: string;
|
|
||||||
// email: string;
|
|
||||||
// phone: string;
|
|
||||||
// registeredAddress: string;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const EditAdminModal: React.FC<EditAdminModalProps> = ({ open, handleClose, editRow, handleUpdate }) => {
|
|
||||||
// const { control, handleSubmit, setValue, reset, formState: { errors } } = useForm<FormData>({
|
|
||||||
// defaultValues: {
|
|
||||||
// name: "",
|
|
||||||
// email: "",
|
|
||||||
// phone: "",
|
|
||||||
// registeredAddress: "",
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (editRow) {
|
|
||||||
// setValue("name", editRow.name);
|
|
||||||
// setValue("email", editRow.email);
|
|
||||||
// setValue("phone", editRow.phone);
|
|
||||||
// setValue("registeredAddress", editRow.registeredAddress);
|
|
||||||
// } else {
|
|
||||||
// reset();
|
|
||||||
// }
|
|
||||||
// }, [editRow, setValue, reset]);
|
|
||||||
|
|
||||||
// const onSubmit = (data: FormData) => {
|
|
||||||
// if (editRow) {
|
|
||||||
// handleUpdate(editRow.id, data.name, data.email, data.phone, data.registeredAddress);
|
|
||||||
// handleClose();
|
|
||||||
// reset();
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Dialog
|
|
||||||
// open={open}
|
|
||||||
// onClose={handleClose}
|
|
||||||
// maxWidth="md"
|
|
||||||
// fullWidth
|
|
||||||
// PaperProps={{
|
|
||||||
// component: "form",
|
|
||||||
// onSubmit: handleSubmit(onSubmit),
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <DialogTitle>Edit Admin</DialogTitle>
|
|
||||||
// <DialogContent>
|
|
||||||
// <Controller
|
|
||||||
// name="name"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Admin Name is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// autoFocus
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Admin Name"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.name}
|
|
||||||
// helperText={errors.name?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="email"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Email is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Email"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.email}
|
|
||||||
// helperText={errors.email?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="phone"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Phone number is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Phone Number"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.phone}
|
|
||||||
// helperText={errors.phone?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// <Controller
|
|
||||||
// name="registeredAddress"
|
|
||||||
// control={control}
|
|
||||||
// rules={{ required: "Address is required" }}
|
|
||||||
// render={({ field }) => (
|
|
||||||
// <TextField
|
|
||||||
// {...field}
|
|
||||||
// required
|
|
||||||
// margin="dense"
|
|
||||||
// label="Address"
|
|
||||||
// type="text"
|
|
||||||
// fullWidth
|
|
||||||
// variant="standard"
|
|
||||||
// error={!!errors.registeredAddress}
|
|
||||||
// helperText={errors.registeredAddress?.message}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// />
|
|
||||||
// </DialogContent>
|
|
||||||
// <DialogActions>
|
|
||||||
// <Button onClick={handleClose}>Cancel</Button>
|
|
||||||
// <Button type="submit">Save</Button>
|
|
||||||
// </DialogActions>
|
|
||||||
// </Dialog>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default EditAdminModal;
|
|
237
src/components/EditAdminModal/editAdminModal.tsx
Normal file
237
src/components/EditAdminModal/editAdminModal.tsx
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { Box, Button, Typography, Modal } from "@mui/material";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
|
||||||
|
|
||||||
|
interface EditAdminModalProps {
|
||||||
|
open: boolean;
|
||||||
|
handleClose: () => void;
|
||||||
|
handleUpdate: (
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
registeredAddress: string
|
||||||
|
) => void;
|
||||||
|
editRow: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
registeredAddress: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditAdminModal: React.FC<EditAdminModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleClose,
|
||||||
|
handleUpdate,
|
||||||
|
editRow,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
setValue,
|
||||||
|
reset,
|
||||||
|
} = useForm<FormData>({
|
||||||
|
defaultValues: {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
registeredAddress: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (editRow) {
|
||||||
|
setValue("name", editRow.name);
|
||||||
|
setValue("email", editRow.email);
|
||||||
|
setValue("phone", editRow.phone);
|
||||||
|
setValue(
|
||||||
|
"registeredAddress",
|
||||||
|
editRow.Admins?.[0]?.registeredAddress || ""
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}, [editRow, setValue, reset]);
|
||||||
|
|
||||||
|
|
||||||
|
const onSubmit = (data: FormData) => {
|
||||||
|
if (editRow) {
|
||||||
|
handleUpdate(
|
||||||
|
editRow.id,
|
||||||
|
data.name,
|
||||||
|
data.email,
|
||||||
|
data.phone,
|
||||||
|
data.registeredAddress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
handleClose();
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={(e, reason) => {
|
||||||
|
if (reason === "backdropClick") return;
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
aria-labelledby="edit-admin-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 Admin
|
||||||
|
</Typography>
|
||||||
|
<CustomIconButton onClick={handleClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Horizontal Line */}
|
||||||
|
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
||||||
|
|
||||||
|
{/* Input Fields */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
||||||
|
{/* Name */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Full Name
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Name is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Full Name"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.name}
|
||||||
|
helperText={errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Email */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="email"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Email is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
type="email"
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Email"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.email}
|
||||||
|
helperText={errors.email?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Phone */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Phone Number
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="phone"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Phone number is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Phone Number"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.phone}
|
||||||
|
helperText={errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Address */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Address
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="registeredAddress"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Address is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Address"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.registeredAddress}
|
||||||
|
helperText={
|
||||||
|
errors.registeredAddress?.message
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</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 Admin
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditAdminModal;
|
|
@ -9,11 +9,8 @@ import {
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { managerList, updateManager } from "../../redux/slices/managerSlice"; // Import the updateManager action
|
import { managerList, updateManager } from "../../redux/slices/managerSlice.ts"; // Import the updateManager action
|
||||||
import {
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";// Custom styled components
|
||||||
CustomIconButton,
|
|
||||||
CustomTextField,
|
|
||||||
} from "../AddEditUserModel/styled.css.tsx"; // Custom styled components
|
|
||||||
import { AppDispatch } from "../../redux/store/store.ts";
|
import { AppDispatch } from "../../redux/store/store.ts";
|
||||||
|
|
||||||
interface EditManagerModalProps {
|
interface EditManagerModalProps {
|
||||||
|
@ -82,7 +79,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
|
||||||
email: data.email,
|
email: data.email,
|
||||||
phone: data.phone,
|
phone: data.phone,
|
||||||
stationId: data.stationId,
|
stationId: data.stationId,
|
||||||
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
).unwrap(); // Ensure that it throws an error if the update fails
|
).unwrap(); // Ensure that it throws an error if the update fails
|
||||||
|
@ -225,26 +221,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Box sx={{ flex: "1 1 48%" }}>
|
|
||||||
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
|
||||||
StationId
|
|
||||||
</Typography>
|
|
||||||
<Controller
|
|
||||||
name="stationId"
|
|
||||||
control={control}
|
|
||||||
rules={{ required: "StationId is required" }}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomTextField
|
|
||||||
{...field}
|
|
||||||
fullWidth
|
|
||||||
placeholder="Enter Station Id"
|
|
||||||
size="small"
|
|
||||||
error={!!errors.stationId}
|
|
||||||
helperText={errors.stationId?.message}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Box> */}
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
|
@ -260,7 +236,7 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
|
||||||
width: "117px",
|
width: "117px",
|
||||||
"&:hover": { backgroundColor: "#439BC1" },
|
"&:hover": { backgroundColor: "#439BC1" },
|
||||||
}}
|
}}
|
||||||
disabled={loading} // Disable the button during loading state
|
disabled={loading}
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<CircularProgress size={24} color="inherit" />
|
<CircularProgress size={24} color="inherit" />
|
||||||
|
@ -273,4 +249,4 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default EditManagerModal;
|
export default EditManagerModal;
|
|
@ -9,11 +9,11 @@ import {
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { updateSlot, fetchAvailableSlots } from "../../redux/slices/slotSlice"; // Update with correct action
|
|
||||||
import {
|
import {
|
||||||
CustomIconButton,
|
updateSlot,
|
||||||
CustomTextField,
|
fetchAvailableSlots,
|
||||||
} from "../AddEditUserModel/styled.css.tsx"; // Custom styled components
|
} from "../../redux/slices/slotSlice.ts"; // Update with correct action
|
||||||
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components
|
||||||
import { AppDispatch } from "../../redux/store/store.ts";
|
import { AppDispatch } from "../../redux/store/store.ts";
|
||||||
|
|
||||||
interface EditSlotModalProps {
|
interface EditSlotModalProps {
|
||||||
|
@ -40,7 +40,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
handleClose,
|
handleClose,
|
||||||
editRow,
|
editRow,
|
||||||
}) => {
|
}) => {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
@ -65,7 +65,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
if (editRow) {
|
if (editRow) {
|
||||||
setValue("startTime", editRow.startTime);
|
setValue("startTime", editRow.startTime);
|
||||||
setValue("endTime", editRow.endTime);
|
setValue("endTime", editRow.endTime);
|
||||||
setIsAvailable(editRow.isAvailable);
|
setIsAvailable(editRow.isAvailable);
|
||||||
} else {
|
} else {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
@ -73,10 +73,9 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
const onSubmit = async (data: FormData) => {
|
||||||
if (editRow) {
|
if (editRow) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const availabilityStatus = isAvailable ? true : false;
|
const availabilityStatus = isAvailable ? true : false;
|
||||||
|
|
||||||
await dispatch(
|
await dispatch(
|
||||||
|
@ -86,7 +85,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
endTime: data.endTime,
|
endTime: data.endTime,
|
||||||
isAvailable: availabilityStatus,
|
isAvailable: availabilityStatus,
|
||||||
})
|
})
|
||||||
).unwrap();
|
).unwrap();
|
||||||
dispatch(fetchAvailableSlots());
|
dispatch(fetchAvailableSlots());
|
||||||
handleClose(); // Close modal on success
|
handleClose(); // Close modal on success
|
||||||
reset(); // Reset form fields after submit
|
reset(); // Reset form fields after submit
|
||||||
|
@ -146,27 +145,6 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
|
|
||||||
{/* Input Fields */}
|
{/* Input Fields */}
|
||||||
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
|
<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 */}
|
{/* Start Time */}
|
||||||
<Box sx={{ flex: "1 1 48%" }}>
|
<Box sx={{ flex: "1 1 48%" }}>
|
|
@ -23,7 +23,7 @@ import {
|
||||||
import {
|
import {
|
||||||
CustomIconButton,
|
CustomIconButton,
|
||||||
CustomTextField,
|
CustomTextField,
|
||||||
} from "../AddEditUserModel/styled.css.tsx"; // Assuming custom styled components
|
} from "../AddUserModal/styled.css"; // Assuming custom styled components
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -121,7 +121,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
const onSubmit = (data: FormData) => {
|
const onSubmit = (data: FormData) => {
|
||||||
const vehicleIds = vehicles
|
const vehicleIds = vehicles
|
||||||
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
|
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
|
||||||
.map((vehicle) => vehicle.id);
|
.map((vehicle) => Number(vehicle.id));
|
||||||
|
|
||||||
handleUpdate(
|
handleUpdate(
|
||||||
editRow.id,
|
editRow.id,
|
||||||
|
@ -135,6 +135,8 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
//setSelectedBrands([]); // Reset brands after submit
|
//setSelectedBrands([]); // Reset brands after submit
|
||||||
setSelectedVehicles([]); // Reset selected vehicles
|
setSelectedVehicles([]); // Reset selected vehicles
|
||||||
};
|
};
|
||||||
|
console.log("editRow:", editRow);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -311,6 +313,52 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
value={selectedBrands}
|
value={selectedBrands}
|
||||||
onChange={handleBrandChange}
|
onChange={handleBrandChange}
|
||||||
label="Choose Brands"
|
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.length > 0 ? (
|
||||||
vehicleBrands.map((brand) => (
|
vehicleBrands.map((brand) => (
|
||||||
|
@ -336,6 +384,8 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Box>
|
</Box>
|
||||||
|
{/* </Box>
|
||||||
|
<Box sx={{ display: "flex", gap: 2 }}> */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -352,9 +402,43 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
multiple
|
multiple
|
||||||
value={selectedVehicles}
|
value={selectedVehicles}
|
||||||
onChange={handleCheckboxChange}
|
onChange={handleCheckboxChange}
|
||||||
renderValue={(selected) =>
|
renderValue={(selected) => {
|
||||||
(selected as string[]).join(", ")
|
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.length > 0 ? (
|
||||||
filteredVehicles.map((vehicle) => (
|
filteredVehicles.map((vehicle) => (
|
||||||
|
@ -378,6 +462,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<FormHelperText>
|
<FormHelperText>
|
||||||
{errors.allowedCarIds
|
{errors.allowedCarIds
|
||||||
? errors.allowedCarIds.message
|
? errors.allowedCarIds.message
|
||||||
|
@ -388,8 +473,6 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
<Box
|
<Box
|
||||||
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}
|
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}
|
211
src/components/EditUserModal/editUserModal.tsx
Normal file
211
src/components/EditUserModal/editUserModal.tsx
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { Box, Button, Typography, Modal } from "@mui/material";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
import {
|
||||||
|
CustomIconButton,
|
||||||
|
CustomTextField,
|
||||||
|
} from "../AddUserModal/styled.css";
|
||||||
|
|
||||||
|
interface EditUserModalProps {
|
||||||
|
open: boolean;
|
||||||
|
handleClose: () => void;
|
||||||
|
handleUpdate: (
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
) => void;
|
||||||
|
editRow: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditUserModal: React.FC<EditUserModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleClose,
|
||||||
|
handleUpdate,
|
||||||
|
editRow,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
setValue,
|
||||||
|
reset,
|
||||||
|
} = useForm<FormData>({
|
||||||
|
defaultValues: {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set values if editRow is provided
|
||||||
|
useEffect(() => {
|
||||||
|
if (editRow) {
|
||||||
|
setValue("name", editRow.name);
|
||||||
|
setValue("email", editRow.email);
|
||||||
|
setValue("phone", editRow.phone);
|
||||||
|
} else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}, [editRow, setValue, reset]);
|
||||||
|
|
||||||
|
const onSubmit = (data: FormData) => {
|
||||||
|
if (editRow) {
|
||||||
|
handleUpdate(
|
||||||
|
editRow.id,
|
||||||
|
data.name,
|
||||||
|
data.email,
|
||||||
|
data.phone,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
handleClose(); // Close the modal
|
||||||
|
reset(); // Reset the form fields
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={(e, reason) => {
|
||||||
|
if (reason === "backdropClick") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
aria-labelledby="edit-user-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 User
|
||||||
|
</Typography>
|
||||||
|
<CustomIconButton onClick={handleClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Horizontal Line */}
|
||||||
|
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
|
||||||
|
|
||||||
|
{/* Input Fields */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
||||||
|
{/* Name */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Full Name
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Name is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Full Name"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.name}
|
||||||
|
helperText={errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Email */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="email"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Email is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
type="email"
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Email"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.email}
|
||||||
|
helperText={errors.email?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Phone */}
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
Phone Number
|
||||||
|
</Typography>
|
||||||
|
<Controller
|
||||||
|
name="phone"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: "Phone number is required" }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder="Enter Phone Number"
|
||||||
|
size="small"
|
||||||
|
error={!!errors.phone}
|
||||||
|
helperText={errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</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 User
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditUserModal;
|
|
@ -11,7 +11,7 @@ import { updateVehicle } from "../../redux/slices/VehicleSlice";
|
||||||
import {
|
import {
|
||||||
CustomIconButton,
|
CustomIconButton,
|
||||||
CustomTextField,
|
CustomTextField,
|
||||||
} from "../AddEditUserModel/styled.css.tsx";
|
} from "../AddUserModal/styled.css";
|
||||||
interface EditVehicleModalProps {
|
interface EditVehicleModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
|
@ -5,17 +5,11 @@ import Box from "@mui/material/Box";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import InputBase from "@mui/material/InputBase";
|
import InputBase from "@mui/material/InputBase";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
import Divider from "@mui/material/Divider";
|
|
||||||
import MenuButton from "../MenuButton";
|
|
||||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
|
||||||
import NotificationsRoundedIcon from "@mui/icons-material/NotificationsRounded";
|
|
||||||
import SideMenu from "../SideMenu";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
import { fetchAdminProfile } from "../../redux/slices/profileSlice";
|
import { fetchAdminProfile } from "../../redux/slices/profileSlice";
|
||||||
import OptionsMenu from "../OptionsMenu";
|
import OptionsMenu from "../OptionsMenu";
|
||||||
import NotificationsNoneIcon from "@mui/icons-material/NotificationsNone";
|
import NotificationsNoneIcon from "@mui/icons-material/NotificationsNone";
|
||||||
import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown";
|
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const [showNotifications, setShowNotifications] = React.useState(false);
|
const [showNotifications, setShowNotifications] = React.useState(false);
|
||||||
|
@ -36,7 +30,7 @@ export default function Header() {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
// height: "84px",
|
// height: "84px",
|
||||||
// backgroundColor: "#1C1C1C",
|
// backgroundColor: "#1C1C1C",
|
||||||
padding: { xs: "20px 12px", sm: "20px 24px" }, // Adjust padding based on screen size // error on this
|
padding: { xs: "20px 12px", sm: "20px 24px" },
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
|
|
@ -2,13 +2,12 @@ import * as React from "react";
|
||||||
import { useTheme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Chip from "@mui/material/Chip";
|
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Stack from "@mui/material/Stack";
|
|
||||||
import { LineChart } from "@mui/x-charts/LineChart";
|
import { LineChart } from "@mui/x-charts/LineChart";
|
||||||
import { Box } from "@mui/material";
|
import { FormControl, MenuItem, Select } from "@mui/material";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
function AreaGradient({ color, id }: { color: string; id: string }) {
|
function AreaGradient({ color, id }: { color: string; id: string }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id={id} x1="50%" y1="0%" x2="50%" y2="100%">
|
<linearGradient id={id} x1="50%" y1="0%" x2="50%" y2="100%">
|
||||||
|
@ -39,6 +38,12 @@ export default function LineChartCard() {
|
||||||
const data = getDaysInMonth(4, 2024);
|
const data = getDaysInMonth(4, 2024);
|
||||||
|
|
||||||
const colorPalette = [theme.palette.primary.light];
|
const colorPalette = [theme.palette.primary.light];
|
||||||
|
const [selectedOption, setSelectedOption] = React.useState("Weekly");
|
||||||
|
|
||||||
|
const handleChange = (event: { target: { value: React.SetStateAction<string>; }; }) => {
|
||||||
|
setSelectedOption(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
@ -73,7 +78,7 @@ export default function LineChartCard() {
|
||||||
>
|
>
|
||||||
Sales Stats
|
Sales Stats
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<FormControl
|
||||||
sx={{
|
sx={{
|
||||||
mt: 2,
|
mt: 2,
|
||||||
mb: 2,
|
mb: 2,
|
||||||
|
@ -83,38 +88,32 @@ export default function LineChartCard() {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
p: 1.5,
|
// p: 1.5,
|
||||||
borderRadius: "8px",
|
|
||||||
border: "1px solid #454545",
|
|
||||||
color: "#F2F2F2",
|
color: "#F2F2F2",
|
||||||
|
width: "149px",
|
||||||
width: "129px",
|
|
||||||
height: "44px",
|
height: "44px",
|
||||||
padding: "12px 16px",
|
padding: "12px 16px",
|
||||||
gap: "8px",
|
gap: "8px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Select
|
||||||
width={"69px"}
|
value={selectedOption}
|
||||||
height={"16px"}
|
onChange={handleChange}
|
||||||
sx={{
|
sx={{
|
||||||
fontWeight: 500,
|
//backgroundColor: "#202020",
|
||||||
fontSize: "14px",
|
|
||||||
lineHeight: "24px",
|
|
||||||
color: "#D9D8D8",
|
color: "#D9D8D8",
|
||||||
|
".MuiSelect-icon": {
|
||||||
textAlign: "center",
|
color: "#F2F2F2", // Icon color
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
|
IconComponent={ExpandMoreIcon}
|
||||||
>
|
>
|
||||||
Weekly
|
<MenuItem value="Monthly">Monthly</MenuItem>
|
||||||
</Typography>
|
<MenuItem value="Weekly">Weekly</MenuItem>
|
||||||
<ExpandMoreIcon
|
<MenuItem value="Daily">Daily</MenuItem>
|
||||||
width="20px"
|
<MenuItem value="Yearly">Yearly</MenuItem>
|
||||||
height="20px"
|
</Select>
|
||||||
|
</FormControl>
|
||||||
sx={{ color: "#F2F2F2" }}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LineChart
|
<LineChart
|
|
@ -1,21 +1,12 @@
|
||||||
import * as React from "react";
|
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid2";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Stack from "@mui/material/Stack";
|
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Copyright from "../../pages/Dashboard/internals/components/Copyright";
|
import SessionsChart from "../SessionsChart/sessionChart";
|
||||||
import ChartUserByCountry from "../ChartUserByCountry";
|
import StatCard, { StatCardProps } from "../StatCard/statCard";
|
||||||
import CustomizedTreeView from "../CustomizedTreeView";
|
import ResourcesPieChart from "../ResourcePieChart/resourcePieChart";
|
||||||
import CustomizedDataGrid from "../CustomizedDataGrid";
|
import RoundedBarChart from "../barChartCard/barChartCard";
|
||||||
import HighlightedCard from "../HighlightedCard";
|
import LineChartCard from "../LineChartCard/lineChartCard";
|
||||||
import PageViewsBarChart from "../PageViewsBarChart";
|
|
||||||
import SessionsChart from "../SessionsChart";
|
|
||||||
import StatCard, { StatCardProps } from "../StatCard";
|
|
||||||
import ResourcesPieChart from "../ResourcePieChart";
|
|
||||||
import { BarChart } from "@mui/icons-material";
|
|
||||||
import RoundedBarChart from "../barChartCard";
|
|
||||||
import { LineHighlightPlot } from "@mui/x-charts";
|
|
||||||
import LineChartCard from "../LineChartCard";
|
|
||||||
|
|
||||||
const data: StatCardProps[] = [
|
const data: StatCardProps[] = [
|
||||||
{
|
{
|
|
@ -4,15 +4,11 @@ import ListItemButton from "@mui/material/ListItemButton";
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import ListItemText from "@mui/material/ListItemText";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import HomeRoundedIcon from "@mui/icons-material/HomeRounded";
|
|
||||||
import AnalyticsRoundedIcon from "@mui/icons-material/AnalyticsRounded";
|
|
||||||
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
|
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { RootState } from "../../redux/store/store";
|
import { RootState } from "../../redux/store/store";
|
||||||
import DashboardOutlinedIcon from "@mui/icons-material/DashboardOutlined";
|
import DashboardOutlinedIcon from "@mui/icons-material/DashboardOutlined";
|
||||||
import ManageAccountsOutlinedIcon from "@mui/icons-material/ManageAccountsOutlined";
|
import ManageAccountsOutlinedIcon from "@mui/icons-material/ManageAccountsOutlined";
|
||||||
import EvStationOutlinedIcon from "@mui/icons-material/EvStationOutlined";
|
|
||||||
import EvStationIcon from "@mui/icons-material/EvStation";
|
import EvStationIcon from "@mui/icons-material/EvStation";
|
||||||
import BookOnlineOutlinedIcon from "@mui/icons-material/BookOnlineOutlined";
|
import BookOnlineOutlinedIcon from "@mui/icons-material/BookOnlineOutlined";
|
||||||
import ChecklistSharpIcon from "@mui/icons-material/ChecklistSharp";
|
import ChecklistSharpIcon from "@mui/icons-material/ChecklistSharp";
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Box, Button, Modal, Typography } from "@mui/material";
|
import { Box, Button, IconButton, Modal, Typography } from "@mui/material";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { CustomIconButton } from "../../AddUserModal/styled.css";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -14,7 +15,7 @@ const style = {
|
||||||
left: "50%",
|
left: "50%",
|
||||||
transform: "translate(-50%, -50%)",
|
transform: "translate(-50%, -50%)",
|
||||||
width: 330,
|
width: 330,
|
||||||
bgcolor: "background.paper",
|
bgcolor: "#272727",
|
||||||
borderRadius: 1.5,
|
borderRadius: 1.5,
|
||||||
boxShadow: 24,
|
boxShadow: 24,
|
||||||
p: 3,
|
p: 3,
|
||||||
|
@ -47,17 +48,22 @@ export default function DeleteModal({
|
||||||
Delete Record
|
Delete Record
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<Box
|
||||||
onClick={() => setDeleteModal(false)}
|
|
||||||
sx={{
|
sx={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "flex-end", // Aligns the close icon to the right
|
justifyContent: "flex-end",
|
||||||
marginTop: -3.5,
|
marginTop: -3.5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CustomIconButton
|
||||||
|
onClick={() => setDeleteModal(false)}
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
id="modal-modal-description"
|
id="modal-modal-description"
|
||||||
sx={{ mt: 2 }}
|
sx={{ mt: 2 }}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Box, Button, Modal, Typography } from "@mui/material";
|
import { Box, Button, Modal, Typography } from "@mui/material";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { CustomIconButton } from "../../AddUserModal/styled.css";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -13,7 +14,7 @@ const style = {
|
||||||
left: "50%",
|
left: "50%",
|
||||||
transform: "translate(-50%, -50%)",
|
transform: "translate(-50%, -50%)",
|
||||||
width: 330,
|
width: 330,
|
||||||
bgcolor: "background.paper",
|
bgcolor: "#272727",
|
||||||
borderRadius: 1.5,
|
borderRadius: 1.5,
|
||||||
boxShadow: 24,
|
boxShadow: 24,
|
||||||
p: 3,
|
p: 3,
|
||||||
|
@ -35,13 +36,16 @@ export default function LogoutModal({
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={open}
|
open={open}
|
||||||
onClose={(e, reason) =>
|
onClose={(event, reason) => {
|
||||||
reason !== "backdropClick" && setLogoutModal(false)
|
if (reason !== "backdropClick") {
|
||||||
} // Prevent closing on backdrop click
|
setLogoutModal(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
aria-labelledby="modal-modal-title"
|
aria-labelledby="modal-modal-title"
|
||||||
aria-describedby="modal-modal-description"
|
aria-describedby="modal-modal-description"
|
||||||
|
disableEscapeKeyDown // Prevent closing with the ESC key
|
||||||
BackdropProps={{
|
BackdropProps={{
|
||||||
onClick: (e) => e.stopPropagation(), // Stop propagation on backdrop click to prevent closing the modal
|
invisible: true, // Use to control backdrop visibility
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={style}>
|
<Box sx={style}>
|
||||||
|
@ -61,14 +65,18 @@ export default function LogoutModal({
|
||||||
>
|
>
|
||||||
<Box sx={{ flex: 1, textAlign: "center" }}>Logout</Box>
|
<Box sx={{ flex: 1, textAlign: "center" }}>Logout</Box>
|
||||||
<Box
|
<Box
|
||||||
onClick={() => setLogoutModal(false)}
|
|
||||||
sx={{
|
sx={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CustomIconButton
|
||||||
|
onClick={() => setLogoutModal(false)}
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</CustomIconButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Box, Modal, Typography, Divider, Grid } from "@mui/material";
|
import { Box, Modal, Typography, Divider, Grid, Chip } from "@mui/material";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { RootState } from "../../../redux/reducers";
|
import { RootState } from "../../../redux/reducers";
|
||||||
|
import { CustomIconButton } from "../../AddUserModal/styled.css";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setViewModal: Function;
|
setViewModal: Function;
|
||||||
handleView: (id: string | undefined) => void;
|
handleView: (id: number | undefined) => void;
|
||||||
id?: string | undefined;
|
id?: number | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
|
@ -64,16 +65,12 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
|
||||||
<Box sx={{ flex: 1, textAlign: "center" }}>
|
<Box sx={{ flex: 1, textAlign: "center" }}>
|
||||||
{selectedStation?.name || "Station"}'s Details
|
{selectedStation?.name || "Station"}'s Details
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<CustomIconButton
|
||||||
onClick={() => setViewModal(false)}
|
onClick={() => setViewModal(false)}
|
||||||
sx={{
|
aria-label="Close"
|
||||||
cursor: "pointer",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</Box>
|
</CustomIconButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
@ -109,12 +106,52 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
<strong>Status:</strong>
|
<strong>Status:</strong>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{selectedStation.status === "available"
|
{selectedStation.status === 1
|
||||||
? "Available"
|
? "Available"
|
||||||
: "Not Available"}
|
: "Not Available"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
{/* Display Vehicles */}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Typography variant="body1">
|
||||||
|
<strong>Vehicles:</strong>
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
gap: 1,
|
||||||
|
marginTop: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedStation.allowedCars &&
|
||||||
|
selectedStation.allowedCars.length > 0 ? (
|
||||||
|
selectedStation.allowedCars.map(
|
||||||
|
(car: any, index: number) => (
|
||||||
|
<Typography
|
||||||
|
key={car.id || index}
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
color: "#FFFFFF",
|
||||||
|
fontWeight: 500,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{car.name}{","}
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
>
|
||||||
|
No vehicles available
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : (
|
) : (
|
||||||
<Typography align="center">
|
<Typography align="center">
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { RootState } from "../../../redux/reducers";
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setViewModal: Function;
|
setViewModal: Function;
|
||||||
handleView: (id: string | undefined) => void;
|
handleView: (id: number | undefined) => void;
|
||||||
id?: number | undefined;
|
id?: number | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import * as React from "react";
|
|
||||||
import { PieChart } from "@mui/x-charts/PieChart";
|
import { PieChart } from "@mui/x-charts/PieChart";
|
||||||
import { useDrawingArea } from "@mui/x-charts/hooks";
|
|
||||||
import { styled } from "@mui/material/styles";
|
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
|
@ -3,10 +3,20 @@ import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
import Select from "@mui/material/Select";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import FormControl from "@mui/material/FormControl";
|
||||||
|
import InputLabel from "@mui/material/InputLabel";
|
||||||
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
export default function SessionsChart() {
|
export default function SessionsChart() {
|
||||||
|
const [selectedStation, setSelectedStation] = React.useState(
|
||||||
|
"Delhi NCR EV Station"
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = (event: { target: { value: React.SetStateAction<string>; }; }) => {
|
||||||
|
setSelectedStation(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -19,7 +29,6 @@ export default function SessionsChart() {
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
backgroundColor: "#202020",
|
backgroundColor: "#202020",
|
||||||
},
|
},
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
@ -42,40 +51,43 @@ export default function SessionsChart() {
|
||||||
Charging prices
|
Charging prices
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{/* Responsive dropdown box */}
|
{/* Dropdown button */}
|
||||||
<Box
|
<FormControl
|
||||||
sx={{
|
sx={{
|
||||||
mt: 2,
|
mt: 2,
|
||||||
mb: 2,
|
mb: 2,
|
||||||
backgroundColor: "#202020",
|
width: "100%",
|
||||||
fontSize: "14px",
|
// backgroundColor: "#202020",
|
||||||
lineHeight: "20px",
|
|
||||||
width: { xs: "100%" },
|
|
||||||
height: "48px",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
p: 1.5,
|
|
||||||
borderRadius: "8px",
|
|
||||||
border: "1px solid #454545",
|
border: "1px solid #454545",
|
||||||
|
borderRadius: "8px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
|
||||||
width="134px"
|
<Select
|
||||||
height="24px"
|
value={selectedStation}
|
||||||
|
onChange={handleChange}
|
||||||
|
label="Select Station"
|
||||||
sx={{
|
sx={{
|
||||||
fontFamily: "Gilroy",
|
//backgroundColor: "#202020",
|
||||||
fontWeight: 500,
|
|
||||||
fontSize: "14px",
|
|
||||||
lineHeight: "24px",
|
|
||||||
color: "#D9D8D8",
|
color: "#D9D8D8",
|
||||||
|
"& .MuiSvgIcon-root": { color: "#F2F2F2" },
|
||||||
}}
|
}}
|
||||||
|
IconComponent={ExpandMoreIcon}
|
||||||
>
|
>
|
||||||
Delhi NCR EV Station
|
<MenuItem value="Delhi NCR EV Station">
|
||||||
</Typography>
|
Delhi NCR EV Station
|
||||||
<ArrowDropDownIcon sx={{ color: "#F2F2F2" }} />
|
</MenuItem>
|
||||||
</Box>
|
<MenuItem value="Mumbai EV Station">
|
||||||
|
Mumbai EV Station
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value="Bangalore EV Station">
|
||||||
|
Bangalore EV Station
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value="Pune EV Station">
|
||||||
|
Pune EV Station
|
||||||
|
</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
{/* Grid container for the four boxes */}
|
{/* Grid container for the four boxes */}
|
||||||
<Box
|
<Box
|
|
@ -32,9 +32,9 @@ export default function SideMenu() {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
dispatch(fetchAdminProfile());
|
// dispatch(fetchAdminProfile());
|
||||||
}, [dispatch]);
|
// }, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
|
@ -59,9 +59,10 @@ export default function SideMenu() {
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
|
justifyContent:"center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
pt: 2,
|
pt: 2,
|
||||||
pl: 2,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
@ -69,7 +70,7 @@ export default function SideMenu() {
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
style={{
|
style={{
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
width: open ? "200px" : "60px", // Adjust width depending on open state
|
width: open ? "120px" : "60px", // Adjust width depending on open state
|
||||||
height: "auto",
|
height: "auto",
|
||||||
transition: "width 0.5s ease", // Smooth transition for width change
|
transition: "width 0.5s ease", // Smooth transition for width change
|
||||||
}}
|
}}
|
|
@ -26,9 +26,9 @@ export default function SideMenuMobile({
|
||||||
}: SideMenuMobileProps) {
|
}: SideMenuMobileProps) {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
||||||
React.useEffect(() => {
|
// React.useEffect(() => {
|
||||||
dispatch(fetchAdminProfile());
|
// dispatch(fetchAdminProfile());
|
||||||
}, [dispatch]);
|
// }, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
import * as React from "react";
|
|
||||||
import { useTheme } from "@mui/material/styles";
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Chip from "@mui/material/Chip";
|
|
||||||
import Stack from "@mui/material/Stack";
|
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import { SparkLineChart } from "@mui/x-charts/SparkLineChart";
|
|
||||||
import { areaElementClasses } from "@mui/x-charts/LineChart";
|
|
||||||
|
|
||||||
export type StatCardProps = {
|
export type StatCardProps = {
|
||||||
title: string;
|
title: string;
|
130
src/components/barChartCard/barChartCard.tsx
Normal file
130
src/components/barChartCard/barChartCard.tsx
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Typography,
|
||||||
|
Box,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
FormControl,
|
||||||
|
SelectChangeEvent,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { BarChart } from "@mui/x-charts/BarChart";
|
||||||
|
import { axisClasses } from "@mui/x-charts/ChartsAxis";
|
||||||
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
|
// Sample Data
|
||||||
|
const data = [
|
||||||
|
{ name: "Jan", v1: 40 },
|
||||||
|
{ name: "Feb", v1: 50 },
|
||||||
|
{ name: "Mar", v1: 80 },
|
||||||
|
{ name: "Apr", v1: 20 },
|
||||||
|
{ name: "May", v1: 60 },
|
||||||
|
{ name: "Jun", v1: 30 },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Chart Configuration
|
||||||
|
const chartSetting = {
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
label: "Value",
|
||||||
|
tickFormatter: (value: number) => `${value}`, // Formatting Y-axis ticks
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
dataKey: "name",
|
||||||
|
scaleType: "band" as const,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
width: 500,
|
||||||
|
height: 300,
|
||||||
|
sx: {
|
||||||
|
[`.${axisClasses.left} .${axisClasses.label}`]: {
|
||||||
|
transform: "translate(-20px, 0)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RoundedBarChart() {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [selectedOption, setSelectedOption] = React.useState("Monthly");
|
||||||
|
|
||||||
|
const handleChange = (event: SelectChangeEvent<string>) => {
|
||||||
|
setSelectedOption(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
width: "553px",
|
||||||
|
height: "444px",
|
||||||
|
borderRadius: "16px",
|
||||||
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" color="#F2F2F2">
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
color="#F2F2F2"
|
||||||
|
sx={{
|
||||||
|
fontFamily: "Gilroy",
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: "18px",
|
||||||
|
lineHeight: "24px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Charge Stats
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<FormControl
|
||||||
|
sx={{
|
||||||
|
mt: 2,
|
||||||
|
ml: "auto",
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
color: "#F2F2F2",
|
||||||
|
width: "149px",
|
||||||
|
height: "44px",
|
||||||
|
padding: "12px 16px",
|
||||||
|
gap: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
value={selectedOption}
|
||||||
|
onChange={handleChange}
|
||||||
|
sx={{
|
||||||
|
color: "#D9D8D8",
|
||||||
|
".MuiSelect-icon": {
|
||||||
|
color: "#F2F2F2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
IconComponent={ExpandMoreIcon}
|
||||||
|
>
|
||||||
|
<MenuItem value="Monthly">Monthly</MenuItem>
|
||||||
|
<MenuItem value="Weekly">Weekly</MenuItem>
|
||||||
|
<MenuItem value="Daily">Daily</MenuItem>
|
||||||
|
<MenuItem value="Yearly">Yearly</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<BarChart
|
||||||
|
dataset={data}
|
||||||
|
series={[
|
||||||
|
{
|
||||||
|
dataKey: "v1",
|
||||||
|
label: "Value",
|
||||||
|
color: "skyblue",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
{...chartSetting}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,113 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import { useTheme } from "@mui/material/styles";
|
|
||||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from "recharts";
|
|
||||||
import { Card, CardContent, Typography, Box } from "@mui/material";
|
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
||||||
const data = [
|
|
||||||
{ name: "Jan", v1: 40 },
|
|
||||||
{ name: "Feb", v1: 50 },
|
|
||||||
{ name: "Mar", v1: 80 },
|
|
||||||
{ name: "Apr", v1: 20 },
|
|
||||||
{ name: "May", v1: 60 },
|
|
||||||
{ name: "Jun", v1: 30 },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function RoundedBarChart() {
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
|
||||||
width: "553px",
|
|
||||||
height: "444px",
|
|
||||||
borderRadius: "16px",
|
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
|
||||||
backgroundColor: "#202020",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
color: "#F2F2F2",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="h6"
|
|
||||||
align="left"
|
|
||||||
color="#F2F2F2"
|
|
||||||
sx={{
|
|
||||||
fontFamily: "Gilroy",
|
|
||||||
fontWeight: 500,
|
|
||||||
fontSize: "18px",
|
|
||||||
lineHeight: "24px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Charge Stats
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
mt: 2,
|
|
||||||
mb: 2,
|
|
||||||
backgroundColor: "#202020",
|
|
||||||
marginLeft: "auto",
|
|
||||||
marginRight: "16px",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
p: 1.5,
|
|
||||||
borderRadius: "8px",
|
|
||||||
border: "1px solid #454545",
|
|
||||||
|
|
||||||
// padding: "4px 8px",
|
|
||||||
color: "#F2F2F2",
|
|
||||||
width: "129px",
|
|
||||||
height: "44px",
|
|
||||||
padding: "12px 16px",
|
|
||||||
gap: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
width={"69px"}
|
|
||||||
height={"16px"}
|
|
||||||
sx={{
|
|
||||||
|
|
||||||
fontWeight: 500,
|
|
||||||
fontSize: "14px",
|
|
||||||
lineHeight: "24px",
|
|
||||||
color: "#D9D8D8",
|
|
||||||
|
|
||||||
textAlign: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Monthly
|
|
||||||
</Typography>
|
|
||||||
<ExpandMoreIcon
|
|
||||||
width="20px"
|
|
||||||
height="20px"
|
|
||||||
|
|
||||||
sx={{ color: "#F2F2F2" ,textAlign: "center", }}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</div>
|
|
||||||
<BarChart
|
|
||||||
width={600}
|
|
||||||
height={300}
|
|
||||||
data={data}
|
|
||||||
margin={{ top: 20, right: 30, left: 20, bottom: 5 }}
|
|
||||||
style={{ width: "100%", height: "auto" }}
|
|
||||||
>
|
|
||||||
<CartesianGrid vertical={false} />
|
|
||||||
<XAxis />
|
|
||||||
<YAxis tickFormatter={(value) => `${value}`} />
|
|
||||||
|
|
||||||
<Bar dataKey="v1" fill="skyblue" radius={[10, 10, 0, 0]} />
|
|
||||||
<Bar dataKey="v2" fill="skyblue" radius={[10, 10, 0, 0]} />
|
|
||||||
</BarChart>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
/* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
sans-serif;
|
sans-serif; */
|
||||||
|
font-family: "Gliroy";
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Box, Stack } from "@mui/material";
|
import { Box, Stack } from "@mui/material";
|
||||||
import { Outlet } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
import SideMenu from "../../components/SideMenu";
|
import SideMenu from "../../components/SideMenu/sideMenu";
|
||||||
import AppNavbar from "../../components/AppNavbar";
|
import AppNavbar from "../../components/AppNavbar";
|
||||||
import Header from "../../components/Header";
|
import Header from "../../components/Header";
|
||||||
import AppTheme from "../../shared-theme/AppTheme";
|
import AppTheme from "../../shared-theme/AppTheme";
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||||
import { createRole } from "../../redux/slices/roleSlice"; // Import the createRole action
|
import { createRole } from "../../redux/slices/roleSlice"; // Import the createRole action
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store"; // Assuming this is the path to your store file
|
import { AppDispatch, RootState } from "../../redux/store/store"; // Assuming this is the path to your store file
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { CustomTextField } from "../../components/AddEditUserModel/styled.css.tsx";
|
import { CustomTextField } from "../../components/AddUserModal/styled.css";
|
||||||
// Define the data structure for permission
|
// Define the data structure for permission
|
||||||
interface Permission {
|
interface Permission {
|
||||||
module: string;
|
module: string;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Box, Button, TextField, Typography } from "@mui/material";
|
import { Box, Button, TextField, Typography } from "@mui/material";
|
||||||
import AddEditCategoryModal from "../../components/AddEditCategoryModal";
|
import AddEditCategoryModal from "../../components/AddEditAdminModal/addEditAdminModal";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
adminList,
|
adminList,
|
||||||
|
@ -28,7 +28,8 @@ export default function AdminList() {
|
||||||
dispatch(adminList());
|
dispatch(adminList());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleClickOpen = () => {
|
const handleClickOpen = (row: any) => {
|
||||||
|
setRowData(row);
|
||||||
setRowData(null); // Reset row data when opening for new admin
|
setRowData(null); // Reset row data when opening for new admin
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
};
|
};
|
||||||
|
@ -96,7 +97,7 @@ export default function AdminList() {
|
||||||
email: string;
|
email: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
Admins: { registeredAddress: string }[];
|
Admins: { registeredAddress: string }[];
|
||||||
userType:string;
|
userType: string;
|
||||||
},
|
},
|
||||||
index: number
|
index: number
|
||||||
) => ({
|
) => ({
|
||||||
|
@ -106,11 +107,10 @@ export default function AdminList() {
|
||||||
email: admin?.email,
|
email: admin?.email,
|
||||||
phone: admin?.phone,
|
phone: admin?.phone,
|
||||||
registeredAddress: admin?.Admins?.[0]?.registeredAddress || "NA",
|
registeredAddress: admin?.Admins?.[0]?.registeredAddress || "NA",
|
||||||
userType:admin?.userType||"NA",
|
userType: admin?.userType || "NA",
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CustomTable
|
<CustomTable
|
||||||
|
@ -124,6 +124,7 @@ export default function AdminList() {
|
||||||
setModalOpen={setModalOpen}
|
setModalOpen={setModalOpen}
|
||||||
tableType="admin"
|
tableType="admin"
|
||||||
handleClickOpen={handleClickOpen}
|
handleClickOpen={handleClickOpen}
|
||||||
|
editRow={rowData}
|
||||||
/>
|
/>
|
||||||
<AddEditCategoryModal
|
<AddEditCategoryModal
|
||||||
open={modalOpen}
|
open={modalOpen}
|
||||||
|
|
|
@ -18,11 +18,10 @@ import { useDispatch } from "react-redux";
|
||||||
import { loginUser } from "../../../redux/slices/authSlice.ts";
|
import { loginUser } from "../../../redux/slices/authSlice.ts";
|
||||||
import AppTheme from "../../../shared-theme/AppTheme.tsx";
|
import AppTheme from "../../../shared-theme/AppTheme.tsx";
|
||||||
import ForgotPassword from "./ForgotPassword.tsx";
|
import ForgotPassword from "./ForgotPassword.tsx";
|
||||||
import { toast } from "sonner";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||||
import { Card, SignInContainer } from "./styled.css.tsx";
|
import { Card, SignInContainer } from "./styled.css.tsx";
|
||||||
import { CustomIconButton } from "../../../components/AddEditUserModel/styled.css.tsx";
|
import { CustomIconButton } from "../../../components/AddUserModal/styled.css.tsx";
|
||||||
import { AppDispatch } from "../../../redux/store/store.ts";
|
import { AppDispatch } from "../../../redux/store/store.ts";
|
||||||
interface ILoginForm {
|
interface ILoginForm {
|
||||||
email: string;
|
email: string;
|
||||||
|
@ -36,7 +35,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors, isValid },
|
formState: { errors, isValid },trigger
|
||||||
} = useForm<ILoginForm>({ mode: "onChange" });
|
} = useForm<ILoginForm>({ mode: "onChange" });
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const router = useNavigate();
|
const router = useNavigate();
|
||||||
|
@ -55,6 +54,10 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<ILoginForm> = async (data: ILoginForm) => {
|
const onSubmit: SubmitHandler<ILoginForm> = async (data: ILoginForm) => {
|
||||||
|
const isValid = await trigger(); // This triggers validation for all fields
|
||||||
|
if (!isValid) {
|
||||||
|
return; // Stop submission if there are errors
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const response = await dispatch(loginUser(data)).unwrap();
|
const response = await dispatch(loginUser(data)).unwrap();
|
||||||
if (response?.data?.token) {
|
if (response?.data?.token) {
|
||||||
|
@ -88,6 +91,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
item
|
item
|
||||||
xs={12}
|
xs={12}
|
||||||
md={5}
|
md={5}
|
||||||
|
width="408px"
|
||||||
|
height="498px"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "black",
|
backgroundColor: "black",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -101,21 +106,23 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: "1rem",
|
marginBottom: "1rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/evLogo.png"
|
src="/evLogo.png"
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
style={{
|
style={{
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
width: "180px",
|
width: "180px",
|
||||||
height: "auto",
|
height: "auto",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h3"
|
variant="h3"
|
||||||
|
width={"408px"}
|
||||||
|
height={"46px"}
|
||||||
sx={{
|
sx={{
|
||||||
color: "white",
|
color: "white",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
|
@ -133,10 +140,13 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
width: { xs: "100%", sm: "300px", lg: "408px" },
|
width: { xs: "100%", sm: "300px", lg: "408px" },
|
||||||
|
height:{lg:"428px"},
|
||||||
padding: "24px",
|
padding: "24px",
|
||||||
borderRadius: "12px",
|
borderRadius: "9px",
|
||||||
backgroundColor: "#1E1E1E",
|
border: "1px solidrgb(45, 48, 49)",
|
||||||
border: "1px solid #4B5255",
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
|
backgroundColor: "#1E1E1E",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
|
@ -252,6 +262,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
"#4b5255",
|
"#4b5255",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"& input": {
|
"& input": {
|
||||||
color: "white",
|
color: "white",
|
||||||
fontSize: {
|
fontSize: {
|
||||||
|
@ -330,7 +341,6 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
? "error"
|
? "error"
|
||||||
: "primary"
|
: "primary"
|
||||||
}
|
}
|
||||||
|
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
|
@ -443,7 +453,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
fontFamily: "Gilroy, sans-serif",
|
fontFamily: "Gilroy, sans-serif",
|
||||||
color: "#01579b",
|
color: "#01579b",
|
||||||
textDecoration: "none", // ✅ Removes underline
|
textDecoration: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Box, Button, TextField, Typography } from "@mui/material";
|
import { Box, Button, TextField, Typography } from "@mui/material";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/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 { addBooking, bookingList } from "../../redux/slices/bookSlice";
|
import { addBooking, bookingList } from "../../redux/slices/bookSlice";
|
||||||
import AddBookingModal from "../../components/AddBookingModal";
|
import AddBookingModal from "../../components/AddBookingModal/addBookingModal";
|
||||||
|
|
||||||
export default function BookingList() {
|
export default function BookingList() {
|
||||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
treeViewCustomizations,
|
treeViewCustomizations,
|
||||||
} from "./theme/customizations";
|
} from "./theme/customizations";
|
||||||
import AppTheme from "../../shared-theme/AppTheme";
|
import AppTheme from "../../shared-theme/AppTheme";
|
||||||
import MainGrid from "../../components/MainGrid";
|
import MainGrid from "../../components/MainGrid/mainGrid";
|
||||||
|
|
||||||
|
|
||||||
const xThemeComponents = {
|
const xThemeComponents = {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
IconButton,
|
IconButton,
|
||||||
Button,
|
Button,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { CustomTextField } from "../../components/AddEditUserModel/styled.css.tsx";
|
import { CustomTextField } from "../../components/AddUserModal/styled.css.tsx";
|
||||||
import AddCircleIcon from "@mui/icons-material/AddCircle";
|
import AddCircleIcon from "@mui/icons-material/AddCircle";
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import CalendarTodayRoundedIcon from "@mui/icons-material/CalendarTodayRounded";
|
import CalendarTodayRoundedIcon from "@mui/icons-material/CalendarTodayRounded";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/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";
|
||||||
|
@ -8,9 +8,9 @@ import {
|
||||||
fetchAvailableSlots,
|
fetchAvailableSlots,
|
||||||
updateSlot,
|
updateSlot,
|
||||||
} from "../../redux/slices/slotSlice";
|
} from "../../redux/slices/slotSlice";
|
||||||
import AddSlotModal from "../../components/AddSlotModal";
|
import AddSlotModal from "../../components/AddSlotModal/addSlotModal";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import EditSlotModal from "../../components/EditSlotModal";
|
import EditSlotModal from "../../components/EditSlotModal/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);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Box, Button, TextField, Typography } from "@mui/material";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import AddManagerModal from "../../components/AddManagerModal/addManagerModal";
|
||||||
import AddManagerModal from "../../components/AddManagerModal";
|
import EditManagerModal from "../../components/EditManagerModal/editManagerModal";
|
||||||
import EditManagerModal from "../../components/EditManagerModal";
|
|
||||||
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 {
|
import {
|
||||||
|
@ -15,13 +14,11 @@ import { useForm } from "react-hook-form";
|
||||||
export default function ManagerList() {
|
export default function ManagerList() {
|
||||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
||||||
const [editRow, setEditRow] = useState<any>(null);
|
|
||||||
const { reset } = useForm();
|
const { reset } = useForm();
|
||||||
|
|
||||||
const [deleteModal, setDeleteModal] = useState<boolean>(false);
|
const [deleteModal, setDeleteModal] = useState<boolean>(false);
|
||||||
const [viewModal, setViewModal] = useState<boolean>(false);
|
const [viewModal, setViewModal] = useState<boolean>(false);
|
||||||
const [rowData, setRowData] = useState<any | null>(null);
|
const [rowData, setRowData] = useState<any | null>(null);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const managers = useSelector(
|
const managers = useSelector(
|
||||||
(state: RootState) => state.managerReducer.managers
|
(state: RootState) => state.managerReducer.managers
|
||||||
|
@ -65,7 +62,7 @@ export default function ManagerList() {
|
||||||
|
|
||||||
// Handle updating an existing manager
|
// Handle updating an existing manager
|
||||||
const handleUpdate = async (
|
const handleUpdate = async (
|
||||||
id: string,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
email: string,
|
email: string,
|
||||||
phone: string,
|
phone: string,
|
||||||
|
@ -100,14 +97,6 @@ export default function ManagerList() {
|
||||||
{ id: "action", label: "Action", align: "center" },
|
{ id: "action", label: "Action", align: "center" },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Filter managers based on search term
|
|
||||||
// const filteredManagers = managers?.filter(
|
|
||||||
// (manager) =>
|
|
||||||
// manager.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
// manager.email?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
// manager.phone?.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
// );
|
|
||||||
|
|
||||||
const categoryRows = managers?.length
|
const categoryRows = managers?.length
|
||||||
? managers.map((manager, index) => {
|
? managers.map((manager, index) => {
|
||||||
const station = manager?.chargingStation; // Correct access to the ChargingStation data
|
const station = manager?.chargingStation; // Correct access to the ChargingStation data
|
||||||
|
|
|
@ -1,9 +1,115 @@
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
|
import { Box, Typography, Button, Card, Grid } from "@mui/material";
|
||||||
|
import ElectricCarIcon from "@mui/icons-material/ElectricCar";
|
||||||
|
import { keyframes } from "@emotion/react";
|
||||||
|
|
||||||
function NotFoundPage() {
|
// Animation for the car icon
|
||||||
return (
|
const pulse = keyframes`
|
||||||
<div>NotFoundPage</div>
|
0% {
|
||||||
)
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export default NotFoundPage;
|
const NotFoundPage = () => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
height: "100vh",
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg,rgb(12, 14, 15),rgb(10, 10, 10))",
|
||||||
|
padding: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#272727",
|
||||||
|
padding: "40px",
|
||||||
|
borderRadius: "20px",
|
||||||
|
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.7)",
|
||||||
|
textAlign: "center",
|
||||||
|
maxWidth: "500px",
|
||||||
|
width: "100%",
|
||||||
|
color: "#E0E0E0",
|
||||||
|
animation: `${pulse} 1.5s infinite`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ElectricCarIcon
|
||||||
|
sx={{
|
||||||
|
fontSize: 100,
|
||||||
|
color: "#52ACDF",
|
||||||
|
marginBottom: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h3"
|
||||||
|
sx={{ fontWeight: 700, color: "#FFFFFF", marginBottom: 1 }}
|
||||||
|
>
|
||||||
|
404
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="h5"
|
||||||
|
sx={{ fontWeight: 500, color: "#FFFFFF", marginBottom: 3 }}
|
||||||
|
>
|
||||||
|
Oops! Page Not Found
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{ color: "#B0B0B0", marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
The path you’re looking for seems to be off the grid. Maybe
|
||||||
|
the charging station is offline? ⚡
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={2} justifyContent="center">
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "#FFFFFF",
|
||||||
|
padding: "12px 32px",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
opacity: 0.9,
|
||||||
|
},
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
onClick={() => (window.location.href = "/")}
|
||||||
|
>
|
||||||
|
Back to Login
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
borderColor: "#52ACDF",
|
||||||
|
color: "#52ACDF",
|
||||||
|
padding: "12px 32px",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "#FFFFFF",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onClick={() => window.history.back()}
|
||||||
|
>
|
||||||
|
Go Back
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NotFoundPage;
|
||||||
|
|
|
@ -120,13 +120,13 @@ const ProfilePage = () => {
|
||||||
>
|
>
|
||||||
Personal Information
|
Personal Information
|
||||||
</Typography>
|
</Typography>
|
||||||
<Link
|
{/* <Link
|
||||||
variant="body1"
|
variant="body1"
|
||||||
href="/edit-profile"
|
href="/edit-profile"
|
||||||
color="#52ACDF"
|
color="#52ACDF"
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</Link>
|
</Link> */}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Box, Button, Typography, TextField, Chip } from "@mui/material";
|
||||||
import AddEditRoleModal from "../../components/AddEditRoleModal";
|
import AddEditRoleModal from "../../components/AddEditRoleModal";
|
||||||
import PermissionsTable from "../../pages/PermissionTable";
|
import PermissionsTable from "../../pages/PermissionTable";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
createRole,
|
createRole,
|
||||||
|
@ -13,10 +13,9 @@ import {
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import AddEditRolePage from "../AddEditRolePage";
|
import AddEditRolePage from "../AddEditRolePage";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
|
||||||
|
|
||||||
export default function RoleList() {
|
export default function RoleList() {
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
|
||||||
const { reset } = useForm();
|
const { reset } = useForm();
|
||||||
|
|
||||||
const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
|
const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
|
||||||
|
@ -100,7 +99,6 @@ export default function RoleList() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
{showPermissions ? (
|
{showPermissions ? (
|
||||||
<AddEditRolePage />
|
<AddEditRolePage />
|
||||||
) : (
|
) : (
|
||||||
|
@ -121,3 +119,4 @@ export default function RoleList() {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Chip } from "@mui/material";
|
|
||||||
import AddStationModal from "../../components/AddStationModal";
|
import AddStationModal from "../../components/AddStationModal/addStationModal";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import EditStationModal from "../../components/EditStationModal";
|
import EditStationModal from "../../components/EditStationModal/editSationModal";
|
||||||
import {
|
import {
|
||||||
createStation,
|
createStation,
|
||||||
stationList,
|
stationList,
|
||||||
|
@ -17,13 +17,11 @@ import { useForm } from "react-hook-form";
|
||||||
export default function StationList() {
|
export default function StationList() {
|
||||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
||||||
const [editRow, setEditRow] = useState<any>(null);
|
|
||||||
const { reset } = useForm();
|
const { reset } = useForm();
|
||||||
|
|
||||||
const [deleteModal, setDeleteModal] = useState<boolean>(false);
|
const [deleteModal, setDeleteModal] = useState<boolean>(false);
|
||||||
const [viewModal, setViewModal] = useState<boolean>(false);
|
const [viewModal, setViewModal] = useState<boolean>(false);
|
||||||
const [rowData, setRowData] = useState<any | null>(null);
|
const [rowData, setRowData] = useState<any | null>(null);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
const vehicles = useSelector(
|
const vehicles = useSelector(
|
||||||
|
@ -64,7 +62,7 @@ export default function StationList() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdate = async (
|
const handleUpdate = async (
|
||||||
id: string,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
registeredAddress: string,
|
registeredAddress: string,
|
||||||
totalSlots: number,
|
totalSlots: number,
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Box, Button, Typography } from "@mui/material";
|
import { Box, Button, Typography } from "@mui/material";
|
||||||
import AddEditCategoryModal from "../../components/AddEditCategoryModal";
|
import AddEditCategoryModal from "../../components/AddEditCategoryModal/addEdit";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { createUser, updateUser, userList } from "../../redux/slices/userSlice";
|
import { createUser, updateUser, userList } from "../../redux/slices/userSlice";
|
||||||
import { AppDispatch, RootState } from "../../redux/store/store";
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
import { string } from "prop-types";
|
import AddUserModal from "../../components/AddUserModal/addUserModal";
|
||||||
import { adminList, updateAdmin } from "../../redux/slices/adminSlice";
|
import EditUserModal from "../../components/EditUserModal/editUserModal";
|
||||||
import AddUserModal from "../../components/AddEditUserModel";
|
|
||||||
|
|
||||||
export default function UserList() {
|
export default function UserList() {
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
|
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
||||||
|
const [rowData, setRowData] = useState<any | null>(null);
|
||||||
|
const [deleteModal, setDeleteModal] = useState<boolean>(false);
|
||||||
|
const [viewModal, setViewModal] = useState<boolean>(false);
|
||||||
const { reset } = useForm();
|
const { reset } = useForm();
|
||||||
|
|
||||||
const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
|
|
||||||
const [viewModal, setViewModal] = React.useState<boolean>(false);
|
|
||||||
const [rowData, setRowData] = React.useState<any | null>(null);
|
|
||||||
|
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
|
@ -28,11 +28,12 @@ export default function UserList() {
|
||||||
|
|
||||||
const handleClickOpen = () => {
|
const handleClickOpen = () => {
|
||||||
setRowData(null); // Reset row data when opening for new admin
|
setRowData(null); // Reset row data when opening for new admin
|
||||||
setModalOpen(true);
|
setAddModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
setModalOpen(false);
|
setAddModalOpen(false);
|
||||||
|
setEditModalOpen(false);
|
||||||
setRowData(null);
|
setRowData(null);
|
||||||
reset();
|
reset();
|
||||||
};
|
};
|
||||||
|
@ -41,7 +42,6 @@ export default function UserList() {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
|
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
await dispatch(createUser(data));
|
await dispatch(createUser(data));
|
||||||
|
@ -53,7 +53,7 @@ export default function UserList() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdate = async (
|
const handleUpdate = async (
|
||||||
id: string,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
email: string,
|
email: string,
|
||||||
phone: string
|
phone: string
|
||||||
|
@ -79,39 +79,21 @@ export default function UserList() {
|
||||||
{ id: "name", label: "Name" },
|
{ id: "name", label: "Name" },
|
||||||
{ id: "email", label: "Email" },
|
{ id: "email", label: "Email" },
|
||||||
{ id: "phone", label: "Phone" },
|
{ id: "phone", label: "Phone" },
|
||||||
// { id: "location", label: "Location" },
|
|
||||||
// { id: "managerAssigned", label: "ManagerAssigned" },
|
|
||||||
// { id: "vehicle", label: "Vehicle" },
|
|
||||||
|
|
||||||
{ id: "action", label: "Action", align: "center" },
|
{ id: "action", label: "Action", align: "center" },
|
||||||
];
|
];
|
||||||
|
const categoryRows = users?.length
|
||||||
|
? users.map((user, index) => ({
|
||||||
|
id: user.id,
|
||||||
|
srno: index + 1,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
phone: user.phone || "NA", // Ensures it's a string
|
||||||
|
}))
|
||||||
|
: [];
|
||||||
|
|
||||||
const categoryRows = users?.length
|
|
||||||
? users?.map(function (
|
|
||||||
user: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
phone: string;
|
|
||||||
// location?: string;
|
|
||||||
// managerAssigned?: string;
|
|
||||||
// vehicle?: string;
|
|
||||||
},
|
|
||||||
index: number
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
id: user?.id,
|
|
||||||
srno: index + 1,
|
|
||||||
name: user?.name,
|
|
||||||
email: user?.email,
|
|
||||||
phone: user?.phone,
|
|
||||||
// location: user?.location,
|
|
||||||
// managerAssigned: user?.managerAssigned,
|
|
||||||
// vehicle: user?.vehicle,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
: [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -123,14 +105,19 @@ export default function UserList() {
|
||||||
setViewModal={setViewModal}
|
setViewModal={setViewModal}
|
||||||
viewModal={viewModal}
|
viewModal={viewModal}
|
||||||
setRowData={setRowData}
|
setRowData={setRowData}
|
||||||
setModalOpen={setModalOpen}
|
|
||||||
tableType="user"
|
tableType="user"
|
||||||
handleClickOpen={handleClickOpen}
|
handleClickOpen={handleClickOpen}
|
||||||
|
setModalOpen={() => setEditModalOpen(true)}
|
||||||
/>
|
/>
|
||||||
<AddUserModal
|
<AddUserModal
|
||||||
open={modalOpen}
|
open={addModalOpen}
|
||||||
handleClose={handleCloseModal}
|
handleClose={handleCloseModal}
|
||||||
handleCreate={handleCreate}
|
handleCreate={handleCreate}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EditUserModal
|
||||||
|
open={editModalOpen}
|
||||||
|
handleClose={handleCloseModal}
|
||||||
handleUpdate={handleUpdate}
|
handleUpdate={handleUpdate}
|
||||||
editRow={rowData}
|
editRow={rowData}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import CustomTable, { Column } from "../../components/CustomTable";
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
import { RootState } from "../../redux/reducers";
|
import { RootState } from "../../redux/reducers";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { AppDispatch } from "../../redux/store/store";
|
import { AppDispatch } from "../../redux/store/store";
|
||||||
|
@ -9,8 +9,8 @@ import {
|
||||||
updateVehicle,
|
updateVehicle,
|
||||||
vehicleList,
|
vehicleList,
|
||||||
} from "../../redux/slices/VehicleSlice";
|
} from "../../redux/slices/VehicleSlice";
|
||||||
import AddVehicleModal from "../../components/AddVehicleModal";
|
import AddVehicleModal from "../../components/AddVehicleModal/addVehicleModal";
|
||||||
import EditVehicleModal from "../../components/EditVehicleModal";
|
import EditVehicleModal from "../../components/EditVehicleModal/editVehicleModal";
|
||||||
|
|
||||||
export default function VehicleList() {
|
export default function VehicleList() {
|
||||||
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
|
||||||
|
@ -58,7 +58,7 @@ export default function VehicleList() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdate = async (
|
const handleUpdate = async (
|
||||||
id: string,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
company: string,
|
company: string,
|
||||||
modelName: string,
|
modelName: string,
|
||||||
|
@ -93,24 +93,13 @@ export default function VehicleList() {
|
||||||
{ id: "action", label: "Action", align: "center" },
|
{ id: "action", label: "Action", align: "center" },
|
||||||
];
|
];
|
||||||
|
|
||||||
// const filteredVehicles = vehicles?.filter(
|
|
||||||
// (vehicle) =>
|
|
||||||
// vehicle.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
// vehicle.company?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
// vehicle.modelName
|
|
||||||
// ?.toLowerCase()
|
|
||||||
// .includes(searchTerm.toLowerCase()) ||
|
|
||||||
// vehicle.chargeType
|
|
||||||
// ?.toLowerCase()
|
|
||||||
// .includes(searchTerm.toLowerCase()) ||
|
|
||||||
// vehicle.imageUrl?.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
// );
|
|
||||||
|
|
||||||
const categoryRows = vehicles?.length
|
const categoryRows = vehicles?.length
|
||||||
? vehicles?.map(
|
? vehicles?.map(
|
||||||
(
|
(
|
||||||
vehicle: {
|
vehicle: {
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
company: string;
|
company: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
|
|
@ -9,7 +9,7 @@ interface VehicleBrand {
|
||||||
|
|
||||||
interface Vehicle {
|
interface Vehicle {
|
||||||
brandId?: string;
|
brandId?: string;
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
company: string;
|
company: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
|
|
|
@ -5,8 +5,7 @@ import { toast } from "sonner";
|
||||||
// Define the Manager interface based on the payload
|
// Define the Manager interface based on the payload
|
||||||
|
|
||||||
interface Manager {
|
interface Manager {
|
||||||
Manager: any;
|
id: number;
|
||||||
id: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
|
@ -74,7 +73,7 @@ export const addManager = createAsyncThunk<
|
||||||
// Update Manager (Async Thunk)
|
// Update Manager (Async Thunk)
|
||||||
export const updateManager = createAsyncThunk<
|
export const updateManager = createAsyncThunk<
|
||||||
Manager,
|
Manager,
|
||||||
{ id: string; managerData: Manager },
|
{ id: number; managerData: Manager },
|
||||||
{ rejectValue: string }
|
{ rejectValue: string }
|
||||||
>("updateManager", async ({ id, managerData }, { rejectWithValue }) => {
|
>("updateManager", async ({ id, managerData }, { rejectWithValue }) => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { toast } from "sonner";
|
||||||
|
|
||||||
// Define TypeScript types
|
// Define TypeScript types
|
||||||
interface Station {
|
interface Station {
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
registeredAddress: string;
|
registeredAddress: string;
|
||||||
totalSlots: number;
|
totalSlots: number;
|
||||||
|
|
|
@ -5,14 +5,12 @@ import { toast } from "sonner";
|
||||||
|
|
||||||
// Define TypeScript types
|
// Define TypeScript types
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
// location?: string;
|
|
||||||
// managerAssigned?: string;
|
|
||||||
// vehicle?: string;
|
|
||||||
password: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserState {
|
interface UserState {
|
||||||
|
|
|
@ -108,6 +108,7 @@ export default function AppRouter() {
|
||||||
path="slot-list"
|
path="slot-list"
|
||||||
element={<ProtectedRoute component={<EvSlotList />} />}
|
element={<ProtectedRoute component={<EvSlotList />} />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* Catch-all Route */}
|
{/* Catch-all Route */}
|
||||||
|
|
Loading…
Reference in a new issue