UserForm.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { connect } from "react-redux";
  2. import { useState, useEffect, useContext } from "react";
  3. import { actionUserUpdate } from "../../../actions/actionUserUpdate";
  4. import { UIContext } from "../../UIContext";
  5. import Select from "react-select";
  6. import { Box, Button, Grid, IconButton, InputLabel, Stack, TextField } from "@mui/material";
  7. import { useFormik } from "formik";
  8. import * as Yup from "yup";
  9. import { useNavigate } from "react-router-dom";
  10. import { MdVisibility, MdVisibilityOff } from "react-icons/md";
  11. import { aclList } from "../../../helpers";
  12. import { actionUploadFile } from "../../../actions/actionUploadFile";
  13. import { ProfileImageEditor } from "../../common/ProfileImageEditor";
  14. import { actionPromisesClear } from "../../../actions/actionPromisesClear";
  15. const CProfileImageEditor = connect(null, {
  16. onFileDrop: (acceptedFiles) => actionUploadFile(acceptedFiles[0]),
  17. })(ProfileImageEditor);
  18. const userSchema = Yup.object().shape({
  19. name: Yup.string(),
  20. username: Yup.string().min(3, "Too Short!").max(15, "Too Long!").required("Required"),
  21. password: Yup.string().min(3, "Too Short!").max(15, "Too Long!"),
  22. nick: Yup.string(),
  23. });
  24. export const UserForm = ({
  25. serverErrors = [],
  26. onSaveClick,
  27. onSave,
  28. onClose,
  29. onUnmount,
  30. promiseStatus,
  31. deletePromiseStatus,
  32. avatar = null,
  33. user = {},
  34. } = {}) => {
  35. const { setAlert } = useContext(UIContext);
  36. const [promiseTimeOut, setPromiseTimeOut] = useState(null);
  37. const [showPassword, setShowPassword] = useState(false);
  38. const [acl, setAcl] = useState([]);
  39. const navigate = useNavigate();
  40. const formik = useFormik({
  41. initialValues: {
  42. name: "",
  43. username: "",
  44. nick: "",
  45. password: "",
  46. },
  47. validationSchema: userSchema,
  48. validateOnChange: true,
  49. onSubmit: () => {
  50. let userToSave = {};
  51. userToSave = formik.values;
  52. user?._id && (userToSave._id = user._id);
  53. userToSave.acl = acl;
  54. avatar ? (userToSave.avatar = avatar) : delete userToSave.avatar;
  55. onSaveClick && onSaveClick();
  56. onSave(userToSave);
  57. setPromiseTimeOut(setTimeout(() => formik.setSubmitting(false), 3000));
  58. },
  59. });
  60. useEffect(() => {
  61. return () => {
  62. promiseTimeOut && clearTimeout(promiseTimeOut);
  63. setPromiseTimeOut(null);
  64. };
  65. }, []);
  66. useEffect(() => {
  67. if (promiseStatus === "FULFILLED") {
  68. formik.setSubmitting(false);
  69. promiseTimeOut && clearTimeout(promiseTimeOut);
  70. setPromiseTimeOut(null);
  71. setAlert({
  72. show: true,
  73. severity: "success",
  74. message: "Готово",
  75. });
  76. }
  77. if (promiseStatus === "REJECTED") {
  78. const errorMessage = (serverErrors ? [].concat(serverErrors) : []).reduce((prev, curr) => prev + "\n" + curr.message, "");
  79. formik.setSubmitting(false);
  80. promiseTimeOut && clearTimeout(promiseTimeOut);
  81. setPromiseTimeOut(null);
  82. setAlert({
  83. show: true,
  84. severity: "error",
  85. message: errorMessage,
  86. });
  87. }
  88. }, [promiseStatus]);
  89. useEffect(() => {
  90. if (deletePromiseStatus === "FULFILLED") {
  91. promiseTimeOut && clearTimeout(promiseTimeOut);
  92. setPromiseTimeOut(null);
  93. navigate("/admin/users/");
  94. }
  95. if (deletePromiseStatus === "REJECTED") {
  96. promiseTimeOut && clearTimeout(promiseTimeOut);
  97. setPromiseTimeOut(null);
  98. setAlert({
  99. show: true,
  100. severity: "error",
  101. message: "Помилка",
  102. });
  103. }
  104. return () => {
  105. onUnmount && onUnmount();
  106. };
  107. }, [deletePromiseStatus]);
  108. useEffect(() => {
  109. setAcl(user?.acl || []);
  110. formik.setFieldValue("name", user.name || "");
  111. formik.setFieldValue("username", user.username || "");
  112. formik.setFieldValue("nick", user.nick || "");
  113. formik.setFieldValue("password", user.password || "");
  114. formik.validateForm();
  115. }, [user]);
  116. useEffect(() => {
  117. return () => {
  118. onClose && onClose();
  119. };
  120. }, []);
  121. return (
  122. <Box className="UserForm" component="form" onSubmit={formik.handleSubmit}>
  123. <Grid container>
  124. <Grid item xs={5}>
  125. <CProfileImageEditor avatar={avatar} />
  126. </Grid>
  127. <Grid item xs={7}>
  128. <TextField
  129. id="name"
  130. name="name"
  131. variant="outlined"
  132. label="Ім'я"
  133. size="small"
  134. error={formik.touched.name && Boolean(formik.errors.name)}
  135. value={formik.values.name}
  136. onBlur={formik.handleBlur}
  137. onChange={formik.handleChange}
  138. helperText={formik.touched.name && formik.errors.name}
  139. multiline
  140. fullWidth
  141. sx={{ mt: 2 }}
  142. />
  143. <TextField
  144. variant="outlined"
  145. id="username"
  146. name="username"
  147. label="Username"
  148. size="small"
  149. error={formik.touched.username && Boolean(formik.errors.username)}
  150. value={formik.values.username}
  151. onBlur={formik.handleBlur}
  152. onChange={formik.handleChange}
  153. helperText={formik.touched.username && formik.errors.username}
  154. multiline
  155. fullWidth
  156. sx={{ mt: 2 }}
  157. />
  158. <TextField
  159. variant="outlined"
  160. id="nick"
  161. name="nick"
  162. label="Nick"
  163. size="small"
  164. error={formik.touched.nick && Boolean(formik.errors.nick)}
  165. value={formik.values.nick}
  166. onBlur={formik.handleBlur}
  167. onChange={formik.handleChange}
  168. helperText={formik.touched.nick && formik.errors.nick}
  169. multiline
  170. fullWidth
  171. sx={{ mt: 2 }}
  172. />
  173. <TextField
  174. id="password"
  175. name="password"
  176. variant="outlined"
  177. size="small"
  178. label="Новий пароль"
  179. type={showPassword ? "text" : "password"}
  180. error={formik.touched.password && Boolean(formik.errors.password)}
  181. value={formik.values.password}
  182. onBlur={formik.handleBlur}
  183. onChange={formik.handleChange}
  184. helperText={formik.touched.password && formik.errors.password}
  185. InputProps={{
  186. endAdornment: (
  187. <IconButton onClick={() => setShowPassword((prev) => !prev)} edge="end">
  188. {showPassword ? <MdVisibilityOff /> : <MdVisibility />}
  189. </IconButton>
  190. ),
  191. }}
  192. fullWidth
  193. sx={{ mt: 2 }}
  194. />
  195. <Box sx={{ mt: 3 }}>
  196. <InputLabel>Permissions</InputLabel>
  197. <Select
  198. placeholder="Обрати категорії"
  199. value={acl.map((value) => ({ value, label: value }))}
  200. closeMenuOnSelect={false}
  201. onChange={(e) => setAcl(e.map(({ value }) => value))}
  202. options={aclList}
  203. isMulti={true}
  204. />
  205. </Box>
  206. </Grid>
  207. </Grid>
  208. <Stack direction="row" sx={{ mt: 3 }} justifyContent="flex-end" spacing={1}>
  209. <Button variant="contained" disabled={!formik.isValid || formik.isSubmitting} type="submit">
  210. Зберегти
  211. </Button>
  212. </Stack>
  213. </Box>
  214. );
  215. };
  216. export const CUserForm = connect(
  217. (state) => ({
  218. promiseStatus: state.promise.userUpsert?.status || null,
  219. deletePromiseStatus: state.promise.userDelete?.status || null,
  220. user: state.promise?.adminUserById?.payload || {},
  221. avatar: state.promise?.uploadFile?.payload || state.promise?.adminUserById?.payload?.avatar || null,
  222. serverErrors: state.promise?.userUpsert?.error || [],
  223. }),
  224. {
  225. onSave: (user) => actionUserUpdate(user),
  226. onClose: () => actionPromisesClear(["userUpsert", "userDelete"]),
  227. }
  228. )(UserForm);