Unit testing a registration component with enzyme and jest - reactjs

I am trying to unit test my registration component
const Register = () => {
const dispatch = useDispatch();
const currentUser = useSelector((state: RootState) => state.user.currentUser);
const errors = useSelector((state: RootState) => state.user.error);
const loading = useSelector((state: RootState) => state.user.loading);
const history = useHistory();
const [email, setEmail] = useState<UseState>({ text: "", touched: false });
const [firstName, setFirstName] = useState<UseState>({
text: "",
touched: false,
});
const [lastName, setLastName] = useState<UseState>({
text: "",
touched: false,
});
const [password, setPassword] = useState<UseState>({
text: "",
touched: false,
isValid: null,
});
const [confirmPassword, setConfirmPassword] = useState<UseState>({
text: "",
touched: false,
isValid: null,
});
const [error, setError] = useState<string>("");
useEffect(() => {
//cleanup
return () => {
dispatch(clearError());
};
//eslint-disable-next-line
}, []);
useEffect(() => {
if (currentUser && currentUser.jwt) {
setEmail({ text: "", touched: false });
setFirstName({ text: "", touched: false });
setLastName({ text: "", touched: false });
setPassword({ text: "", touched: false });
setConfirmPassword({ text: "", touched: false });
}
// eslint-disable-next-line
}, [currentUser]);
const handleRegister = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (
password.text === confirmPassword.text &&
password.isValid &&
confirmPassword.isValid
) {
dispatch(
signUpStart({
email: email.text,
firstName: firstName.text,
lastName: lastName.text,
password: password.text,
confirmPassword: confirmPassword.text,
})
);
} else {
if (errors) {
// cleanup
return () => {
dispatch(clearError());
};
}
setError("Different passwords");
}
};
return (
<section className={styles.register__page}>
{loading && <Loading />}
<article className={styles.register__wrapper}>
<div className={styles.register__wrapper__header}>
<h1>Sign-up</h1>
<p>
Text
</p>
</div>
<div className={styles.register__wrapper__body}>
<form
onSubmit={(e) => handleRegister(e)}
className={styles.register__form}
>
<div className={styles.input__wrapper}>
<FontAwesomeIcon icon={faUser} />
<div className={styles.input__wrapper__inner}>
<input
required
type="email"
name="email"
id="email"
value={email.text}
onChange={(e) =>
setEmail({ text: e.target.value, touched: true })
}
/>
<label
htmlFor="email"
placeholder="E-mail"
className={email.text !== "" ? styles.filled : undefined}
>
E-mail
</label>
</div>
</div>
<div className={styles.input__wrapper}>
<FontAwesomeIcon icon={faUser} />
<div className={styles.input__wrapper__inner}>
<input
type="text"
name="firstname"
id="firstname"
value={firstName.text}
onChange={(e) =>
setFirstName({ text: e.target.value, touched: true })
}
/>
<label
htmlFor="firstname"
className={firstName.text !== "" ? styles.filled : undefined}
>
Name
</label>
</div>
</div>
<div className={styles.input__wrapper}>
<FontAwesomeIcon icon={faUser} />
<div className={styles.input__wrapper__inner}>
<input
type="text"
name="lastname"
id="lastname"
value={lastName.text}
onChange={(e) =>
setLastName({ text: e.target.value, touched: true })
}
/>
<label
htmlFor="lastname"
className={lastName.text !== "" ? styles.filled : undefined}
>
Surname
</label>
</div>
</div>
<div
className={[
styles.input__wrapper,
!password.isValid && password.touched
? styles.wrong
: styles.input__wrapper,
].join(" ")}
>
<FontAwesomeIcon icon={faKey} />
{!password.isValid && password.touched && (
<FontAwesomeIcon
icon={faExclamationCircle}
className={styles.errorIcon}
/>
)}
<div className={styles.input__wrapper__inner}>
<input
required
type="password"
name="password"
id="password"
value={password.text}
onChange={(e) => validateOnChange(e)}
/>
<label
htmlFor="password"
className={password.text !== "" ? styles.filled : undefined}
>
Hasło
</label>
</div>
</div>
<div
className={[
styles.input__wrapper,
!confirmPassword.isValid && confirmPassword.touched
? styles.wrong
: styles.input__wrapper,
].join(" ")}
>
<FontAwesomeIcon icon={faKey} />
{!confirmPassword.isValid && confirmPassword.touched && (
<FontAwesomeIcon
icon={faExclamationCircle}
className={styles.errorIcon}
/>
)}
<div className={styles.input__wrapper__inner}>
<input
required
type="password"
name="confirmPassword"
id="confirmPassword"
value={confirmPassword.text}
onChange={(e) => validateOnChange(e)}
/>
<label
htmlFor="confirmPassword"
className={
confirmPassword.text !== "" ? styles.filled : undefined
}
>
Confirm password
</label>
</div>
</div>
<button type="submit" className={styles.register__btn}>
Rejestruj
</button>
{errors && <p className={styles.error}>{errors}</p>}
{error !== "" && <p className={styles.error}>{error}</p>}
</form>
<p className={styles.login__link}>
Text
</p>
</div>
</article>
</section>
);
};
export default Register;
I tried several different approaches, however, none of them have worked for me so far. I ended up with something like that:
describe("Register /", () => {
it('register with proper credentials', () => {
const history = createMemoryHistory();
const component = mount(<Provider store={store}><Router history={history}><Register /></Router></Provider>);
component.find('input[name="firstname"]').simulate('change', {target: {name: 'firstname', value: 'Test'}});
component.find('input[name="lastname"]').simulate('change', {target: {name: 'lastname', value: 'Test'}});
component.find('input[name="password"]').simulate('change', {target: {name: 'password', value: 'TestSecret'}});
component.find('input[name="email"]').simulate('change', {target: {name: 'email', value: 'test#test.com'}});
})
After that I wanted to assert if the fields are filled in correctly and if the handleRegister is called but the fields are returning an empty string ("{}") and that's where I got stuck. What am I doing wrong?

Related

I cannot understand how setValue is working in init() which used in useEffect?

I know that useEffect( without any dependencies) only work on Mount So how state updates by setValues in init() here??
I am beginner in mern stack so please if you wnat any info please comment
//Code snippet
const init = () => {
getCategories().then(data => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
categories: data,
formData: new FormData()
});
}
});
};
useEffect(() => {
init();
}, []);
//full code for help
import React, { useState, useEffect } from 'react';
import Layout from '../core/Layout';
import { isAuthenticated } from '../auth';
import { Link } from 'react-router-dom';
import { createProduct, getCategories } from './apiAdmin';
const AddProduct = () => {
const [values, setValues] = useState({
name: '',
description: '',
price: '',
categories: [],
category: '',
shipping: '',
quantity: '',
photo: '',
loading: false,
error: '',
createdProduct: '',
redirectToProfile: false,
formData: ''
});
const { user, token } = isAuthenticated();
const {
name,
description,
price,
categories,
category,
shipping,
quantity,
loading,
error,
createdProduct,
redirectToProfile,
formData
} = values;
// load categories and set form data
const init = () => {
getCategories().then(data => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
categories: data,
formData: new FormData()
});
}
});
};
useEffect(() => {
init();
}, []);
const handleChange = name => event => {
const value = name === 'photo' ? event.target.files[0] : event.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value });
};
const clickSubmit = event => {
event.preventDefault();
setValues({ ...values, error: '', loading: true });
createProduct(user._id, token, formData).then(data => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
name: '',
description: '',
photo: '',
price: '',
quantity: '',
loading: false,
createdProduct: data.name
});
}
});
};
const newPostForm = () => (
<form className="mb-3" onSubmit={clickSubmit}>
<h4>Post Photo</h4>
<div className="form-group">
<label className="btn btn-secondary">
<input onChange={handleChange('photo')} type="file" name="photo" accept="image/*" />
</label>
</div>
<div className="form-group">
<label className="text-muted">Name</label>
<input onChange={handleChange('name')} type="text" className="form-control" value={name} />
</div>
<div className="form-group">
<label className="text-muted">Description</label>
<textarea onChange={handleChange('description')} className="form-control" value={description} />
</div>
<div className="form-group">
<label className="text-muted">Price</label>
<input onChange={handleChange('price')} type="number" className="form-control" value={price} />
</div>
<div className="form-group">
<label className="text-muted">Category</label>
<select onChange={handleChange('category')} className="form-control">
<option>Please select</option>
{categories &&
categories.map((c, i) => (
<option key={i} value={c._id}>
{c.name}
</option>
))}
</select>
</div>
<div className="form-group">
<label className="text-muted">Shipping</label>
<select onChange={handleChange('shipping')} className="form-control">
<option>Please select</option>
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</div>
<div className="form-group">
<label className="text-muted">Quantity</label>
<input onChange={handleChange('quantity')} type="number" className="form-control" value={quantity} />
</div>
<button className="btn btn-outline-primary">Create Product</button>
</form>
);
const showError = () => (
<div className="alert alert-danger" style={{ display: error ? '' : 'none' }}>
{error}
</div>
);
const showSuccess = () => (
<div className="alert alert-info" style={{ display: createdProduct ? '' : 'none' }}>
<h2>{`${createdProduct}`} is created!</h2>
</div>
);
const showLoading = () =>
loading && (
<div className="alert alert-success">
<h2>Loading...</h2>
</div>
);
return (
<Layout title="Add a new product" description={`G'day ${user.name}, ready to add a new product?`}>
<div className="row">
<div className="col-md-8 offset-md-2">
{showLoading()}
{showSuccess()}
{showError()}
{newPostForm()}
</div>
</div>
</Layout>
);
};
export default AddProduct
You're right that the useEffect without any dependencies will run once on mount. So that means that the function init() is gonna be called at least once on mount, right? So whatever action you have in your init function will be called once. You don't need dependencies in order to set a state.

