I'm trying to implement drag and drop behaviour using React and react-beautiful-dnd library.
I want to chose some images using react-dropzone library and after choosing images I show thumbnails on the right side of the screen and after that I want to be able to drag one of those thumbnails to the left side and drop it to one of those containers.
My code is as follows:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Dropzone from "react-dropzone";
import { Animated } from "react-animated-css";
import { orderBy } from "lodash";
import UUID from "uuid";
import "./styles.css";
const animationIn = "fadeInDown";
const animationOut = "fadeOutUp";
const animationDuration = 400; // in ms
const pictureTypes = [
{
title: "3/4 front left",
imageOverlay: "https://via.placeholder.com/100",
item: "front-left",
mandatory: true,
image: null,
priority: 1
},
{
title: "3/4 rear right",
imageOverlay: "https://via.placeholder.com/100",
item: "rear-right",
mandatory: true,
image: null,
priority: 2
},
{
title: "Inside door right",
imageOverlay: "https://via.placeholder.com/100",
item: "front-door-right-i",
mandatory: true,
image: null,
priority: 3
}
];
class App extends Component {
constructor(props) {
super(props);
this.state = {
files: [],
pictureTypes: pictureTypes
};
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result) {
debugger;
// dropped outside the list
if (!result.destination) {
return;
}
}
addFilesToState(files) {
let files_with_preview = [];
files.map(file => {
file["preview"] = URL.createObjectURL(file);
files_with_preview.push(file);
this.setState({ [`visibleAnimate${file.path}`]: true });
});
const new_files = [...this.state.files, ...files_with_preview];
this.setState({ files: new_files });
}
renderPreviews(files) {
if (files.length < 1)
return <div>Drag and drop some files to see them here.</div>;
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<div>Chosen pictures</div>
<div style={{ display: "flex", flexDirection: "row" }}>
{files.map((file, index) => {
return (
<Draggable key={UUID.v4()} draggableId={UUID.v4()} index={index}>
{provided => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<img
src={file.preview}
alt={file.path}
style={{ width: 80 }}
/>
</div>
)}
</Draggable>
);
})}
</div>
</div>
);
}
handlePictureTypesDrop(file, pictureType) {
const file_blob = URL.createObjectURL(file);
const updated_picture_type = {
...this.state.pictureTypes.find(pt => pt.item === pictureType.item),
image: file_blob
};
const updated_picture_types = [
...this.state.pictureTypes.filter(pt => pt.item !== pictureType.item),
updated_picture_type
];
let new_picture_types = [...updated_picture_types];
this.setState({ pictureTypes: new_picture_types });
}
renderPictureTypes() {
const { allowed_types } = this.props;
const { pictureTypes } = this.state;
const self = this;
return orderBy(pictureTypes, "priority").map(pt => {
return (
<div style={{ width: "25%", marginRight: 5 }}>
<Dropzone
onDrop={files => self.handlePictureTypesDrop(files[0], pt)}
accept={allowed_types}
multiple={false}
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
<div className="picture-types-wrapper">
<div>
<img
src={pt.image !== null ? pt.image : pt.imageOverlay}
alt={pt.title}
/>
</div>
<div style={{ fontSize: "0.65rem" }}>{pt.title}</div>
</div>
</div>
)}
</Dropzone>
</div>
);
});
}
// Normally you would want to split things out into separate components.
// But in this example everything is just done in one place for simplicity
render() {
const { files } = this.state;
const self = this;
return (
<DragDropContext onDragEnd={this.onDragEnd}>
<Droppable droppableId="droppable">
{provided => (
<div
key="droppable"
{...provided.droppableProps}
ref={provided.innerRef}
>
<Dropzone
onDrop={files => self.addFilesToState(files)}
accept="image/jpeg, image/png"
>
{({ getRootProps, getInputProps }) => (
<section className="drag-drop-section">
<div {...getRootProps()}>
<input {...getInputProps()} />
<p className="drag-drop-text">
Drag 'n' drop some files here, or click to select files
</p>
</div>
</section>
)}
</Dropzone>
<div
style={{ display: "flex", flexDirection: "row", marginTop: 10 }}
>
<div style={{ display: "flex", flexDirection: "row" }}>
{self.renderPictureTypes()}
</div>
<div className="flex w-1/2 pl-2">
{self.renderPreviews(files)}
</div>
</div>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
}
// Put the thing into the DOM!
ReactDOM.render(<App />, document.getElementById("root"));
Here is the example code on codesandbox.
The photo's are successfully added to the right side where I render the thumbnails but I cant drag one of them then to the left side.
Any idea how to solve it?