Cant upload Image with Reactjs Nodejs MongoDb - node.js

I'm trying to upload a image using React for my client side, Node Js as my server and monogoDb for my database. I'm using multer to store the images and everytime I make a request to create an account I get a 500 error. How do I make a post request that includes a Image to a monogoDb database from my React frontend through a Node Js server ?
Frontend
import React, { useState } from "react";
import {useHistory } from "react-router-dom";
import FormData from 'form-data'
import axios from "axios";
const CreateAccount = () => {
const api = "http://localhost:5000/user/create-account";
const history = useHistory();
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [emailAddress, setEmailAddress] = useState("");
const [password, setPassword] = useState("");
const [gender, setGender] = useState("Male");
const [sexualPreference, setSexualPreference] = useState("Straight");
const [age, setAge] = useState("");
const [description, setDescription] = useState("");
const [picture, setPicture] = useState(null);
const [imgData, setImgData] = useState(null);
const account = {
firstName: firstName,
lastName: lastName,
emailAddress: emailAddress,
password: password,
gender: gender,
sexualPreference: sexualPreference,
age: age,
description: description,
pictures: picture
};
const onChangePicture = e => {
if (e.target.files[0]) {
console.log("picture: ", e.target.files);
setPicture(e.target.files[0]);
const reader = new FileReader();
reader.addEventListener("load", () => {
setImgData(reader.result);
});
reader.readAsDataURL(e.target.files[0]);
}
console.log(imgData);
console.log(picture);
};
const submit = () => {
let data = new FormData();
data.append('firstName', firstName);
data.append('lastName', lastName);
data.append('emailAddress', emailAddress);
data.append('password', password);
data.append('gender', gender);
data.append('sexualPreference',sexualPreference);
data.append('age', age);
data.append('description', description);
data.append('pictures',
{
uri: imgData,
name:`${picture}.jpg`,
type:'image/jpg'
});
axios.post(api, account, {
method: "post",
url: api,
data: account,
headers: { "Content-Type": "multipart/form-data" },
})
.then((res) => {
// handle success
console.log(res.data);
history.push({
pathname: "/",
});
})
.catch((error) => {
//handle error
console.log(account);
console.log(error);
});
}
const handleSubmit = (event) => {
event.preventDefault();
submit();
};
return (
<div>
<div>
<h1>Create account</h1>
</div>
<form onSubmit={handleSubmit} encType="multipart/form-data">
<p>First Name</p>
<input
id="firstName"
name="firstName"
type="firstName"
onChange={(e) => setFirstName(e.target.value)}
></input>
<p>Last Name</p>
<input
id="lastName"
name="lastName"
type="lastName"
onChange={(e) => setLastName(e.target.value)}
></input>
<p>Email Address</p>
<input
id="emailAddress"
name="emailAddress"
type="emailAddress"
onChange={(e) => setEmailAddress(e.target.value)}
></input>
<p>Password</p>
<input
id="password"
name="password"
type="password"
onChange={(e) => setPassword(e.target.value)}
></input>
<p>Gender</p>
<select
id="gender"
name="gender"
type="gender"
onChange={(e) => setGender(e.target.value)}
>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
<p>Sexual Preference</p>
<select
id="sexualPreference"
name="sexualPreference"
type="sexualPreference"
onChange={(e) => setSexualPreference(e.target.value)}
>
<option value="Straight" >Straight</option>
<option value="Gay" >Gay</option>
<option value="Lesbian" >Lesbian</option>
<option value="Bisexual" >Bisexual</option>
</select>
<p>Age</p>
<input
id="age"
name="age"
type="age"
onChange={(e) => setAge(e.target.value)}
></input>
<p>Description</p>
<input
id="description"
name="description"
type="description"
onChange={(e) => setDescription(e.target.value)}
></input>
<input
type="file"
name="file"
id="picture"
onChange={onChangePicture}
></input>
<button type="submit">Submit</button>
</form>
</div>
);
};
export default CreateAccount;
Backend
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
cb(null, new Date().toISOString() + file.originalname);
}
})
const upload = multer({storage: storage})
router.post( "/user/create-account", upload.single("pictures"), [
check("firstName")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "firstName"'),
check("lastName")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "username"'),
check("emailAddress")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "emailAddress"'),
check("password")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "password"'),
check("gender")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "gender"'),
check("sexualPreference")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "sexualPreference"'),
check("age")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "age"'),
check("description")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "description"'),
check("pictures")
.exists({ checkNull: true, checkFalsy: true })
.withMessage('Please provide a value for "pictures"'),
],
asyncHandler(async (req, res, next) => {
// Attempt to get the validation result from the Request object.
const errors = validationResult(req);
// If there are validation errors...
if (!errors.isEmpty()) {
// Use the Array `map()` method to get a list of error messages.
const errorMessages = errors.array().map((error) => error.msg);
// Return the validation errors to the client.
return res.status(400).json({ errors: errorMessages });
}
//new user request body using mongo model from schema
const postUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
emailAddress: req.body.emailAddress,
password: req.body.password,
gender: req.body.gender,
sexualPreference: req.body.sexualPreference,
age: req.body.age,
description: req.body.description,
pictures: req.file.path
});
console.log(req.file)
const userEmail = await User.findOne({
emailAddress: postUser.emailAddress,
});
if (postUser.emailAddress === userEmail) {
console.log("User with this email already exists");
return res.status(500).end();
} else if (postUser) {
//if true salts the password with bcryptjs
let salt = await bcryptjs.genSalt(10);
const hashPass = await bcryptjs.hash(postUser.password, salt);
console.log(hashPass);
postUser.password = hashPass;
postUser.save();
res.json({ postUser });
return res.status(201).end();
} else {
res.status(400).send({ error: "Error: Account not created" }).end();
}
})
);
schema
const mongoose = require('mongoose');
const userSchema = mongoose.Schema( {
firstName:{
type: String,
required: true
},
lastName: {
type: String,
require: true
},
emailAddress: {
type: String,
require: true
},
password:{
type: String,
required: true
},
gender:{
type: String,
required: true
},
sexualPreference: {
type: String,
required: true
},
age: {
type: Number,
required: true
},
description: {
type: String,
required: true
},
pictures: {
type: String,
required: true
},
matches: {
type: [{
Object
}],
},
})
module.exports = mongoose.model('User', userSchema);

