Full screen drag and drop files in React - reactjs

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;
}

Related

Passing value of component in separate jsx file's value to event on Full-Calendar

I am new to React. I am trying to pass the value of a select box imported from a separate .jsx file to an event for full-calendar. I can't find anything on this or figure out how to do it for the life of me. This is my component for the select box in a separate file.
import React from 'react'
export const Dropdown = (props) => (
<div className="form-group">
<select
className="form-control"
name="partner"
onChange={props.onChange}
>
<option defaultValue>Select Partner</option>
{props.options.map((item, index) => (
<option key={index} value={item.value}>
{item.label}
</option>
))}
</select>
</div>
)
export default class DropdownList extends React.Component {
constructor() {
super()
this.state = {
list: [],
chosenValue: '',
}
}
componentDidMount() {
fetch('/calendar/users')
.then((response) => response.json())
.then((item) => this.setState({ list: item }))
}
onDropdownChange = (e) => {
this.setState({ chosenValue: e.target.value })
}
render() {
return (
<div className="form-group">
<Dropdown
name="partner"
id="partner"
options={this.state.list}
onDropdownChange={this.onDropdownChange}
/>
</div>
)
}
}
This is my modal that contains the form to pass through as an event to full-calendar
import React, {useState} from "react";
import Modal from "react-modal";
import DateTimePicker from "react-datetime-picker";
import 'bootstrap-icons/font/bootstrap-icons.css'
import DropdownList from "./SelectBox";
export default function ({ isOpen, onClose, onEventAdded }) {
const [title, setTitle] = useState("");
const [start, setStart] = useState(new Date());
const [end, setEnd] = useState(new Date());
const [selectValue] = useState(DropdownList);
const onSubmit = (event) => {
event.preventDefault();
onEventAdded({
title,
start,
partner: selectValue,
end
});
onClose()
};
return (
<Modal isOpen={isOpen}
onClose={onClose}
style={{
overlay: {
backgroundColor: 'rgba(0, 0, 0, 0.5)'
},
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
border: '1px solid #ccc',
background: '#fff',
overflow: 'auto',
WebkitOverflowScrolling: 'touch',
borderRadius: '4px',
outline: 'none',
padding: '20px',
maxWidth: '1200px',
minHeight: '80%',
textAlign: 'center'
}
}}
>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch#4.5.2/dist/lux/bootstrap.min.css" />
<form onSubmit={onSubmit}>
<div className='form-group'>
<input className='form-control' placeholder="Title" value={title} onChange={e => setTitle(e.target.value)} />
</div>
<DropdownList />
<div className='form-group'>
<DateTimePicker name='start' value={start} onChange={date => setStart(date)} />
</div>
<div className='form-group'>
<DateTimePicker name='end' value={end} onChange={date =>setEnd(date)} />
</div>
<button className="btn btn-primary btn-block" type="submit">Add Event</button>
<button className="btn btn-danger btn-block" onClick={onClose}>Cancel</button>
</form>
</Modal>
)
}
I have tried DropdownList.value, redoing the onDropdownChange(e) function in the modal jsx file to no avail. I'm sure this is really simple and I'm getting a headache so thank you for your kindness ahead of time. I'm currently trying to use props but it's all coming up undefined.
Edit: tried to add to component in the modal file
const [partner, setPartner] = useState();
<DropdownList
ref={partnerRef}
onDropdownChange={e => setPartner(this.chosenValue = e.target.value)}
/>

how to change only current component style on hover

I have a requirement where I need to highlight the component on hover
I have two styles defined baseStyle and highlight
<div style={{ background: '#fff' }}>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
</div>
Expected Output:
on hovering any of the component only that component must be highlighted(i.e just need to add highlight css class to it).
but right now all the component is getting highlighted because of toolStyle state. can anyone help me on this by giving some logic.
Here is an example
you can create a small component with the highlight effect
and use it component any number of times and from anywhere
(As I said in comments )
https://codesandbox.io/s/laughing-mclaren-4i8en?file=/src/highlight.js
child.js
import { useState } from "react";
const baseStyle = { color: "black", fontSize: 14 };
const highlight = { color: "red" };
export default function Highlight({ text }) {
const [toolStyle, setToolStyle] = useState(baseStyle);
return (
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={(e) => setToolStyle(baseStyle)}
style={toolStyle}
>
{text}
</div>
);
}
parent.js
import Highlight from "./highlight";
import "./styles.css";
export default function App() {
return (
<div>
<Highlight text="text 1" />
<Highlight text="text 2" />
<Highlight text="text 3" />
</div>
);
}
This is the best way to implement this with code reusability and
less of code duplication
You can do something like this:
export default function App() {
let [hovered, setHovered] = React.useState({ div1: false, div2: false });
return (
<div>
<div
className={hovered.div1 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div1: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div1: false }))}
>
Hello
</div>
<div
className={hovered.div2 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div2: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div2: false }))}
>
Hello
</div>
</div>
);
}
You can move your styles to CSS file and avoid extra complexity:
App.js
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCoffee } from "#fortawesome/free-solid-svg-icons";
import "./App.css";
function App() {
return (
<div className="wrapper">
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
</div>
);
}
export default App;
App.css
.wrapper {
background: #fff;
}
.wrapper > div {
color: red;
font-size: 20px;
}
.wrapper > div:hover {
color: green;
cursor: pointer;
}

