ReactJS DropZone browser attempts to open file on drop - reactjs

Trying to implement the Dropzone component but not have much luck. Am I missing something here?
import { useState } from 'react';
import { useDropzone } from 'react-dropzone';
import styled from 'styled-components';
export const FilDataForm = (props) => {
const [files, setFiles] = useState([])
const getColor = (props) => {
if (props.isDragAccept) return '#00e676';
if (props.isDragReject) return '#ff1744';
if (props.isDragActive) return '#2196f3';
return '#eeeeee';
}
const onDrop = (file) => {
console.log('HERE!!!!!')
let nf = files;
nf.push(file)
setFiles(nf)
}
const Container = styled.div`
flex:1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
border-width: 2px;
border-radius: 2px;
border-color: ${props => getColor(props)};
border-style: dashed;
background-color: #fafafa;
color: #bdbdbd;
outline: none;
transition: border .24s ease-in-out;
`
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone(onDrop);
return (
<div className="modal">
<div className="dialog" style={{ width: "25%", marginBottom: "50px" }}>
<div className="header"><h2>File Uploader</h2></div>
<div className="content">
<Container {...getRootProps({ isDragActive, isDragAccept, isDragReject })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
<div className="grid-container" style={{ marginTop: "20px", height: "250px" }}></div>
</div>
</div>
</div>
)
}
Dragging the file(s) into the drop area causes the browser to launch a new tab attempting to open the file. Any help is appreciated.
EDIT
Clicking in the Dropzone does not open the file dialog either.

You need to prevent the default event.
I'm using Class component based React Dropzone and this is how i have stopped the default event.
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
Complete Code
<Dropzone onDrop={ (files) => fileHandling(files) } >
{({ getRootProps, getInputProps }) => (
<div
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
style={{ border: '1px solid #707070' }}
>
<input {...getInputProps()} />
<h3 style={{ cursor: 'pointer' }}>
Drag & Drop file or click here to Upload
</h3>
</div>
)}
</Dropzone>
Hope it helps

Related

Radio button style changes when clicked with React Hooks

I want the radio button to change when clicked. This is what i have now image
I want it to change to this when clicked
Here's my code: `
const [active, setIsActive] = useState(false)
<div className={`checkbox payment-radio-btn1 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="paystack" name='payment' onChange={handleChange}/>
<label id='paystack'>Paystack (Debit/Credit Card)</label>
</div>
<div className={`checkbox payment-radio-btn2 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="wallet" name='payment' onChange={handleChange}/>
<label id='wallet'>Pay with Wallet</label>
</div>
Here's my css code
.checkbox:hover{
border: 2px solid #00B6F0;
background: #FFFFFF;
}
.payment-radio-btn1{
position: absolute;
width: 406px;
height: 64px;
left: 10px;
top: 128px;
background: #F3F4F5;
box-shadow: 0px 24px 38px 3px rgba(0, 0, 0, 0.14);
border-radius: 4px;
margin-top: 20px;
margin-left: 6px;
display: flex;
}
One option is a custom Radio element that allows you to represent your radio buttons however you like. In this example we use two emoji, but you could use images, or SVG if you wanted.
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
We can use the Radio elements in our app like this.
function App() {
const [radio, selectRadio] =
useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
{/* more radio options ...*/}
</div>
}
This is made possible by writing useRadio which encodes the radio group logic nicely in a custom hook.
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
Here's a minimal, verifiable example. Run it below and click some radio buttons to see the application state change.
function App() {
const [radio, selectRadio] = useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
<Radio checked={radio == "wallet"} onClick={selectRadio("wallet")}>
Pay with Wallet
</Radio>
<Radio checked={radio == "paypal"} onClick={selectRadio("paypal")}>
PayPal
</Radio>
<pre>{JSON.stringify({paymentOption: radio}, null, 2)}</pre>
</div>
}
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
ReactDOM.render(<App/>, document.querySelector("#app"))
.radio { cursor: pointer; }
pre { padding: 0.5rem; background-color: #ffc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Why my react-bootstrap Accordion is not working on small devices?

I have a simple Accordion in one of my components.
function CustomToggle({eventKey}) {
const [children, setChildren] = useState('Mais filtros 🠗')
const decoratedOnClick = useAccordionToggle(eventKey, () =>
setChildren(children === 'Mais filtros 🠗' ? 'Menos filtros 🠕' : 'Mais filtros 🠗')
)
return (
<div className="text-center">
<div className="tag align-center" onClick={decoratedOnClick}>
{children}
</div>
</div>
)
}
...
<Accordion>
<CustomToggle eventKey="0" />
<Accordion.Collapse eventKey="0">
<QueryForm
baseEndpoint={this.props.baseEndpoint}
tagsInitialValues={this.state.searchParams.tags}
textInitialValue={this.state.searchParams.description}
setSearchParams={this.setSearchParams}
/>
</Accordion.Collapse>
</Accordion>
It works perfectly on larger breakpoints, but, for smaller devices, the QueryForm shows in the opposite direction and stays on top of the page's content.
Check the sandbox: https://codesandbox.io/s/0y8cm
(click on 'Mais filtros' to trigger the accordion and see the problematic breakpoint when the navbar toggle appears)
What am I doing wrong?
The default of Accordion react component it doesn't use absolute position for define the position of the accordion content. I'm not sure how you customize position: absolute. Then the first way if you consider don't need to use the position: absolute. You can remove it at:
collapsing {
position: absolute !important;
z-index: 3;
width: 100%;
top: 75px;
}
.collapse.show {
display: block;
position: absolute;
z-index: 3;
width: 100%;
top: 75px;
}
The second way, if you intend to do something with position: absolute in mobile, you should pick a container of the form and add position: relative then your form will render base on the position of that container.
<div style={{ position: "relative" }}>
<Accordion>
<CustomToggle eventKey="0" />
<Accordion.Collapse eventKey="0">
<QueryForm
baseEndpoint={this.props.baseEndpoint}
tagsInitialValues={this.state.searchParams.tags}
textInitialValue={this.state.searchParams.description}
setSearchParams={this.setSearchParams}
/>
</Accordion.Collapse>
</Accordion>
</div>
There is some issue in your Navbar.css. Not sure why you use position to be absolute. I commented out those, and it works now.
.collapsing {
/* position: absolute !important; */
/* z-index: 3; */
width: 100%;
/* top: 75px; */
}
.collapse.show {
display: block;
/* position: absolute; */
/* z-index: 3; */
width: 100%;
/* top: 75px; */
}
https://codesandbox.io/s/relaxed-dust-2yimw?file=/src/components/common/Navbar.css:736-984
Do you run the Accordian on small device?
here is my code. I hope it's will help you.
import React, {useState} from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Accordion from '#material-ui/core/Accordion';
import AccordionSummary from '#material-ui/core/AccordionSummary';
import AccordionDetails from '#material-ui/core/AccordionDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import PropTypes from 'prop-types';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
heading: {
fontSize: theme.typography.pxToRem(1),
fontWeight: theme.typography.fontWeightRegular,
},
}));
const Accordian = ({
title,
data,
onclick,
shownName
}) =>{
const classes = useStyles();
let content;
const [subtitle, setSubtitle] = useState("");
const [expand, setExpand] = useState(true);
const liClick = (e) => {
setSubtitle(e.target.getAttribute('data'));
onclick(e);
setExpand(!expand);
}
const clickExpand = (e) =>{
setExpand(!expand);
}
content = data.map((value, key)=>{
return (
<li
className="list-group-item"
key={data[key][shownName]+"_"+key}
name={data[key][shownName]}
data={data[key][shownName]}
onClick={liClick}
>
{data[key].mark?(<img src={data[key].mark} align="left" className="mark_sign" alt="mark"/>):''}
{data[key][shownName]}
<i className="fa fa-angle-right" align="right"/>
</li>
);
});
return (
<div className={classes.root}>
<div className="container">
<Accordion
defaultExpanded={true}
expanded={expand}
style={{
borderBottom:'1px',
borderBottomColor:'white',
borderBottomStyle:'solid'
}}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography
className={classes.heading}
style={{fontSize:'14px', textAlign:'left'}}
onClick={clickExpand}
>
<span className="Name" style={{ float:'left'}}>{title}{' '}</span>
<span style={{fontSize:'18px', color:'#007bff',width:'100%',top:'10px',left:'0', textAlign:'center', position:'absolute'}}>{' '}{subtitle}</span>
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<span
className="list-group list-group-flush"
align="center"
>
{content}
</span>
</Typography>
</AccordionDetails>
</Accordion>
</div>
</div>
);
}
Accordian.propTypes = {
shownName: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,
onclick: PropTypes.func.isRequired
};
export default Accordian;
Yesterday I fix the this problem. So I share this code.
Please check agian.