Related

How do I store data from a dropdown in Mongodb

I am trying to store data from an option, but I'm not sure where I went wrong in the schema or the react code. Is there another I could perhaps do it?
When I run it I get this error.
POST http://localhost:8080/api/user 500 (Internal Server Error)
Here is my model
model.js
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const joi = require('joi');
const { optional } = require('joi');
const userSchema = new mongoose.Schema({
firstName:{type: String, required: true},
lastName:{type: String, required: true},
email:{type: String, required: true},
password:{type: String, required: true},
status:{type: String, enum: ['active', 'inactive'],required : true },
});
userSchema.methods.generateAuthToken = function(){
const token = jwt.sign({_id:this._id}, process.env.JWTPRIVATEKEY)
return token
}
const User = mongoose.model("user", userSchema);
const validate = (data) => {
const schema = joi.object({
firstName:joi.string().required().label("First Name"),
lastName:joi.string().required().label("Last Name"),
email: joi.string().email().required().label("Email"),
password: joi.string().required().label("password"),
status:joi.string().enum['active', 'inactive'].required().label(" ")
});
return schema.validate(data)
}
module.exports = {User, validate}
When I run it I get "error creating user"
routes user.js
const router =require("express").Router();
const {User, validate} = require('../models/user')
const bcrypt = require("bcrypt");
router.post("/", async(req, res) => {
try{
const {error} = validate(req.body)
if(error)
return res.status(400).send({message: error.details[0].message})
const user = await User.findOne({ email:req.body.email})
if (user)
return res.status(409).send({message: "duplicate email"})
const salt = await bcrypt.genSalt(Number(process.env.SALT))
const hashPassword = await bcrypt.hash(req.body.password, salt);
await new User({...req.body, password: hashPassword}).save();
res.status(201).send({message: "User created succesfully"})
}catch(error){
console.log(error.details)
res.status(500).send({message: "Error creating user"})
}
})
module.exports = router;
here are my react.js files, I believe my error should lie here but I maybe be mistaken.
index.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate } from "react-router-dom";
import styles from "./styles.module.css";
const Signup = () => {
const [data, setData] = useState({
firstName: "",
lastName: "",
email: "",
password: "",
status: "",
});
const [error, setError] = useState("");
const navigate = useNavigate();
const handleChange = ({ currentTarget: input }) => {
setData({ ...data, [input.name]: input.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const url = "http://localhost:8080/api/user";
const { data: res } = await axios.post(url, data);
navigate("/login");
console.log(res.message);
} catch (error) {
if (
error.response &&
error.response.status >= 400 &&
error.response.status <= 500
) {
setError(error.response.data.message);
}
}
};
return (
<div className={styles.signup_container}>
<div className={styles.signup_form_container}>
<div className={styles.left}>
<h1>Welcome Back</h1>
<Link to="/login">
<button type="button" className={styles.white_btn}>
Sign in
</button>
</Link>
</div>
<div className={styles.right}>
<form className={styles.form_container} onSubmit={handleSubmit}>
<h1>Create Account</h1>
<input
type="text"
placeholder="First Name"
name="firstName"
onChange={handleChange}
value={data.firstName}
required
className={styles.input}
/>
<input
type="text"
placeholder="Last Name"
name="lastName"
onChange={handleChange}
value={data.lastName}
required
className={styles.input}
/>
<input
type="email"
placeholder="Email"
name="email"
onChange={handleChange}
value={data.email}
required
className={styles.input}
/>
<input
type="password"
placeholder="Password"
name="password"
onChange={handleChange}
value={data.password}
required
className={styles.input}
/>
<select name ="status">
<option value="1">active</option>
<option value="2">inactive</option>
</select>
{error && <div className={styles.error_msg}>{error}</div>}
<button type="submit" className={styles.green_btn}>
Sign Up
</button>
</form>
</div>
</div>
</div>
);
};
export default Signup;

User not existend in the database JWT?

So i have got a slight problem with the user authentication with JWT token. When i Login it returns to me "user doesnt exist", although there's clearly an user in the database. I've tried to fix by not looking for the password in the database and comparing it and it worked, but my question is how can i compare passwords in mongoose database and check if the user exists?
Login route:
//create route for sign in
router.post('/signin', async (req, res) => {
//destructure email and password from req.body
const user = await User.findOne({
email: req.body.email,
password: req.body.password,
})
if (!user) res.status(400).send({ message: 'User doesnt exist' })
else {
const valid = compare(req.body.password, user.password)
if (!valid) res.send(400).send({ message: 'Password doesnt match' })
if (valid) {
const accesstoken = createAccessToken(user._id)
const refreshtoken = createRefreshToken(user._id)
return res.send({
email: user.email,
refreshtoken: user.refreshtoken,
sendAccessToken: sendAccessToken(req, accesstoken),
sendRefreshToken: sendRefreshToken(refreshtoken),
})
}
}
})
user Model:
const mongoose = require('mongoose')
// const SALT_WORK_FACTOR = 10
// const bcrypt = require('bcryptjs')
//how a user will be stored in the mongodb schema
const userSchema = new mongoose.Schema({
name: { type: String, required: true, index: { unique: true } },
email: { type: String, required: true, unique: true, dropDups: true },
password: { type: String, required: true, minlength: 6, trim: true },
isAdmin: { type: Boolean, required: true, default: false },
refreshtoken: { type: String },
})
const userModel = mongoose.model('Users', userSchema)
module.exports = userModel
login page:
import React, { useState, useEffect, useContext } from 'react'
import { userContext } from '../../App'
// import { useDispatch, useSelector } from 'react-redux'
// import { login } from '../../actions/userActions'
function Login(props) {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [user, setUser] = useContext(userContext)
//acces the userLogin from redux store
// const userLogin = useSelector((state) => state.userLogin)
// const { loading, userInfo, error } = userLogin
// const dipsatch = useDispatch()
// useEffect(() => {
// if (userInfo) {
// props.history.push('/')
// }
// }, [userInfo])
//handlesubmit
const handleSubmit = async (e) => {
e.preventDefault()
const result = await (
await fetch('http://localhost:5000/users/signin', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
}),
})
).json()
if (result.accesstoken) {
setUser({
accesstoken: result.accesstoken,
})
window.location = '/'
} else {
alert(result.error)
}
}
useEffect(() => {
console.log(user)
}, [user])
return (
<div>
<h1 className="login-h">Login</h1>
<form onSubmit={handleSubmit} className="login">
<div className="login-form">
<label>email</label>
<br />
<input
type="email"
placeholder="username or email"
for="email"
onChange={(e) => setEmail(e.target.value)}
></input>
<br />
<label>Password</label>
<br />
<input
type="password"
placeholder="Password"
for="password"
onChange={(e) => setPassword(e.target.value)}
></input>
<br />
<p className="forget-pw">
Forgot password?
</p>
<button>Login</button> <br />
<br />
{/* <p style={{ color: 'red' }}>{result.error}</p> */}
</div>
<p className="have-ccl">
{' '}
No account yet?Signup
</p>
</form>
</div>
)
}
export default Login
There are a few problems:
Remove the unnecessary password: req.body.password line from your mongoose query. This is basically comparing unhashed passwords with hashed passwords in a plain JavaScript object. This never returns true because the hash is always different from the unhashed password.
Is it possible that your body is never actually sent? You need to add the name attribute to inputs before they can be parsed. Are you using body-parser?