Diffrent Input type using Bootstrap desing in Redux-React functional componnent

Im trying to display my data in diffrent Form inputs, but in some of them, i dont know how to reach my data.
//DashShowDetails.js:
import { useState, useEffect } from 'react';
import { Button, Form } from 'react-bootstrap';
import { Input, Label } from 'reactstrap';
function DashShowDetails(props) {
const { data } = props;
const [edit, setEdit] = useState(false);
const [formData, setFormData] = useState({
id: data._id,
showId: data.showId,
showName: data.name,
showGenres: data.genres,
showStatus: data.status,
showPremiered: data.premiered,
showEnded: data.ended,
showRating: data.rating,
showSummery: data.summary,
showImage: data.image,
});
const onClick = () => {
setEdit(current => !current)
}
const onChange = (e) => {
setFormData((prevState) => ({
...prevState,
[e.target.name]: e.target.value
}))
}
const onSubmit = async (e) => {
e.preventDefault()
let show = formData;
dispatch(updateDashShow(show));
setEdit(current => !current);
setFormData((prevState) => ({
...prevState,
}))
}
useEffect(() => {
}, [edit]);
return (
<div>
<div>
<h5>{data.name}</h5>
<Button onClick={onClick}>Edit Show</Button>
</div>
<div>
{edit === true && (
<div>
<h3>Edit {data.name}</h3>
<Form onSubmit={onSubmit} >
<div>
<Label>Show ID:</Label>
<Input type="text" name="showId" value={data.showId} onChange={onChange} />
</div>
<div>
<Label>Show Name:</Label>
<Input type="text" name="showName" defaultValue={data.name} onChange={onChange} />
</div>
<div>
<Label>Show Genres:</Label>
<Input type="text" name="showGenres" defaultValue={data.genres} onChange={onChange} />
</div>
<div>
<Label>Show Status:</Label>
<Input type="select" name="showStatus" select={data.status} onChange={onChange}>
<option value="running">Running</option>
<option value="ended">Ended</option>
</Input>
</div>
<div>
<Label>Premiered Date:</Label>
<Input type="date" name="showPremiered" value={data.premiered} onChange={onChange} />
</div>
<div>
<Label>Ended Date:</Label>
<Input type="date" name="showEnded" value={data.ended} onChange={onChange} />
</div>
<div>
<Label>Show Rating:</Label>
<Input type="array" name="showRating" value={data.rating} onChange={onChange} />
</div>
<div>
<Label>Show Summery:</Label>
<Input type="textarea" name="showSummery" value={data.summery} onChange={onChange} />
</div>
<div>
<Label>Image:</Label>
</div>
<Button type="submit">Update Show</Button>
<Button>Delete Show</Button>
</Form>
</div>
)}
</div>
</div>
);
}
export default DashShowDetails;
My output when i click 'Edit Show' is:
How can i display my Data in inputs: Premiered Date, Show Rating, Show Summery & Image?
My Schema file in Node.js: (sending new data to MoongoDB)
const showSchema = new mongoose.Schema({
showId: {type: Number},
name: {type: String},
genres: {type: Array},
status: {type: String},//Boolean
premiered: {type: Date},
ended: {type: Date},
rating: {type: Array},
summary: {type: String},
image: {type: Array},//Link?File?
})
module.exports = mongoose.model('shows', showSchema);