React Material UI textfield label problem

I have problem with material ui text field.
There is a form with more textinput. When I scroll down the page, the textinputs label overlap on the header. Could You any idea solve this problem.
Thank You for Your help!
Without scrolling
Scrolling
Code Sandbox: https://codesandbox.io/s/serverless-night-wpkrb?file=/src/App.js
Code from sandbox below:
textinput.js
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
width: "25ch"
}
}
}));
const id = (error) => {
if (error === true) {
return "outlined-error";
} else {
return "outlined";
}
};
const shrink = (arg) => {
// ez a func biztosítja, hogy teljes label legyen és ne legyen kezelési hiba
if (arg === "") {
return false;
} else {
return true;
}
};
export default function BasicTextFields(props) {
const classes = useStyles();
return (
<form className={classes.root} noValidate autoComplete="off">
<TextField
error={props.error}
id={id(props.error)}
label={props.label}
variant="outlined"
onChange={props.change}
style={{ width: props.width }}
value={props.value}
InputLabelProps={{ shrink: shrink(props.value) }}
type={props.type}
inputProps={{ maxLength: props.maxlength }}
/>
</form>
);
}
App.js
import React from "react";
import "./styles.css";
import "w3-css/w3.css";
import BasicTextFields from "./textinput";
export default function App() {
return (
<div className="body">
<div className="w3-top w3-padding-8 w3-border-bottom w3-border-black">
<div className="w3-center w3-padding-16">
<div className="t1">
TündErella - <span style={{ fontSize: 45 }}> some text here.</span>{" "}
</div>
</div>
</div>
<div style={{ marginTop: 200 }}>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
</div>
);
}
styles.css
.App {
font-family: sans-serif;
text-align: center;
}
.body {
border: 1px solid white;
/*background-image: url("./static/background_maarten-deckers_1.jpg");*/
background-color: ivory;
}
.w3-top {
background-color: #daf0da;
}
.t1 {
font-size: 60px;
font-family: "Great Vibes", cursive;
}
The label for outlined TextField is rendered with a z-index of 1. This is the same z-index as applied by w3-top.
You need to bump up the z-index of w3-top in your styles.css:
.w3-top {
background-color: #daf0da;
z-index: 2;
}
In order for these styles to win over the styles defined in w3-css, you need to flip the order of your imports
from:
import "./styles.css";
import "w3-css/w3.css";
to:
import "w3-css/w3.css";
import "./styles.css";
Here's a working example: https://codesandbox.io/s/override-w3-top-z-index-k5fjv?file=/src/styles.css:198-252