System validation failed - Node / Express / Mongoose

When I submit my form I get the following error: Error [ValidationError]: System validation failed: lastName: Path lastName is required., firstName: Path firstName is required.
I'm not sure what's causing this, when I console.log(formData) I get the data I submitted into the form.
App.js
const express = require('express')
const app = express();
const mongoose = require('mongoose');
const dotenv = require ('dotenv/config');
const System = require('./models/System');
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/', (req,res) => {
res.render('index.ejs');
});
app.post('/post-feedback', (req, res) => {
const formData = {
firstame: req.body.firstName,
lastname: req.body.lastName,
assetTag: req.body.assetTag
}
const system = new System(formData);
system.save()
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
});
});
Model:
const mongoose = require('mongoose');
var SystemSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
assetTag: {
type: Number,
required: true
}
});
module.exports = mongoose.model('System', SystemSchema);
Form:
<form action="/post-feedback" method="POST">
<div class="form-group">
<label for="firstName">First Name: </label>
<input type="text" class="form-control" id="firstName" name="firstName">
</div>
<div class="form-group">
<label for="lastName">Last Name: </label>
<input type="text" class="form-control" id="lastName" name="lastName">
</div>
<div class="form-group">
<label for="assetNum">Asset Tag: </label>
<input type="text" class="form-control" id="assetTag" name="assetTag">
</div>
<button type="submit" name="submit" class="btn btn-primary">Submit</button>
</form>
The only one reason why you got some error it's because you're typo on your formData. It must be firstName and lastName, make sure it same with your Schema field and then Make Sure your assetTag is a number, because your Schema type is number.
You can try with this code below:
app.post('/post-feedback', (req, res) => {
const formData = {
// you're typo here: firstame
firstName: req.body.firstName,
// you're typo here: lastname
lastName: req.body.lastName,
// must be number
assetTag: parseInt(req.body.assetTag);
}
const system = new System(formData);
system.save()
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
});
});
I hope it can help you.
app.post('/post-feedback', (req, res) => {
const system = new System(req.body);
system.save()
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
});
});
i think above code should be work.