using a value through react components

I'm new to React and been struggling with new challenges. Please write me your opinion and help me to get out of this challenge. I need to take the input value and append it in list area. Basically getting that state.inputValue and append it in ul of listArea.
This is InputTask component.
import React from 'react';
class InputTask extends React.Component {
state = { inputValue: ''}
onInputSubmit = (e) => {
this.setState({inputValue: e.target.value})
}
handleSubmit = (e) => {
e.preventDefault();
console.log('A name was submitted: ' + this.state.inputValue);
}
render() {
return (
<form className="ui input" onSubmit={this.handleSubmit} style={{marginRight:10}}>
<input type="text" value={ this.state.inputValue } onChange={this.onInputSubmit}/>
</form>
)
}
}
export default InputTask;
And this is listArea component.
import React from 'react';
class ListArea extends React.Component{
render() {
const style={
backgroundColor: "#f5d556",
height: "400px",
padding: "40px",
borderRadius: "20px"
};
const listStyle = {
backgroundColor: "green",
color: "white",
listStyle: "none",
textAlign: "left",
padding: "5px",
marginBottom: "10px",
borderRadius: "5px"
}
const iconStyle = {
float: "right"
}
const labelStyle = {
color: "white"
}
return(
<div className="ui form" style={{marginBottom:10}}>
<div className="field">
<div style={style}>
<ul style={{paddingLeft: 0}}>
<li style={listStyle}>
<div className="ui checkbox">
<input type="checkbox" name="example"/>
<label style={labelStyle}> hello there!</label>
</div>
<i className="white trash icon" style={iconStyle}></i>
</li>
</ul>
</div>
</div>
</div>
)
}
}
export default ListArea;
this is App component
import React from 'react';
import ReactDOM from 'react-dom';
import InputTask from "./components/inputTask";
import ListArea from "./components/listArea";
class App extends React.Component {
render() {
return (
<div className="ui container" style={{textAlign:'center'}}>
<h1>Tasks</h1>
<ListArea />
<InputTask />
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById('root'));
In InputTask component at handleSubmit with this.props.InputSelected(this.state.inputValue);
I sent back selected input to it's parent(App.js)
import React from "react";
class InputTask extends React.Component {
state = { inputValue: "" };
onInputSubmit = (e) => {
this.setState({ inputValue: e.target.value });
};
handleSubmit = (e) => {
e.preventDefault();
console.log("A name was submitted: " + this.state.inputValue);
this.props.InputSelected(this.state.inputValue);
this.setState({ inputValue: "" });
};
render() {
return (
<form
className="ui input"
onSubmit={this.handleSubmit}
style={{ marginRight: 10 }}
>
<input
type="text"
value={this.state.inputValue}
onChange={this.onInputSubmit}
/>
</form>
);
}
}
export default InputTask;
In App component I got selected value with handleInputSelected and added it to list to send to ListArea component
import React from "react";
import InputTask from "./components/inputTask";
import ListArea from "./components/listArea";
class App extends React.Component {
state = { list: [] };
handleInputSelected = (input) => {
const { list } = { ...this.state };
list.push(input);
this.setState(list);
};
render() {
return (
<div className="ui container" style={{ textAlign: "center" }}>
<h1>Tasks</h1>
<ListArea list={this.state.list} />
<InputTask InputSelected={(input) => this.handleInputSelected(input)} />
</div>
);
}
}
export default App;
And finally in ListArea component with map on list I just append li element to ul.
import React from "react";
class ListArea extends React.Component {
render() {
console.log("data: ", this.props.data);
const style = {
backgroundColor: "#f5d556",
height: "400px",
padding: "40px",
borderRadius: "20px",
overflow: "scroll"
};
const listStyle = {
backgroundColor: "green",
color: "white",
listStyle: "none",
textAlign: "left",
padding: "5px",
marginBottom: "10px",
borderRadius: "5px"
};
const iconStyle = {
float: "right"
};
const labelStyle = {
color: "white"
};
console.log(this.props.data);
return (
<div className="ui form" style={{ marginBottom: 10 }}>
<div className="field">
<div style={style}>
<ul style={{ paddingLeft: 0 }}>
<li style={listStyle}>
<div className="ui checkbox">
<input type="checkbox" name="example" />
<label style={labelStyle}> hello there!</label>
</div>
<i className="white trash icon" style={iconStyle}></i>
</li>
{this.props.list.map((m) => (
<li style={listStyle}>
<div className="ui checkbox">
<input type="checkbox" name="example" />
<label style={labelStyle}> {m}</label>
</div>
<i className="white trash icon" style={iconStyle}></i>
</li>
))}
</ul>
</div>
</div>
</div>
);
}
}
export default ListArea;

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

Why is this.prop not updating?

I have a parent component, that dynamically creates child components, and works great. But as part of that child component, I'm trying to open a modal with a button click, yet the button doesn't work.
To me it seems like that the this.props.lgShow isn't getting the state change. How do I make sure of that?
Here's my parent component:
import React, { Component, Fragment } from 'react';
import Button from 'react-bootstrap/Button';
import Policy from './Policy/Policy';
import PolicyButton from './PolicyButton/PolicyButton';
class Handbook extends Component {
constructor(props){
super(props);
this.state = {
clients: [],
policies: [],
usedPolicies: [],
client: 'Choose Client',
logo: '',
color1: '#000',
color2: '#fff',
lgShow: 'false' // show modal toggle
};
this.modalOpen = this.modalOpen.bind(this);
this.modalClose = this.modalClose.bind(this);
this.modalSave = this.modalSave.bind(this);
}
componentDidMount() {
fetch('/api/themes/all')
.then(res => res.json())
.then((result) => {
this.setState({ clients: result });
console.log(result);
})
.then(
fetch(`/api/policy/all`)
.then(res => res.json())
.then((result) => {
this.setState({ policies: result });
console.log(result);
})
);
}
handleDeletePolicy = policyId => {
console.log(`Button clicked: ` + policyId);
for (var i = 0; i < this.state.usedPolicies.length; i++) {
if (this.state.usedPolicies[i].id === policyId) {
const policies = this.state.policies;
const usedPolicies = this.state.usedPolicies;
policies.push(usedPolicies[i]);
this.setState({ policies: policies });
usedPolicies.splice(i, 1);
this.setState({ usedPolicies: usedPolicies });
console.log(this.state.policies);
console.log(this.state.usedPolicies);
}
}
}
modalOpen = policyId => {
console.log("Open Modal" + policyId);
this.setState({lgShow: true});
}
modalClose = policyId => {
console.log("Close Modal" + policyId);
this.setState({ lgShow: false });
}
modalSave = policyId => {
console.log("Save Modal" + policyId);
this.setState({ lgShow: false });
}
render(){
return(
<Fragment>
<div className='policies'>
{this.state.usedPolicies.map(policy => (
<Policy key={policy.id} id={policy.id} policy={policy.policy} contents={policy.contents} color1={this.state.color1} color2={this.state.color2} onDeletePolicy={this.handleDeletePolicy} onOpen={this.modalOpen} onClose={this.modalClose} onSave={this.modalSave} />
))}
</div>
</Fragment>
);
}
}
export default Handbook;
And here is my child component.. I believe the problem must be here somewhere.
import React, { Component } from 'react';
import styled from 'styled-components';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import TinyEditor from '../../TinyEditor/TinyEditor';
const Div = styled.div `
background-color: white;
color: black;
margin-top: 2em;
.edit{
text-align: right;
svg{
font-size: 1em;
margin: 0.25em;
}
}
.policy{
border: 1px solid black;
padding: 2em;
}
h1{
margin-bottom: 1em;
text-align: left;
padding: .25em;
}
`
class Policy extends Component {
constructor(props){
super(props);
this.state = {
id: this.props.id,
policy: this.props.policy,
contents: this.props.contents,
color1: this.props.color1,
color2: this.props.color2,
lgShow: this.props.lgShow
}
}
render(){
return(
<Div className="container">
<div className="edit">
<Button variant="light" onClick={() => this.props.onOpen(this.props.id)}><i className="far fa-edit"></i></Button>
<Button variant="light" onClick={() => this.props.onDeletePolicy(this.props.id)}><i className="far fa-trash-alt"></i></Button>
</div>
<div className="policy">
<h1 style={{ background: this.props.color1, color: this.props.color2 }}>{this.props.policy}</h1>
<div dangerouslySetInnerHTML={{ __html: this.props.contents }}></div>
</div>
<Modal
size="lg"
show={this.props.lgShow}
onHide={this.props.onClose}
aria-labelledby="modal-title-lg"
>
<Modal.Header closeButton>
<Modal.Title id="modal-title-lg">
Large Modal
</Modal.Title>
</Modal.Header>
<Modal.Body>
<TinyEditor />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.props.onClose}>
Close
</Button>
<Button variant="primary" onClick={this.props.onSave}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</Div>
)
}
}
export default Policy;
I do not see 'lgShow' property in the 'Policy' tag.
<Policy
key={policy.id}
id={policy.id}
policy={policy.policy}
contents={policy.contents}
color1={this.state.color1}
color2={this.state.color2}
onDeletePolicy={this.handleDeletePolicy}
onOpen={this.modalOpen}
onClose={this.modalClose}
onSave={this.modalSave}
/>
In the child element 'Policy' you wrote:
this.state = {
id: this.props.id,
policy: this.props.policy,
contents: this.props.contents,
color1: this.props.color1,
color2: this.props.color2,
lgShow: this.props.lgShow // This one is not in parent element
}

Resources