needing page to pull just one user based on ID for editing but get them all

This is my edit user page and I would like it to pull one user at a time for editing.
When you click the pencil to edit I would like just the one user pulled but instead I get all of them like in the second image.
in the code below I map them out but have tried using filter and a reducer but no fix has worked as of yet. would an inline condition be better like the one below but have not figured how to get the right ID from the URL.
{Collectors.CollectorID === Collectors.CollectorID && <div><h2>1-30 days past due in Tandem – all credit types</h2> <p>{Collectors.CollectorCode}{Collectors.FinanceCompany}</p></div>}
import React from "react";
import axios from 'axios';
class UpdateUser extends React.Component {
constructor(props) {
super(props);
this.state = {
collectorList: [],
CollectorID: props.CollectorID,
ProgramBucketID: props.ProgramBucketID,
CollectorOptionsID: props.CollectorOptionsID,
FinanceCompanyID: props.FinanceCompanyID,
Active: '',
LastName: '',
CollectorCode: '',
Aging1to15: '',
Aging31to45: '',
Aging31to60: '',
AgingOver60: '',
ProgramBucketA: '',
ProgramBucketB: '',
ProgramBucketC: '',
ProgramBucketSU: '',
FinanceCompany: ''
}
this.handleActiveChange = this.handleActiveChange.bind(this);
this.handleAging115Change = this.handleAging115Change.bind(this);
this.handleAging3145Change = this.handleAging3145Change.bind(this);
this.handleAging3160Change = this.handleAging3160Change.bind(this);
this.handleAgingOver60Change = this.handleAgingOver60Change.bind(this);
this.handleProgramAChange = this.handleProgramAChange.bind(this);
this.handleProgramBChange = this.handleProgramBChange.bind(this);
this.handleProgramCChange = this.handleProgramCChange.bind(this);
this.handleProgramSUChange = this.handleProgramSUChange.bind(this);
}
componentDidMount(e) {
this.getCollectors()
}
handleActiveChange(e) {
this.setState({
Active: !this.state.Active
})
}
handleAging115Change() {
this.setState({
Aging1to15: !this.state.Aging1to15
})
}
handleAging3145Change() {
this.setState({
Aging31to45: !this.state.Aging31to45
})
}
handleAging3160Change() {
this.setState({
Aging31to60: !this.state.Aging31to60
})
}
handleAgingOver60Change() {
this.setState({
AgingOver60: !this.state.AgingOver60
})
}
handleProgramAChange() {
this.setState({
ProgramBucketA: !this.state.ProgramBucketA
})
}
handleProgramBChange() {
this.setState({
ProgramBucketB: !this.state.ProgramBucketB
})
}
handleProgramCChange() {
this.setState({
ProgramBucketC: !this.state.ProgramBucketC
})
}
handleProgramSUChange() {
this.setState({
ProgramBucketSU: !this.state.ProgramBucketSU
})
}
getCollectors = () => {
axios.get(`http://localhost:5000/getCollectors`)
.then((result) => result.data)
.then((result) => {
this.setState({collectorList: result});
});
};
onUpdateClick = CollectorID => {
axios.put(`http://localhost:5000/UpdateUser/${CollectorID}`, {
CollectorID: this.state.CollectorID,
CollectorOptionsID: this.state.CollectorOptionsID,
ProgramBucketID: this.state.ProgramBucketID,
FinanceCompanyID: this.state.FinanceCompanyID,
Active: this.state.Active,
LastName: this.state.LastName,
CollectorCode: this.state.CollectorCode,
Aging1to15: this.state.Aging1to15,
Aging31to45: this.state.Aging31to45,
Aging31to60: this.state.Aging31to60,
AgingOver60: this.state.AgingOver60,
ProgramBucketA: this.state.ProgramBucketA,
ProgramBucketB: this.state.ProgramBucketB,
ProgramBucketC: this.state.ProgramBucketC,
ProgramBucketSU: this.state.ProgramBucketSU,
FinanceCompany: this.state.FinanceCompany
});
};
render() {
// console.log(this.state);
return (
<div>
<h1>Update Collectors</h1>
<div className="wrapper">
{this.state.collectorList.map((Collectors) => (
<form className="updateUserForm" key={Collectors.CollectorID}>
<div className="updateUserItem">
<b>{Collectors.FirstName} {Collectors.LastName} | {Collectors.CollectorCode}</b>
{/*Active or inactive User*/}
<label>Active Status</label>
<input
type='checkbox'
name="Active"
value={this.state.Active}
defaultChecked={Collectors.Active === false ? false : true}
onChange={this.handleActiveChange}
/>
{/*Collector Last Name*/}
<label>Last Name</label>
<input
type="text"
name="LastName"
defaultValue={Collectors.LastName}
onChange={e => this.setState({
LastName: e.target.value
})}
/>
{/*Collector Code First Initial Middle Initial Last Initial*/}
<label>Collector Code</label>
<input
type="text"
name="CollectorCode"
defaultValue={Collectors.CollectorCode}
onChange={e => this.setState({
CollectorCode: e.target.value
})}
/>
{/*Aging Bucket selection section */}
<label>Aging Bucket</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>1-15<br/>
<input
type='checkbox'
className='AgingBucketCheckbox'
value={this.state.Aging1to15}
defaultChecked={Collectors.Aging1to15 === false ? false : true}
onChange={this.handleAging115Change}
/></label>
<label className='newUserCheckboxLabel'>31-45<br/>
<input
type='checkbox'
className='AgingBucketCheckbox'
value={this.state.Aging31to45}
defaultChecked={Collectors.Aging31to45 === false ? false : true}
onChange={this.handleAging3145Change}
/></label>
<label className='newUserCheckboxLabel'>31-60<br/>
<input
type='checkbox'
className='AgingBucketCheckboxsm'
value={this.state.Aging31to60}
defaultChecked={Collectors.Aging31to60 === false ? false : true}
onChange={this.handleAging3160Change}
/></label>
<label className='newUserCheckboxLabel'>Over 60<br/>
<input
type='checkbox'
className='AgingBucketCheckboxlg'
value={this.state.AgingOver60}
defaultChecked={Collectors.AgingOver60 === false ? false : true}
onChange={this.handleAgingOver60Change}
/></label>
</div>
{/*Progam code selection section*/}
<label>Program Bucket</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>A<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketA}
defaultChecked={Collectors.ProgramBucketA === false ? false : true}
onChange={this.handleProgramAChange}
/></label>
<label className='newUserCheckboxLabel'>B<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketB}
defaultChecked={Collectors.ProgramBucketB === false ? false : true}
onChange={this.handleProgramBChange}
/></label>
<label className='newUserCheckboxLabel'>C<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketC}
defaultChecked={Collectors.ProgramBucketC === false ? false : true}
onChange={this.handleProgramCChange}
/></label>
<label className='newUserCheckboxLabel'>SU<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketSU}
defaultChecked={Collectors.ProgramBucketSU === false ? false : true}
onChange={this.handleProgramSUChange}
/></label>
</div>
{/*Finance Company selection section*/}
<label>Finance Company</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>
<input
type="text"
name="FinanceCompany"
defaultValue={Collectors.FinanceCompany}
onChange={e => this.setState({
FinanceCompany: e.target.value
})}
/></label>
</div>
<button className="updateUserButton" onClick={() => this.onUpdateClick(Collectors.CollectorID) }>Update User</button>
</div>
</form>
))}
</div>
</div>
);
}
}
export default UpdateUser;
After going through some tests I found the below code works wonderfully if anyone is having this issue.
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useParams } from "react-router-dom";
const UpdateUser = () => {
const { CollectorID } = useParams();
const [user, setUser] = useState({
Active: '',
FirstName: '',
LastName: '',
CollectorCode: ''
});
const { Active, FirstName, LastName, CollectorCode } = undefined || user;
const onInputChange = e => {
setUser({
...user, [e.target.name]: e.target.value,
Active: !Active });
};
useEffect(() => {
loadUser();
}, []);// eslint-disable-line react-hooks/exhaustive-deps
const loadUser = async () => {
const result = await axios.get(`http://localhost:5000/getCollectors/${CollectorID}`);
setUser(result.data[CollectorID - 1]);
// console.log(result.data[CollectorID - 1]);
};
const onSubmit = async e => {
e.preventDefault();
await axios.put(`http://localhost:5000/UpdateUser/${CollectorID}`, {
CollectorID: CollectorID,
Active: Active,
LastName: LastName,
CollectorCode: CollectorCode
});
console.log(CollectorID, Active, LastName, CollectorCode)
};
return (
<div className="previewWrapper">
<h1>Update Collector</h1>
{FirstName} {LastName} | {CollectorCode} - {CollectorID} {console.log(user)}
<form className="newUserForm" onSubmit={e => onSubmit(e)}>
<div className="newUserItem">
{/*Active or inactive User*/}
<label>Active</label>
<input
type='checkbox'
defaultValue={Active}
defaultChecked={Active}
onChange={e => onInputChange(e)}
/>
{/*Collector Last Name*/}
<label>Last Name</label>
<input
type="text"
placeholder="Last Name"
name="LastName"
defaultValue={LastName}
onChange={e => onInputChange(e)}
/>
{/*Collector Code First Initial Middle Initial Last Initial*/}
<label>Collector Code</label>
<input
type="text"
name="CollectorCode"
placeholder="Collector Code"
defaultValue={CollectorCode}
onChange={e => onInputChange(e)}
/>
<button className="newUserButton">Update Collector</button>
</div>
</form>
</div>
);
}
export default UpdateUser;