How to query MongoDB database using MongoDB, Express, React, and Node?

I cannot for the life of me figure out how to use a React, Express, Node, and MongoDB together to query the MongoDB database and display that information onto the DOM. My query works when hardcoded in, but when using the front-end text input, it does not work. Here is the code:
React Component:
const { facilities } = this.props.facility;
return(
<Container>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Input
type="text"
name="facilityState"
id="facilityState"
placeholder="Search State"
value={query}
onChange={this.onChange}
/>
</FormGroup>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
> Search </Button>
</Form>
<Button onClick={this.checkReduxState}> Check Redux State </Button>
{ this.props.isAuthenticated ?
<ListGroup>
<TransitionGroup className="facilities-list">
{facilities.map(({_id, name, address, city, state, zip, phone, email}) => (
<CSSTransition key={_id} timeout={500} classNames="fade">
<ListGroupItem>
{ this.props.isAuthenticated ?
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={this.onDeleteClick.bind(this, _id)}
> ×</Button> : null }
<p> {name} </p>
<p> {address} </p>
<p> {city} </p>
<p> {state} </p>
<p> {zip} </p>
<p> {phone} </p>
<p> {email} </p>
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup> : null
}
</Container>
Express Route:
router.get('/query', (req, res) => {
Facility.find({
state: req.body.facilityState
// state: req.query.facilityState
})
.then(facilities => res.json(facilities));
});
Mongoose Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// mongoose.set('useCreateIndex', true);
const FacilitySchema = new Schema({
name: {
type: String,
required: true
},
address: {
type: String,
// text: true,
required: true
},
city: {
type: String,
required: true
},
state: {
type: String,
text: true,
index: true,
required: true
},
zip: {
type: Number,
required: true
},
phone: {
type: Number,
required: true
},
email: {
type: String,
required: true
},
});
// FacilitySchema.index({state: 'text'});
module.exports = Facility = mongoose.model('facility', FacilitySchema);
When I hard code the desired string value in for req.body.facilityState, pressing the submit button on the user interface works. Also, when using Postman this route works. But for some reason, the express req.body(or req.query) and the component aren't communicating with each other like they should. Can anyone help with this?
EDIT
Here is onChange function:
onChange = (e) => {
this.setState({ [e.target.name] : e.target.value })
}
EDIT 2
Here is redux action file query:
export const queryFacilities = () => dispatch => {
dispatch(setFacilitiesLoading());
axios
.get('/api/facilities/query')
.then(res =>
dispatch({
type: QUERY_FACILITIES,
payload: res.data
}))
.catch(err => dispatch(returnErrors(err.response.data, err.response.status)));
}
I fixed the issue by changing my API call from
router.get('/query', (req, res) => {
Facility.find({
state: req.body.facilityState
// state: req.query.facilityState
})
.then(facilities => res.json(facilities));
});
to
router.get('/query/:state', (req, res) => {
Facility.find({
state: req.params.state
})
.then(facilities => res.json(facilities));
});
and also changing my Redux action from
export const queryFacilities = () => dispatch => {
dispatch(setFacilitiesLoading());
axios
.get('/api/facilities/query')
.then(res =>
dispatch({
type: QUERY_FACILITIES,
payload: res.data
}))
.catch(err => dispatch(returnErrors(err.response.data, err.response.status)));
}
to
export const queryFacilities = (state) => (dispatch, getState) => {
dispatch(setFacilitiesLoading());
axios
.get(`/api/facilities/query/${state}`)
.then(res =>
dispatch({
type: QUERY_FACILITIES,
payload: res.data
}))
.catch(err => dispatch(returnErrors(err.response.data, err.response.status)));
}
So essentially I was able to pass my input through to the API by using req.params, not by using req.body.

How can I apply a state with only 1extra nested state to MongoDB

I'm trying to get the input value to mongoDB while my password is being hashed.
But my password in my scheme is inside an object (localProvider). (This is only for educational only, this is what my teacher coded)
{
username: {
type: String,
required: false,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
match: /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/,
},
localProvider: {
password: {
type: String,
required: false,
},
},
facebookProvider: {
id: { type: String, required: false },
token: { type: String, required: false },
},
published_at: { type: Date, required: false },
deleted_at: { type: Date, required: false },
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
{
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
},
);
UserSchema.methods.slugify = function () {
this.slug = slug(this.email);
};
UserSchema.pre('validate', function (next) {
if (!this.slug) {
this.slugify();
}
return next();
});
UserSchema.pre('save', function (next) {
const user = this;
if (!user.isModified('localProvider.password')) return next();// only hash the password if it has been modified (or is new)
try {
return bcrypt.genSalt(config.auth.bcrypt.SALT_WORK_FACTOR, (errSalt, salt) => {
if (errSalt) throw errSalt;
return bcrypt.hash(user.localProvider.password, salt, (errHash, hash) => {
if (errHash) throw errHash;
user.localProvider.password = hash;
return next();
});
});
} catch (error) {
return next(error);
}
});
UserSchema.methods.comparePassword = function (candidatePassword, cb) {
const user = this;
bcrypt.compare(candidatePassword, user.localProvider.password, (err, isMatch) => {
if (err) return cb(err, null);
return cb(null, isMatch);
});
};
UserSchema.virtual('id').get(function () { return this._id; });
UserSchema.plugin(mongoosePaginate);
export default mongoose.model('User', UserSchema);
I've tried in the register.js passing my input values with onChange
[event.target.name]: event.target.value
Only this line of code works only for the single values not inside an object.
As you've seen in the scheme there's no way, so far I know, to pass value to a single state value and to a nested state value.
So is there a solution to fix the code so I'm able to push also the username & email to the state and push the password to localProvider in 1 handleChange?
code from my register.js
class Signup extends Component {
constructor() {
super()
this.state = {
username: '',
email: '',
redirectTo: null,
localProvider:{
password: ''
}
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleInputChange(event, value){
this.setState({
[event.target.name]: event.target.value
})
}
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let statusCopy = Object.assign({}, this.state);
statusCopy.localProvider[inputName].value = inputValue;
this.setState(statusCopy);
}
handleSubmit(event) {
console.log('sign-up handleSubmit, username: ')
console.log(this.state.username)
event.preventDefault()
//request to server to add a new username/password
axios.post('/api/v1/users/', {
...this.state
})
.then(response => {
console.log(response)
if (!response.data.errmsg) {
console.log('successful signup')
this.props.history.push("/");
} else {
console.log('username already taken')
}
}).catch(error => {
console.log('signup error: ')
console.log(error)
})
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form}>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="name">Name</InputLabel>
<Input name="username" type="text" id="username" autoComplete="username" onChange={this.handleInputChange} />
</FormControl>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="email">Email Address</InputLabel>
<Input id="email" name="email" autoComplete="email" onChange={this.handleInputChange} />
</FormControl>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="password">Password</InputLabel>
<Input type="password" id="password" autoComplete="current-password" onChange={this.handleChange} name="password"/>
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
>
Sign in
</Button>
</form>
</Paper>
</React.Fragment>
)
}
}
export default withStyles(styles)(Signup);```
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let providerCopy = Object.assign({}, this.state.localProvider); // new
let statusCopy = Object.assign({}, this.state, {localProvider: providerCopy}); //edited
statusCopy.localProvider[inputName].value = inputValue;
this.setState(statusCopy);
}
Object.assign() only copies to one level deep and you need to deep copy for 2 levels, so you can use it twice or use the spread operator over an object also works.
let nextState = {...this.state, localProvider: {...this.state.localProvider, [el.target.name]: [el.target.value] } };
this.setState(nextState);
Look here for more information on nested state changes.

Resources