How can I have multiple dropzones on one page that preview multiple images when using react-dropzone?

I am using react-dropzone on my app and would like to have multiple dropzones on one page to preview multiple images. For example, I would like to be able to drop a hero image onto a dropzone that displays the hero image on the top of the page. I would then like to drop a different image onto a different dropzone that displays the image in a thumbnail container.
import React, { useState, useMemo, useEffect } from "react";
import Container from "../components/Container";
import { useDropzone } from "react-dropzone";
const Test = () => {
// Dropzone
const baseStyle = {
flex: 1,
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "20px",
borderWidth: 2,
borderRadius: 2,
borderColor: "#eeeeee",
borderStyle: "dashed",
backgroundColor: "#fafafa",
color: "#bdbdbd",
outline: "none",
transition: "border .24s ease-in-out",
};
const activeStyle = {
borderColor: "#2196f3",
};
const acceptStyle = {
borderColor: "#00e676",
};
const rejectStyle = {
borderColor: "#ff1744",
};
const [files, setFiles] = useState({});
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
accept: "image/*",
onDrop: (acceptedFiles) => {
console.log(acceptedFiles);
setFiles(
Object.assign(acceptedFiles[0], {
preview: URL.createObjectURL(acceptedFiles[0]),
})
);
},
});
const style = useMemo(
() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {}),
}),
[isDragActive, isDragReject, isDragAccept]
);
useEffect(
() => () => {
// Make sure to revoke the data uris to avoid memory leaks
URL.revokeObjectURL(files.preview);
},
[files]
);
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<div>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be the dropzone for the Thumbnail image */}
<div>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be where the Hero image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Hero Image"
/>
{/* This would be where the Thumbnail image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Thumbnail Image"
/>
</Container>
);
};
export default Test;
I'm guessing I need to modify the onDrop function but I can't figure how to do this. Any help would be greatly appreciated!
Create two separate file variables and handle them separately.
use two separate getRootsProps and getInputProps on both inputs.
const [file, setFile] = useState({});
const [fileGallery, setFileGallery] = useState({});
const { getRootProps:getRootfileProps, getInputProps:getInputfileProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFile(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFileGallery(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<div>
<div {...getRootfileProps({ style })}>
<input {...getInputfileProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be the dropzone for the Thumbnail image */}
<div>
<div {...getRootGalleryProps({ style })}>
<input {...getInputGalleryProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be where the Hero image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Hero Image"
/>
{/* This would be where the Thumbnail image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Thumbnail Image"
/>
</Container>
);
};
export default Test;
you need to create two separate file variables and handle them separately. also you are using same getRootsProps and getInputProps on both inputs which is not correct.
const [file, setFile] = useState({});
const [fileGallery, setFileGallery] = useState({});
const { getRootProps:getRootfileProps, getInputProps:getInputfileProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFile(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFileGallery(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
You should use two separate filenames on the state one for hero one for thumbnail and manage each of them for each dropzones
something like this:
const [heroFiles, setHeroFiles] = useState({});
const [filesThumb, setFilesThumb] = useState({});
you are using the Dropzone hook and that will make it difficult to achieve what you are intending to, use the Dropzone component instead and declare state for each Dropzone input you intend to use.
import React, { useState } from "react";
import Container from "../components/Container";
import Dropzone from "react-dropzone";
const Test = () => {
const [heroFiles, setHeroFiles] = useState([]);
const [thumbnailFiles, setThumbnailFiles] = useState([]);
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<Dropzone onDrop={(acceptedFiles) => {
setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}} name="heroImage" multiple={false}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>
Drop hero image here, or click to select file
</span>
</div>
)}
</Dropzone>
{/* This would be the dropzone for the Thumbnail image */}
<Dropzone onDrop={(acceptedFiles) => {
setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}} name="heroImage" multiple={false}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>
Drop hero image here, or click to select file
</span>
</div>
)}
</Dropzone>
{/* This would be where the Hero image is displayed */}
<img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={heroFiles.length > 0 ? heroFiles[0].preview : "https://via.placeholder.com/600x200"} alt="Hero Image"/>
{/* This would be where the Thumbnail image is displayed */}
<img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={thumbnailFiles.length > 0 ? thumbnailFiles[0].preview : "https://via.placeholder.com/600x200"} alt="Thumbnail Image"/>
</Container>
);
}
export default Test;
this is supposed to take care of your issues.