How can I get radio button value in React?

I have three radio buttons and I need to put the value of the selected one in inputs.reply, just like I did with inputs.name, inputs.email, inputs.phone and inputs.message. How can I do this? I know it's probably a very easy thing to do, but I've been trying for hours and it doesn't work.
import Head from 'next/head'
import React, { useState } from 'react'
export default () => {
const [status, setStatus] = useState({
submitted: false,
submitting: false,
info: { error: false, msg: null }
})
const [inputs, setInputs] = useState({
reply: '',
name: '',
phone: '',
email: '',
message: ''
})
function SubmitButton(){
if (inputs.name && inputs.email && inputs.message) {
return <button type="submit" className="btn-submit" disabled={status.submitting}> {!status.submitting ? !status.submitted ? 'Submit' : 'Submitted' : 'Submitting...'} </button>
} else {
return <button type="submit" className="btn-submit" disabled>Submit</button>
};
};
const handleResponse = (status, msg) => {
if (status === 200) {
setStatus({
submitted: true,
submitting: false,
info: { error: false, msg: msg }
})
setInputs({
reply: '',
name: '',
phone: '',
email: '',
message: ''
})
} else {
setStatus({
info: { error: true, msg: msg }
})
}
}
const handleOnChange = e => {
e.persist()
setInputs(prev => ({
...prev,
[e.target.id]: e.target.value
}))
setStatus({
submitted: false,
submitting: false,
info: { error: false, msg: null }
})
}
const handleOnSubmit = async e => {
e.preventDefault()
setStatus(prevStatus => ({ ...prevStatus, submitting: true }))
const res = await fetch('/api/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(inputs)
})
const text = await res.text()
handleResponse(res.status, text)
}
return (
<div className="contact">
<main>
<div className="content">
<div>
<h2>Get in touch!</h2>
<h3>How can we help you?</h3>
</div>
<form onSubmit={handleOnSubmit}>
<h4>How would you like us to get back to you?</h4>
<div className="form-group form-group-radio">
<div>
<input type="radio" onChange={handleOnChange} value="Phone" name="email-reply" id="reply-phone" />
<label className="radio-label" htmlFor="reply-phone">Phone</label>
</div>
<div>
<input type="radio" onChange={handleOnChange} value="E-mail" name="email-reply" id="reply-email" />
<label className="radio-label" htmlFor="reply-email">E-mail</label>
</div>
<div>
<input type="radio" onChange={handleOnChange} value="No reply needed" name="email-reply" id="no-reply" />
<label className="radio-label" htmlFor="no-reply">No reply needed</label>
</div>
</div>
<div className="form-group">
<input
id="name"
type="text"
name="name"
onChange={handleOnChange}
required
value={inputs.name}
className={inputs.name ? "form-control active" : "form-control"}
/>
<label className="form-label" htmlFor="name">Name</label>
</div>
<div className="form-group">
<input
id="email"
type="text"
name="email"
onChange={handleOnChange}
required
value={inputs.email}
className={inputs.email ? "form-control active" : "form-control"}
/>
<label className="form-label" htmlFor="email">Email</label>
</div>
<div className="form-group">
<input
id="phone"
type="tel"
name="phone"
onChange={handleOnChange}
required
value={inputs.phone}
className={inputs.phone ? "form-control active" : "form-control"}
/>
<label className="form-label" htmlFor="phone">Phone</label>
</div>
<div className="form-group">
<textarea
id="message"
onChange={handleOnChange}
required
value={inputs.message}
className={inputs.message ? "form-control active" : "form-control"}
/>
<label className="form-label" htmlFor="message">Message</label>
</div>
<SubmitButton />
{status.info.error && (
<div className="message-feedback error">
<p>Error: {status.info.msg}</p>
</div>
)}
{!status.info.error && status.info.msg && (
<div className="message-feedback success">
<p>Thanks for messaging us!</p>
<p>We'll get back to you soon.</p>
</div>
)}
</form>
</div>
</main>
</div>
)
}
Thank you.
Remove the id attribute from all of the <input type="radio" /> and instead add a name="reply" to all of them.
Now update handleOnChange, specifically this part
setInputs(prev => ({
...prev,
[e.target.id || e.target.name]: e.target.value
}))
You can update the handleOnChange method to check for the type of the target event and if its a radio button, you can update the radio state, otherwise use the dynamic key to update the state.
const handleOnChange = (e) => {
e.persist();
const key = e.target.type === "radio" ? "reply" : e.target.id;
setInputs((prev) => ({
...prev,
[key]: e.target.value
}));
setStatus({
submitted: false,
submitting: false,
info: { error: false, msg: null }
});
};

