425 lines
22 KiB
JavaScript
425 lines
22 KiB
JavaScript
import LtrTextField from "@/core/components/LtrTextField";
|
|
import StyledForm from "@/core/components/StyledForm";
|
|
import validateNationalCode from "@/core/utils/nationalCodeValidation";
|
|
import useProvinces from "@/lib/hooks/useProvince";
|
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
import {
|
|
Button,
|
|
Chip,
|
|
DialogActions,
|
|
DialogContent,
|
|
Divider,
|
|
FormControl,
|
|
FormHelperText,
|
|
Grid,
|
|
IconButton,
|
|
InputAdornment,
|
|
InputLabel,
|
|
MenuItem,
|
|
OutlinedInput,
|
|
Select,
|
|
Stack,
|
|
TextField,
|
|
} from "@mui/material";
|
|
import { Controller, useForm } from "react-hook-form";
|
|
import { object, string } from "yup";
|
|
import { useMemo, useState } from "react";
|
|
import useRoles from "@/lib/hooks/useRoles";
|
|
import useRequest from "@/lib/hooks/useRequest";
|
|
import { CREATE_USER } from "@/core/utils/routes";
|
|
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
|
|
|
const defaultValues = {
|
|
full_name: "",
|
|
username: "",
|
|
position: "",
|
|
gender: "male",
|
|
national_id: "",
|
|
phone_number: "",
|
|
province_id: "",
|
|
password: "",
|
|
role_id: "",
|
|
telephone_id: "",
|
|
};
|
|
|
|
const validationSchema = object().shape({
|
|
full_name: string().required("نام و نام خانوادگی را وارد کنید"),
|
|
username: string().required("نام کاربری را وارد کنید"),
|
|
phone_number: string()
|
|
.matches(/^09\d{9}$/, "شماره همراه باید با 09 شروع شود و 11 رقم باشد.")
|
|
.required("شماره همراه را وارد کنید"),
|
|
gender: string().required("جنسیت را وارد کنید"),
|
|
national_id: string()
|
|
.test("max", "کد ملی باید شامل 10 رقم باشد", (value) => value.toString().length === 10)
|
|
.test("validation", "کد ملی صحیح نمی باشد", (value) => validateNationalCode(value))
|
|
.required("کد ملی را وارد کنید"),
|
|
password: string()
|
|
.required("رمز عبور را وارد کنید")
|
|
.matches(/^(?=.*[a-zA-Z])(?=.*\d).{8,}$/, "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد"),
|
|
position: string().required("سمت را وارد کنید"),
|
|
province_id: string().required("استان را وارد کنید"),
|
|
role_id: string().required("نقش را وارد کنید"),
|
|
telephone_id: string().required("شماره تماس داخلی را وارد کنید"),
|
|
});
|
|
|
|
const CreateUserForm = ({ setOpen, mutate }) => {
|
|
const requestServer = useRequest({ notificationSuccess: true });
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
|
|
const { roles, errorRoles, loadingRoles } = useRoles();
|
|
|
|
const handleClickShowPassword = () => setShowPassword((show) => !show);
|
|
|
|
const provinceSelectOptions = useMemo(() => {
|
|
if (loadingProvinces) {
|
|
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
|
}
|
|
if (errorProvinces) {
|
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
|
}
|
|
return [
|
|
{ value: "", label: "انتخاب استان" },
|
|
...provinces.map((province) => ({
|
|
value: province.id,
|
|
label: province.name,
|
|
})),
|
|
];
|
|
}, [provinces, errorProvinces, loadingProvinces]);
|
|
|
|
const roleSelectOptions = useMemo(() => {
|
|
if (loadingRoles) {
|
|
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
|
}
|
|
if (errorRoles) {
|
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
|
}
|
|
return [
|
|
{ value: "", label: "انتخاب نقش" },
|
|
...roles.map((role) => ({
|
|
value: role.id,
|
|
label: role.name_fa,
|
|
})),
|
|
];
|
|
}, [roles, errorRoles, loadingRoles]);
|
|
|
|
const {
|
|
control,
|
|
handleSubmit,
|
|
formState: { isSubmitting, errors },
|
|
} = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
|
|
|
|
const onSubmit = async (data) => {
|
|
const formData = new FormData();
|
|
Object.keys(data).forEach((key) => {
|
|
formData.append(key, data[key]);
|
|
});
|
|
try {
|
|
await requestServer(CREATE_USER, "post", {
|
|
data: formData,
|
|
});
|
|
setOpen(false);
|
|
mutate();
|
|
} catch (error) {}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<DialogContent dividers>
|
|
<Divider sx={{ mb: 3 }}>
|
|
<Chip color="primary" variant="outlined" label="کاربر جدید" />
|
|
</Divider>
|
|
<StyledForm
|
|
id="createUserForm"
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
style={{ width: "100%", height: "100%" }}
|
|
>
|
|
<Stack spacing={2}>
|
|
<Grid container spacing={2}>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<LtrTextField
|
|
{...field}
|
|
label="نام کاربری"
|
|
variant="outlined"
|
|
fullWidth
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"username"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<LtrTextField
|
|
{...field}
|
|
label="رمز عبور"
|
|
variant="outlined"
|
|
type={showPassword ? "text" : "password"}
|
|
slotProps={{
|
|
input: {
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<IconButton onClick={handleClickShowPassword}>
|
|
{showPassword ? <VisibilityOff /> : <Visibility />}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
fullWidth
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"password"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<TextField
|
|
{...field}
|
|
label="نام و نام خانوادگی"
|
|
variant="outlined"
|
|
fullWidth
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"full_name"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<TextField
|
|
{...field}
|
|
label="سمت"
|
|
variant="outlined"
|
|
fullWidth
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"position"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<LtrTextField
|
|
{...field}
|
|
label="شماره همراه"
|
|
variant="outlined"
|
|
fullWidth
|
|
type="tel"
|
|
onChange={(e) => {
|
|
const inputValue = event.target.value;
|
|
if (isNaN(Number(inputValue))) {
|
|
return;
|
|
}
|
|
if (inputValue.length > 11) {
|
|
return;
|
|
}
|
|
field.onChange(inputValue);
|
|
}}
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"phone_number"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<FormControl fullWidth error={!!error}>
|
|
<InputLabel id={`label-gender`} shrink>
|
|
جنسیت
|
|
</InputLabel>
|
|
<Select
|
|
labelId={`label-gender`}
|
|
id={"gender"}
|
|
name={`gender`}
|
|
value={field.value}
|
|
input={<OutlinedInput label={"جنسیت"} />}
|
|
onChange={(e) => field.onChange(e.target.value)}
|
|
displayEmpty
|
|
>
|
|
<MenuItem value={"male"}>مرد</MenuItem>
|
|
<MenuItem value={"female"}>زن</MenuItem>
|
|
</Select>
|
|
<FormHelperText error={!!error} sx={{ mt: 1 }}>
|
|
{!!error && error.message}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
);
|
|
}}
|
|
name={"gender"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<LtrTextField
|
|
{...field}
|
|
label="شماره ملی"
|
|
variant="outlined"
|
|
fullWidth
|
|
type="tel"
|
|
onChange={(e) => {
|
|
const inputValue = event.target.value;
|
|
if (isNaN(Number(inputValue))) {
|
|
return;
|
|
}
|
|
if (inputValue.length > 10) {
|
|
return;
|
|
}
|
|
field.onChange(inputValue);
|
|
}}
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"national_id"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<FormControl fullWidth error={!!error}>
|
|
<InputLabel id={`label-province`} shrink>
|
|
استان
|
|
</InputLabel>
|
|
<Select
|
|
labelId={`label-province`}
|
|
id={"province"}
|
|
name={`province_id`}
|
|
value={field.value}
|
|
input={<OutlinedInput label={"استان"} />}
|
|
onChange={(e) => field.onChange(e.target.value)}
|
|
displayEmpty
|
|
>
|
|
{provinceSelectOptions.map((option) => (
|
|
<MenuItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
<FormHelperText error={!!error} sx={{ mt: 1 }}>
|
|
{!!error && error.message}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
);
|
|
}}
|
|
name={"province_id"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<FormControl fullWidth error={!!error}>
|
|
<InputLabel id={`label-role`} shrink>
|
|
نقش
|
|
</InputLabel>
|
|
<Select
|
|
labelId={`label-role`}
|
|
id={"role"}
|
|
name={`role_id`}
|
|
value={field.value}
|
|
input={<OutlinedInput label={"نقش"} />}
|
|
onChange={(e) => field.onChange(e.target.value)}
|
|
displayEmpty
|
|
>
|
|
{roleSelectOptions.map((option) => (
|
|
<MenuItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
<FormHelperText error={!!error} sx={{ mt: 1 }}>
|
|
{!!error && error.message}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
);
|
|
}}
|
|
name={"role_id"}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Controller
|
|
control={control}
|
|
render={({ field, fieldState: { error } }) => {
|
|
return (
|
|
<LtrTextField
|
|
{...field}
|
|
label="شماره تماس داخلی"
|
|
variant="outlined"
|
|
fullWidth
|
|
type="tel"
|
|
error={!!error}
|
|
helperText={!!error && error.message}
|
|
/>
|
|
);
|
|
}}
|
|
name={"telephone_id"}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</Stack>
|
|
</StyledForm>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button
|
|
disabled={isSubmitting}
|
|
variant="outlined"
|
|
color="secondary"
|
|
size="large"
|
|
onClick={() => setOpen(false)}
|
|
>
|
|
بستن
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
disabled={isSubmitting}
|
|
form="createUserForm"
|
|
size="large"
|
|
autoFocus
|
|
variant="contained"
|
|
>
|
|
{isSubmitting ? "در حال ثبت کاربر جدید..." : "ثبت کاربر جدید"}
|
|
</Button>
|
|
</DialogActions>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default CreateUserForm;
|