index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import { Box, Button, Grid, IconButton, Paper, Table, TableBody, TableCell, TableRow, TextField } from "@mui/material";
  2. import { useContext, useEffect, useState } from "react";
  3. import { connect } from "react-redux";
  4. import { actionUpdateAvatar } from "../../../actions/actionUpdateAvatar";
  5. import { actionUserUpdate } from "../../../actions/actionUserUpdate";
  6. import { Ava } from "../../common/Ava";
  7. import { DropZone } from "../../common/DropZone";
  8. import { CProfileImage } from "./ProfileImage";
  9. import { useFormik } from "formik";
  10. import * as Yup from "yup";
  11. import { UIContext } from "../../UIContext";
  12. import { MdVisibility, MdVisibilityOff } from "react-icons/md";
  13. const CDropZone = connect(null, { onFileDrop: (acceptedFiles) => actionUpdateAvatar(acceptedFiles[0]) })(DropZone);
  14. const profileSchema = Yup.object().shape({
  15. name: Yup.string(),
  16. username: Yup.string().min(3, "Too Short!").max(15, "Too Long!").required("Required"),
  17. password: Yup.string().min(3, "Too Short!").max(15, "Too Long!"),
  18. nick: Yup.string(),
  19. });
  20. export const ProfileForm = ({ profile = {}, promiseStatus, onProfileSave, serverErrors = [] } = {}) => {
  21. const [isLetterShown, setIsLetterShown] = useState(false);
  22. const [editMod, setEditMod] = useState(false);
  23. const [showPassword, setShowPassword] = useState(false);
  24. const { setAlert } = useContext(UIContext);
  25. const [promiseTimeOut, setPromiseTimeOut] = useState(null);
  26. const formik = useFormik({
  27. initialValues: {
  28. username: "",
  29. password: "",
  30. repeatPassword: "",
  31. },
  32. validationSchema: profileSchema,
  33. validateOnChange: true,
  34. onSubmit: () => {
  35. onProfileSave(formik.values);
  36. setPromiseTimeOut(setTimeout(() => formik.setSubmitting(false), 3000));
  37. },
  38. });
  39. useEffect(() => {
  40. return () => {
  41. promiseTimeOut && clearTimeout(promiseTimeOut);
  42. setPromiseTimeOut(null);
  43. };
  44. }, []);
  45. useEffect(() => {
  46. formik.setValues(profile);
  47. return () => {
  48. promiseTimeOut && clearTimeout(promiseTimeOut);
  49. setPromiseTimeOut(null);
  50. };
  51. }, [profile]);
  52. useEffect(() => {
  53. if (promiseStatus === "FULFILLED") {
  54. formik.setSubmitting(false);
  55. promiseTimeOut && clearTimeout(promiseTimeOut);
  56. setPromiseTimeOut(null);
  57. setAlert({
  58. show: true,
  59. severity: "success",
  60. message: "Готово",
  61. });
  62. }
  63. if (promiseStatus === "REJECTED") {
  64. const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
  65. formik.setSubmitting(false);
  66. promiseTimeOut && clearTimeout(promiseTimeOut);
  67. setPromiseTimeOut(null);
  68. setAlert({
  69. show: true,
  70. severity: "error",
  71. message: errorMessage,
  72. });
  73. }
  74. }, [promiseStatus]);
  75. return (
  76. <Box component="form" className="ProfileForm" onSubmit={formik.handleSubmit}>
  77. <Grid container spacing={3}>
  78. <Grid xs={4} item>
  79. <CDropZone>
  80. <Box
  81. className="profileImageWrapper"
  82. onMouseEnter={() => setIsLetterShown(true)}
  83. onMouseLeave={() => setIsLetterShown(false)}
  84. >
  85. <CProfileImage />
  86. <Box className={`letter ${isLetterShown && "show"}`}>Drop file or click to update</Box>
  87. </Box>
  88. </CDropZone>
  89. </Grid>
  90. <Grid xs={8} item>
  91. <Table justify>
  92. <TableBody>
  93. <TableRow>
  94. <TableCell>Username</TableCell>
  95. <TableCell>
  96. {editMod ? (
  97. <TextField
  98. size="small"
  99. id="username"
  100. name="username"
  101. variant="standard"
  102. label="Username"
  103. error={formik.touched.username && Boolean(formik.errors.username)}
  104. value={formik.values.username}
  105. onBlur={formik.handleBlur}
  106. onChange={formik.handleChange}
  107. helperText={formik.touched.username && formik.errors.username}
  108. />
  109. ) : (
  110. formik.values.username
  111. )}
  112. </TableCell>
  113. </TableRow>
  114. <TableRow>
  115. <TableCell>Nick</TableCell>
  116. <TableCell>
  117. {editMod ? (
  118. <TextField
  119. size="small"
  120. id="nick"
  121. name="nick"
  122. variant="standard"
  123. label="Nick"
  124. error={formik.touched.nick && Boolean(formik.errors.nick)}
  125. value={formik.values.nick}
  126. onBlur={formik.handleBlur}
  127. onChange={formik.handleChange}
  128. helperText={formik.touched.nick && formik.errors.nick}
  129. />
  130. ) : (
  131. formik.values.nick
  132. )}
  133. </TableCell>
  134. </TableRow>
  135. <TableRow>
  136. <TableCell>Name</TableCell>
  137. <TableCell>
  138. {editMod ? (
  139. <TextField
  140. size="small"
  141. id="name"
  142. name="name"
  143. variant="standard"
  144. label="Name"
  145. error={formik.touched.name && Boolean(formik.errors.name)}
  146. value={formik.values.name}
  147. onBlur={formik.handleBlur}
  148. onChange={formik.handleChange}
  149. helperText={formik.touched.name && formik.errors.name}
  150. />
  151. ) : (
  152. formik.values.name
  153. )}
  154. </TableCell>
  155. </TableRow>
  156. <TableRow>
  157. <TableCell>Password</TableCell>
  158. <TableCell>
  159. {editMod ? (
  160. <TextField
  161. size="small"
  162. id="password"
  163. name="password"
  164. variant="standard"
  165. label="Password"
  166. type={showPassword ? "text" : "password"}
  167. error={formik.touched.password && Boolean(formik.errors.password)}
  168. value={formik.values.password}
  169. onBlur={formik.handleBlur}
  170. onChange={formik.handleChange}
  171. helperText={formik.touched.password && formik.errors.password}
  172. InputProps={{
  173. endAdornment: (
  174. <IconButton onClick={() => setShowPassword((prev) => !prev)} edge="end">
  175. {showPassword ? <MdVisibilityOff /> : <MdVisibility />}
  176. </IconButton>
  177. ),
  178. }}
  179. />
  180. ) : (
  181. "****************"
  182. )}
  183. </TableCell>
  184. </TableRow>
  185. <TableRow>
  186. <TableCell></TableCell>
  187. <TableCell>
  188. {editMod ? (
  189. <Box display="flex" justifyContent="flex-end">
  190. <Button variant="text" color="error" onClick={() => setEditMod(false)}>
  191. Скасувати
  192. </Button>
  193. <Button
  194. variant="text"
  195. color="primary"
  196. type="submit"
  197. disabled={formik.isSubmitting || !formik.isValid}
  198. >
  199. Зберегти
  200. </Button>
  201. </Box>
  202. ) : (
  203. <Box display="flex" justifyContent="flex-end">
  204. <Button onClick={() => setEditMod(true)}>Редагувати</Button>
  205. </Box>
  206. )}
  207. </TableCell>
  208. </TableRow>
  209. </TableBody>
  210. </Table>
  211. </Grid>
  212. </Grid>
  213. </Box>
  214. );
  215. };
  216. export const CProfileForm = connect(
  217. (state) => ({
  218. profile: state.promise?.aboutMe?.payload,
  219. promiseStatus: state.promise.userUpsert?.status || null,
  220. serverErrors: state.promise?.userUpsert?.error || [],
  221. }),
  222. {
  223. onProfileSave: (profile = {}) => actionUserUpdate(profile),
  224. }
  225. )(ProfileForm);