bulk-email/src/components/AddManagerModal/addManagerModal.tsx

418 lines
11 KiB
TypeScript

import { Controller, useForm } from "react-hook-form";
import {
Box,
Button,
Typography,
Modal,
IconButton,
InputAdornment,
Select,
MenuItem,
FormControl,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { Visibility, VisibilityOff } from "@mui/icons-material";
import { useDispatch, useSelector } from "react-redux";
import { addManager, managerList } from "../../redux/slices/managerSlice.ts";
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
import React, { useEffect, useState } from "react";
import { RootState } from "../../redux/reducers.ts";
import { stationList } from "../../redux/slices/stationSlice.ts";
import { autofillFix } from "../../shared-theme/customizations/autoFill.tsx";
export default function AddManagerModal({ open, handleClose }) {
const dispatch = useDispatch();
const {
control,
register,
handleSubmit,
formState: { errors },
reset,
clearErrors,
} = useForm({
mode: "onChange", // Trigger validation on change for real-time feedback
});
const [showPassword, setShowPassword] = useState(false);
const stations = useSelector(
(state: RootState) => state?.stationReducer.stations
);
useEffect(() => {
dispatch(stationList());
}, [dispatch]);
// Handle form submission
const onSubmit = async (data: any) => {
const selectedStation = stations.find(
(station) => station.name === data.stationName
);
const managerData = {
name: data.name,
email: data.email,
phone: data.phone,
password: data.password,
stationId: selectedStation?.id,
};
try {
await dispatch(addManager(managerData));
dispatch(managerList());
clearErrors(); // Clear errors on successful submission
reset(); // Reset form fields on successful submission
handleClose(); // Close modal
} catch (error) {
console.error("Error adding manager:", error);
}
};
// Handle modal close, clearing errors and resetting form
const handleModalClose = () => {
clearErrors(); // Clear errors when closing via close icon
reset(); // Reset form fields when closing via close icon
handleClose(); // Close modal
};
const togglePasswordVisibility = (e: React.MouseEvent) => {
e.preventDefault();
setShowPassword((prev) => !prev);
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return; // Prevent closing on backdrop click
}
handleModalClose();
}}
aria-labelledby="add-manager-modal"
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Add Manager
</Typography>
<CustomIconButton onClick={handleModalClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Form */}
<form onSubmit={handleSubmit(onSubmit)}>
{/* Manager Name */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Manager Name
</Typography>
<CustomTextField
fullWidth
placeholder="Enter Manager Name"
size="small"
sx={{ marginTop: 1 }}
error={!!errors.name}
helperText={
errors.name ? errors.name.message : ""
}
{...register("name", {
required: "Manager 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]+$/,
message:
"Manager Name must only contain letters and spaces",
},
})}
/>
</Box>
</Box>
{/* Station Dropdown */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1 }}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Select Station
</Typography>
<FormControl
fullWidth
size="small"
error={!!errors.stationName}
>
<Controller
name="stationName"
control={control}
rules={{
required: "Station Name is required",
}}
render={({ field }) => (
<Select
{...field}
onChange={(e) =>
field.onChange(e.target.value)
} // Update form state
value={field.value || ""} // Ensure controlled value
sx={{ marginTop: 1 }}
displayEmpty
renderValue={(selected) => {
if (!selected) {
return (
<Typography color="text.secondary">
Choose Station
</Typography>
);
}
return selected;
}}
MenuProps={{
PaperProps: {
style: {
maxHeight: 224,
},
},
}}
>
{Array.isArray(stations) &&
stations.length > 0 ? (
stations.map((station) => (
<MenuItem
key={station.id}
value={station.name}
>
{station.name}
</MenuItem>
))
) : (
<MenuItem disabled>
No stations available
</MenuItem>
)}
</Select>
)}
/>
{errors.stationName && (
<Typography
color="error"
variant="body2"
sx={{ mt: 0.5 }}
>
{errors.stationName.message}
</Typography>
)}
</FormControl>
</Box>
</Box>
{/* Email and Password */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
{/* Email */}
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Email
</Typography>
<CustomTextField
fullWidth
placeholder="Enter Manager Email"
size="small"
sx={{ marginTop: 1 }}
autoComplete="new-email"
error={!!errors.email}
helperText={
errors.email ? errors.email.message : ""
}
{...register("email", {
required: "Email is required",
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message:
"Please enter a valid email address (e.g., example@domain.com).",
},
})}
/>
</Box>
{/* Password */}
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
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
sx={{ marginTop: 1 }}
autoComplete="new-password"
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>
{/* Phone Number */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Phone Number
</Typography>
<CustomTextField
fullWidth
placeholder="Enter Phone Number"
size="small"
sx={{ marginTop: 1 }}
error={!!errors.phone}
helperText={
errors.phone ? errors.phone.message : ""
}
{...register("phone", {
required: "Phone Number is required",
validate: (value) => {
if (!/^[0-9]*$/.test(value)) {
return "Only numbers are allowed";
}
if (value.length < 6) {
return "Phone number must be at least 6 digits";
}
if (value.length > 14) {
return "Phone number must be at most 14 digits";
}
return true;
},
})}
/>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
mt: 3,
}}
>
<Button
type="submit"
sx={{
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
fontSize: "16px",
width: "125px",
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Add Manager
</Button>
</Box>
</form>
</Box>
</Modal>
);
}