Full screen drag and drop files in React

In this official example of react-dropzone, a full screen drop zone is achieved by wrapping the whole app inside the <Dropzone /> component. I am creating a multi route app and feel that wrapping everything inside the <Dropzone /> component is not a very clean solution.
Is there a way to create a full screen/page drop zone in React without placing the <Dropzone /> component on the root level?
Create a route to a Dropzone form and adjust the height and size of the field by utilizing CSS.
Working example: https://codesandbox.io/s/l77212orwz (this example uses Redux Form, but you don't have to)
container/UploadForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
import ShowForm from "../components/showForm";
class UploadImageForm extends Component {
state = { imageFile: [] };
handleFormSubmit = formProps => {
const fd = new FormData();
fd.append("imageFile", formProps.imageToUpload[0]);
// append any additional Redux form fields
// create an AJAX request here with the created formData
};
handleOnDrop = newImageFile => this.setState({ imageFile: newImageFile });
resetForm = () => {
this.setState({ imageFile: [] });
this.props.reset();
};
render = () => (
<div style={{ padding: 10 }}>
<ShowForm
handleOnDrop={this.handleOnDrop}
resetForm={this.resetForm}
handleFormSubmit={this.handleFormSubmit}
{...this.props}
{...this.state}
/>
</div>
);
}
export default reduxForm({ form: "UploadImageForm" })(UploadImageForm);
components/showForm.js
import isEmpty from "lodash/isEmpty";
import React from "react";
import { Form, Field } from "redux-form";
import DropZoneField from "./dropzoneField";
const imageIsRequired = value => (isEmpty(value) ? "Required" : undefined);
export default ({
handleFormSubmit,
handleOnDrop,
handleSubmit,
imageFile,
pristine,
resetForm,
submitting
}) => (
<Form onSubmit={handleSubmit(handleFormSubmit)}>
<Field
name="imageToUpload"
component={DropZoneField}
type="file"
imagefile={imageFile}
handleOnDrop={handleOnDrop}
validate={[imageIsRequired]}
/>
<button
type="submit"
className="uk-button uk-button-primary uk-button-large"
disabled={submitting}
>
Submit
</button>
<button
type="button"
className="uk-button uk-button-default uk-button-large"
disabled={pristine || submitting}
onClick={resetForm}
style={{ float: "right" }}
>
Clear
</button>
</Form>
);
components/dropzoneField.js
import React, { Fragment } from "react";
import DropZone from "react-dropzone";
import { MdCloudUpload } from "react-icons/md";
import RenderImagePreview from "./renderImagePreview";
export default ({
handleOnDrop,
input,
imagefile,
meta: { error, touched }
}) => (
<div>
<DropZone
accept="image/jpeg, image/png, image/gif, image/bmp"
className="upload-container"
onDrop={handleOnDrop}
onChange={file => input.onChange(file)}
>
<div className="dropzone-container">
<div className="dropzone-area">
{imagefile && imagefile.length > 0 ? (
<RenderImagePreview imagefile={imagefile} />
) : (
<Fragment>
<MdCloudUpload style={{ fontSize: 100, marginBottom: 0 }} />
<p>Click or drag image file to this area to upload.</p>
</Fragment>
)}
</div>
</div>
</DropZone>
{touched && error && <div style={{ color: "red" }}>{error}</div>}
</div>
);
components/renderImagePreview.js
import map from "lodash/map";
import React from "react";
export default ({ imagefile }) =>
map(imagefile, ({ name, preview, size }) => (
<ul key={name}>
<li>
<img src={preview} alt={name} />
</li>
<li style={{ textAlign: "center" }} key="imageDetails">
{name} - {size} bytes
</li>
</ul>
));
styles.css
.dropzone-container {
text-align: center;
background-color: #efebeb;
height: 100%;
width: 100%;
}
.dropzone-area {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.upload-container {
height: 100vh;
width: 100%;
margin-bottom: 10px;
}
ul {
list-style-type: none;
}
p {
margin-top: 0;
}

Resources