GoodForm.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import { connect } from 'react-redux';
  2. import React, { useState, useEffect, useContext } from 'react';
  3. import { actionPromise, actionPromiseClear } from '../../../reducers';
  4. import Select from 'react-select';
  5. import { actionGoodUpdate } from '../../../actions/actionGoodUpdate';
  6. import { EntityEditor } from '../../common/EntityEditor';
  7. import { actionUploadFiles } from '../../../actions/actionUploadFiles';
  8. import { UIContext } from '../../UIContext';
  9. import {
  10. Alert,
  11. Box,
  12. Button,
  13. Chip,
  14. FormControl,
  15. InputLabel,
  16. MenuItem,
  17. OutlinedInput,
  18. Snackbar,
  19. Stack,
  20. TextareaAutosize,
  21. TextField,
  22. Typography,
  23. } from '@mui/material';
  24. import { useFormik } from 'formik';
  25. import * as Yup from 'yup';
  26. import { Error } from '../../common/Error';
  27. const goodSchema = Yup.object().shape({
  28. name: Yup.string().required("Обов'язкове"),
  29. description: Yup.string().required("Обов'язкове"),
  30. price: Yup.number().min(0, 'більше або равно 0').required("Обов'язкове"),
  31. amount: Yup.number().min(0, 'більше або равно 0').required("Обов'язкове"),
  32. });
  33. const CGoodEditor = connect(
  34. (state) => ({
  35. entity: state.promise?.adminGoodById?.payload || {},
  36. uploadFiles: state.promise?.uploadFiles,
  37. }),
  38. {
  39. onFileDrop: (files) => actionUploadFiles(files),
  40. }
  41. )(EntityEditor);
  42. export const GoodForm = ({
  43. serverErrors = [],
  44. onSaveClick,
  45. onSave,
  46. onClose,
  47. promiseStatus,
  48. catList = [],
  49. good = {},
  50. } = {}) => {
  51. const [inputCategories, setInputCategories] = useState([]);
  52. const [inputImages, setInputImages] = useState([]);
  53. const { setAlert } = useContext(UIContext);
  54. const formik = useFormik({
  55. initialValues: {
  56. name: '',
  57. description: '',
  58. price: 0,
  59. amount: 0,
  60. },
  61. validationSchema: goodSchema,
  62. validateOnChange: true,
  63. onSubmit: () => {
  64. let goodToSave = {};
  65. good?._id && (goodToSave._id = good._id);
  66. goodToSave.name = formik.values.name;
  67. goodToSave.description = formik.values.description;
  68. goodToSave.price = +formik.values.price;
  69. goodToSave.amount = +formik.values.amount;
  70. goodToSave.categories = inputCategories;
  71. goodToSave.images = inputImages?.map(({ _id }) => ({ _id })) || [];
  72. onSaveClick && onSaveClick();
  73. onSave(goodToSave);
  74. },
  75. });
  76. useEffect(() => {
  77. if (promiseStatus === 'FULFILLED') {
  78. formik.setSubmitting(false);
  79. setAlert({
  80. show: true,
  81. severity: 'success',
  82. message: 'Готово',
  83. });
  84. }
  85. if (promiseStatus === 'REJECTED') {
  86. const errorMessage = serverErrors.reduce((prev, curr) => prev + '\n' + curr.message, '');
  87. formik.setSubmitting(false);
  88. setAlert({
  89. show: true,
  90. severity: 'error',
  91. message: errorMessage,
  92. });
  93. }
  94. }, [promiseStatus]);
  95. useEffect(() => {
  96. setInputCategories(good?.categories || []);
  97. setInputImages(good?.images || []);
  98. formik.setFieldValue('name', good.name || '');
  99. formik.setFieldValue('description', good.description || '');
  100. formik.setFieldValue('amount', good.amount || 0);
  101. formik.setFieldValue('price', good.price || 0);
  102. }, [good.categories, good.name, good.description, good.amount, good.price]);
  103. useEffect(() => {
  104. return () => {
  105. onClose && onClose();
  106. };
  107. }, []);
  108. return (
  109. <Box className="GoodForm" component="form" onSubmit={formik.handleSubmit}>
  110. <TextField
  111. id="name"
  112. name="name"
  113. variant="outlined"
  114. label="Назва"
  115. size="small"
  116. error={formik.touched.name && Boolean(formik.errors.name)}
  117. value={formik.values.name}
  118. onBlur={formik.handleBlur}
  119. onChange={formik.handleChange}
  120. helperText={formik.touched.name && formik.errors.name}
  121. multiline
  122. fullWidth
  123. sx={{ mt: 2 }}
  124. />
  125. <Box sx={{ mt: 3 }}>
  126. <InputLabel>Зображення</InputLabel>
  127. <CGoodEditor onImagesSave={(images) => setInputImages(images)} />
  128. </Box>
  129. <TextField
  130. variant="outlined"
  131. id="description"
  132. name="description"
  133. label="Опис"
  134. size="small"
  135. error={formik.touched.description && Boolean(formik.errors.description)}
  136. value={formik.values.description}
  137. onBlur={formik.handleBlur}
  138. onChange={formik.handleChange}
  139. helperText={formik.touched.description && formik.errors.description}
  140. multiline
  141. fullWidth
  142. sx={{ mt: 2 }}
  143. />
  144. <Box sx={{ mt: 3 }}>
  145. <TextField
  146. variant="outlined"
  147. id="price"
  148. name="price"
  149. label="Ціна"
  150. size="small"
  151. error={formik.touched.price && Boolean(formik.errors.price)}
  152. value={formik.values.price}
  153. onBlur={formik.handleBlur}
  154. onChange={formik.handleChange}
  155. helperText={formik.touched.price && formik.errors.price}
  156. multiline
  157. fullWidth
  158. sx={{ mt: 2 }}
  159. />
  160. </Box>
  161. <Box sx={{ mt: 3 }}>
  162. <TextField
  163. variant="outlined"
  164. id="amount"
  165. name="amount"
  166. label="Кількість"
  167. size="small"
  168. error={formik.touched.amount && Boolean(formik.errors.amount)}
  169. value={formik.values.amount}
  170. onBlur={formik.handleBlur}
  171. onChange={formik.handleChange}
  172. helperText={formik.touched.amount && formik.errors.amount}
  173. multiline
  174. fullWidth
  175. sx={{ mt: 2 }}
  176. />
  177. </Box>
  178. <Box sx={{ mt: 3 }}>
  179. <InputLabel>Категорії</InputLabel>
  180. <Select
  181. placeholder="Обрати категорії"
  182. value={inputCategories.map(({ _id, name }) => ({ value: _id, label: name }))}
  183. closeMenuOnSelect={false}
  184. onChange={(e) => setInputCategories(e.map(({ label, value }) => ({ _id: value, name: label })))}
  185. options={catList?.map(({ _id, name }) => ({ value: _id, label: name }))}
  186. isMulti={true}
  187. />
  188. </Box>
  189. <Box direction="row" sx={{ mt: 3 }} justifyContent="flex-end">
  190. <Button variant="contained" disabled={!formik.isValid || formik.isSubmitting} type="submit" fullWidth>
  191. Зберегти
  192. </Button>
  193. </Box>
  194. </Box>
  195. );
  196. };
  197. export const CGoodForm = connect(
  198. (state) => ({
  199. catList: state.promise.catAll?.payload || [],
  200. promiseStatus: state.promise.goodUpsert?.status || null,
  201. good: state.promise?.adminGoodById?.payload || {},
  202. serverErrors: state.promise?.goodUpsert?.error || [],
  203. }),
  204. {
  205. onSave: (good) => actionGoodUpdate(good),
  206. onClose: () => actionPromiseClear('goodUpsert'),
  207. }
  208. )(GoodForm);