index.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. import React from 'react';
  2. import Button from '@material-ui/core/Button';
  3. import TextField from '@material-ui/core/TextField';
  4. import { makeStyles } from '@material-ui/core/styles';
  5. import './Add.scss';
  6. import {useState, useEffect} from "react";
  7. import {useDispatch, useSelector} from "react-redux";
  8. import {origUrl,history} from '../../App.js';
  9. import AddCircleIcon from '@material-ui/icons/AddCircle';
  10. import {useDropzone} from 'react-dropzone';
  11. import {
  12. DndContext,
  13. KeyboardSensor,
  14. PointerSensor,
  15. useSensor,
  16. useSensors, useDroppable
  17. } from "@dnd-kit/core";
  18. import { sortableKeyboardCoordinates, rectSortingStrategy, SortableContext, useSortable, horizontalListSortingStrategy } from "@dnd-kit/sortable";
  19. import { CSS } from "@dnd-kit/utilities";
  20. import {arrayMoveImmutable} from 'array-move';
  21. import {connect} from 'react-redux';
  22. import {actionUpload,actioCreateAd} from '../../actions';
  23. const SortableItem = (props) => {
  24. const {
  25. attributes,
  26. listeners,
  27. setNodeRef,
  28. transform,
  29. transition
  30. } = useSortable({ id: props.id });
  31. const itemStyle = {
  32. transform: CSS.Transform.toString(transform),
  33. transition,
  34. cursor: "grab",
  35. };
  36. const Render = props.render
  37. return (
  38. <div style={itemStyle} ref={setNodeRef} {...attributes} {...listeners}>
  39. <Render {...{[props.itemProp]:props.item}}/>
  40. </div>
  41. );
  42. };
  43. const Droppable = ({ id, items, itemProp, keyField, render }) => {
  44. const { setNodeRef } = useDroppable({ id });
  45. return (
  46. <SortableContext id={id} items={items} strategy={rectSortingStrategy}>
  47. {items.map((item) => (
  48. <SortableItem render={render} key={item[keyField]} id={item}
  49. itemProp={itemProp} item={item}/>
  50. ))}
  51. </SortableContext>
  52. );
  53. };
  54. function Dnd({items:startItems,render, itemProp, keyField, onChange, horizontal}) {
  55. const [items, setItems] = useState(
  56. startItems
  57. );
  58. useEffect(() => setItems(startItems), [startItems])
  59. useEffect(() => {
  60. if (typeof onChange === 'function'){
  61. onChange(items)
  62. }
  63. },[items])
  64. const sensors = useSensors(
  65. useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
  66. useSensor(KeyboardSensor, {
  67. coordinateGetter: sortableKeyboardCoordinates
  68. })
  69. );
  70. const handleDragEnd = ({ active, over }) => {
  71. const activeIndex = active.data.current.sortable.index;
  72. const overIndex = over.data.current?.sortable.index || 0;
  73. setItems((items) => {
  74. return arrayMoveImmutable( items, activeIndex, overIndex)
  75. });
  76. }
  77. const containerStyle = {
  78. display: horizontal ? "flex" : '',
  79. flexWrap: "wrap",
  80. marginBottom: "30px",
  81. justifyContent: "center",
  82. };
  83. return (
  84. <DndContext
  85. sensors={sensors}
  86. onDragEnd={handleDragEnd}
  87. >
  88. <div style={containerStyle}>
  89. <Droppable id="aaa"
  90. items={items}
  91. itemProp={itemProp}
  92. keyField={keyField}
  93. render={render}/>
  94. </div>
  95. </DndContext>
  96. );
  97. }
  98. const ImgBox = ({image, onDelete})=>{
  99. const useStyles = makeStyles((theme) => ({
  100. img:{
  101. borderRadius: "8px",
  102. width: '100%',
  103. height: '100%',
  104. margin: '5px',
  105. maxWidth: '200px',
  106. }
  107. }));
  108. const classes = useStyles();
  109. return(<>
  110. {image!== undefined && <img className={classes.img} src={origUrl+image.url} onClick={() => onDelete(image)}/>}
  111. </>
  112. )
  113. }
  114. const useStyles = makeStyles((theme) => ({
  115. root: {
  116. height: '50vh',
  117. },
  118. paper: {
  119. margin: theme.spacing(8, 4),
  120. display: 'flex',
  121. flexDirection: 'column',
  122. alignItems: 'center',
  123. },
  124. input:{
  125. marginBottom: '3%'
  126. },
  127. form: {
  128. width: '100%', // Fix IE 11 issue.
  129. marginTop: theme.spacing(1),
  130. },
  131. submit: {
  132. margin: theme.spacing(3, 0, 2),
  133. },
  134. }));
  135. function CreateAd({action, newImg}) {
  136. const classes = useStyles()
  137. const dispatch = useDispatch();
  138. const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
  139. const [createAd, setCreateAd] = useState({ title:'', description:'', price:0});
  140. const [create, setCreate] = useState('');
  141. console.log(create)
  142. useEffect(() => {
  143. if(newImg){
  144. console.log(newImg)
  145. if(newImg._id){
  146. if(createAd.images){
  147. setCreateAd({...createAd,images: [...createAd.images, newImg]})
  148. console.log(createAd)
  149. }else{
  150. setCreateAd({...createAd,images: [newImg]})
  151. }
  152. }
  153. }
  154. }, [newImg]);
  155. useEffect(() => {
  156. setCreateAd({images:[], title:'', description:'', price:0})
  157. },[])
  158. useEffect(() => {
  159. acceptedFiles.map(file =>action(file));
  160. }, [acceptedFiles]);
  161. const deleteImage = image => setCreateAd({...createAd, images: createAd.images.filter(i => i !== image)})
  162. const localPostImage = ({image}) => <ImgBox image={image}
  163. onDelete={imgToDelete => deleteImage(imgToDelete)}/>
  164. const onclickCreate = ()=>{
  165. if(create.images.length>0){
  166. let arrIdImg = create.images.map((el)=> el={_id:el._id})
  167. console.log(arrIdImg)
  168. dispatch(actioCreateAd({...createAd,images: arrIdImg, tags: ['']}))
  169. }else{
  170. dispatch(actioCreateAd({...createAd, tags: ['']}))
  171. }
  172. setCreateAd({ title:'', description:'', price:0})
  173. history.push("/page/1")
  174. }
  175. return (
  176. <main className="mainAdd">
  177. <div className="bannerAdd" >
  178. <div className="imd__flex__boxx">
  179. <Dnd items={createAd.images||[]} render={localPostImage} itemProp="image" keyField="_id"
  180. onChange={newArray=>setCreate({...createAd,images: newArray})}
  181. horizontal/>
  182. </div>
  183. <div className="conteiner">
  184. <div className="flex__boxx">
  185. <section className="containerSection">
  186. <div {...getRootProps({className: 'dropzone'})}>
  187. <input {...getInputProps()} />
  188. <p>Drag 'n' drop some files here, or click to select files</p>
  189. </div>
  190. </section>
  191. <div className="textBox">
  192. <TextField
  193. type='number'
  194. value={createAd.price}
  195. onChange={(e) => setCreateAd({...createAd, price: +(e.target.value)})}
  196. className={classes.input}
  197. required id="standard-required"
  198. label="Price $"
  199. />
  200. <TextField
  201. value={createAd.title}
  202. onChange={(e) => setCreateAd({...createAd, title: e.target.value})}
  203. className={classes.input}
  204. required id="standard-required"
  205. label="Title"
  206. />
  207. <TextField
  208. value={createAd.description}
  209. onChange={(e) => setCreateAd({...createAd, description: e.target.value})}
  210. id="outlined-multiline-static"
  211. label="Description"
  212. multiline
  213. rows={4}
  214. variant="outlined"
  215. />
  216. <Button
  217. onClick={onclickCreate}
  218. type="submit"
  219. fullWidth
  220. variant="contained"
  221. color="primary"
  222. className={classes.submit}
  223. startIcon={<AddCircleIcon/>}
  224. >
  225. create ad
  226. </Button>
  227. </div>
  228. </div>
  229. </div>
  230. </div>
  231. </main>
  232. );
  233. }
  234. const CreateAdConnect = connect(state => ({
  235. newImg: state.promise?.upload?.payload||[]}),
  236. {action: actionUpload} )(CreateAd)
  237. export default CreateAdConnect