why am i getting undefined for match object in react.js

The below code is to update a product in admin panel. I have manage to do everything except that on a button pressed for update i want to fetch the url from the above address bar. I thought of using match.params.productId. Here produtId is what i wanted ti get. But i dont know why the match object returns undefined..PLease help me to get rid of this.
import React, { useState, useEffect } from "react";
import Base from "../core/Base";
import { Link } from "react-router-dom";
import {
getAllCategories,
getProduct,
updateProduct
} from "./helper/adminapicall";
import { isAuthenticated } from "../auth/helper/index";
const UpdateProduct = ({ match }) => {
const { user, token } = isAuthenticated();
const [values, setValues] = useState({
name: "",
description: "",
price: "",
stock: "",
photo: "",
categories: [],
category: "",
loading: false,
error: "",
createdProduct: "",
getaRedirect: false,
formData: ""
});
const {
name,
description,
price,
stock,
categories,
category,
loading,
error,
createdProduct,
getaRedirect,
formData
} = values;
const preload = (productId) => {
getProduct(productId).then((data) => {
console.log(data);
if (data.error) {
setValues({ ...values, error: data.error });
} else {
preloadCategories();
setValues({
...values,
name: data.name,
description: data.description,
price: data.price,
category: data.category._id,
stock: data.stock,
formData: new FormData()
});
}
});
};
const preloadCategories = () => {
getAllCategories().then((data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
categories: data,
formData: new FormData()
});
}
});
};
useEffect(() => {
//console.log(match);
preload(match.params.productId);
}, []);
//TODO: work on it
const onSubmit = (event) => {
event.preventDefault();
setValues({ ...values, error: "", loading: true });
updateProduct(match.params.productId, user._id, token, formData).then(
(data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
name: "",
description: "",
price: "",
photo: "",
stock: "",
loading: false,
createdProduct: data.name
});
}
}
);
};
const handleChange = (name) => (event) => {
const value = name === "photo" ? event.target.files[0] : event.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value });
};
const successMessage = () => (
<div
className="alert alert-success mt-3"
style={{ display: createdProduct ? "" : "none" }}
>
<h4>{createdProduct} updated successfully</h4>
</div>
);
const createProductForm = () => (
<form>
<span>Post photo</span>
<div className="form-group">
<label className="btn btn-block btn-success">
<input
onChange={handleChange("photo")}
type="file"
name="photo"
accept="image"
placeholder="choose a file"
/>
</label>
</div>
<div className="form-group">
<input
onChange={handleChange("name")}
name="photo"
className="form-control"
placeholder="Name"
value={name}
/>
</div>
<div className="form-group">
<textarea
onChange={handleChange("description")}
name="photo"
className="form-control"
placeholder="Description"
value={description}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("price")}
type="number"
className="form-control"
placeholder="Price"
value={price}
/>
</div>
<div className="form-group">
<select
onChange={handleChange("category")}
className="form-control"
placeholder="Category"
>
<option>Select</option>
{categories &&
categories.map((cate, index) => (
<option key={index} value={cate._id}>
{cate.name}
</option>
))}
</select>
</div>
<div className="form-group">
<input
onChange={handleChange("stock")}
type="number"
className="form-control"
placeholder="Stock"
value={stock}
/>
</div>
<button
type="submit"
onClick={onSubmit}
className="btn btn-outline-success mb-3"
>
Update Product
</button>
</form>
);
return (
<Base
title="Add a product here!"
description="Welcome to product creation section"
className="container bg-info p-4"
>
<Link to="/admin/dashboard" className="btn btn-md btn-dark mb-3">
Admin Home
</Link>
<div className="row bg-dark text-white rounded">
<div className="col-md-8 offset-md-2">
{successMessage()}
{createProductForm()}
</div>
</div>
</Base>
);
};
export default UpdateProduct;

Resources