I fetching data from API to the fields input and by default, the values come from API. After fetching I have the edit button and after click, I can edit the values in form fields. So, please, can someone tell me how to add validation on inputs (for example if empty inputs, after click save show the message in inputs "empty value" and red border on this input) Thank you
import React, { useEffect, useState, useRef } from "react";
import { useParams, Link } from "react-router-dom";
import { useGlobalContext } from "../context";
import styled from "styled-components";
import Sort from "../components/sort";
const urlID = "https://jsonplaceholder.typicode.com/users?id=";
const Profile = () => {
const { id } = useParams();
const [user, setUser] = useState([]);
const [isReadOnly, setIsReadOnly] = useState(true);
const [isEdit, setIsEdit] = useState(false);
const form = useRef(null);
const fetchUser = async (urlID) => {
try {
const response = await fetch(urlID);
const data = await response.json();
if (data) {
const { name, username, email, phone, website } = data[0];
const { street, city, zipcode } = data[0].address;
const newPerson = {
name,
username,
email,
phone,
website,
street,
city,
zipcode,
};
setUser(newPerson);
} else {
setUser(null);
}
} catch (error) {
console.log(error);
}
};
useEffect(() => {
fetchUser(`${urlID}${id}`);
}, [id]);
const editInput = () => {
setIsEdit(true);
setIsReadOnly(false);
};
const handleSubmit = (e) => {
e.preventDefault();
const data = new FormData(form.current);
const value = Object.fromEntries(data.entries());
// value.user = data.getAll("name");
console.log(value);
setIsEdit(false);
setIsReadOnly(true);
};
const handleChange = (e) => {
setUser({
...user,
[e.target.name]: e.target.value,
});
};
return (
<main>
<Wrapper>
<Sort />
<div>
<header>
<h3>User profile</h3>
<button onClick={() => editInput()} className='btn'>
Edit
</button>
</header>
<form className='form' ref={form} onSubmit={handleSubmit}>
<div className='form-control'>
<label htmlFor='name'>Name</label>
<input
name='name'
type='name'
defaultValue={user.name}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='username'>Username</label>
<input
name='username'
type='username'
defaultValue={user.username}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='email'>Email</label>
<input
name='email'
type='email'
defaultValue={user.email}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='street'>Street</label>
<input
type='street'
name='street'
defaultValue={user.street}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='city'>City</label>
<input
type='city'
name='city'
defaultValue={user.city}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='zipcode'>Zip code</label>
<input
type='zipcode'
name='zipcode'
defaultValue={user.zipcode}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='website'>Website</label>
<input
type='website'
name='website'
defaultValue={user.website}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='phone'>Phone</label>
<input
type='phone'
name='phone'
defaultValue={user.phone}
readOnly={isReadOnly}
style={
!isEdit
? { color: "rgba(0, 0, 0, 0.3)" }
: { color: "#000000" }
}
onChange={handleChange}
/>
</div>
<div className='form-control'>
<label htmlFor='comment'>Comment</label>
<textarea
name='textarea'
id=''
cols='30'
rows='10'
readOnly={isReadOnly}
onChange={handleChange}
></textarea>
</div>
<div className='btn-container'>
<Link to='/' className='btn'>
Back
</Link>
<button
type='submit'
className='btn-submit'
disabled={isReadOnly}
style={
!isEdit
? { backgroundColor: "#afafaf" }
: { backgroundColor: "#52CF4F" }
}
onClick={handleSubmit}
>
Save
</button>
</div>
</form>
</div>
</Wrapper>
</main>
);
};
const Wrapper = styled.section`
display: grid;
grid-template-columns: 1fr 2fr;
max-width: 665px;
width: 90vw;
gap: 2rem;
h3 {
font-style: normal;
font-weight: 700;
font-size: 14px;
line-height: 16px;
color: #000000;
}
.btn {
background: #4b51ef;
border-radius: 5px;
padding: 6px 11px;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #ffffff;
border: transparent;
text-decoration: none;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
}
.form {
display: grid;
gap: 10px;
padding: 20px 0 20px 12px;
background: #ffffff;
border: 2px solid #f3f3f3;
border-radius: 8px;
box-sizing: border-box;
}
.form-control {
display: flex;
flex-direction: column;
gap: 3px;
max-width: 210px;
}
.form-control label {
font-weight: 400;
font-size: 8px;
line-height: 9px;
color: #000000;
}
.form-control input,
textarea {
font-weight: 400;
font-size: 10px;
line-height: 12px;
/* color: rgba(0, 0, 0, 0.3); */
padding: 5px 0 5px 10px;
background: #ffffff;
border: 1px solid #d8d8d8;
border-radius: 5px;
}
/* input:invalid {
border-color: red;
} */
.btn-container {
display: flex;
align-items: center;
justify-content: center;
}
.btn-submit {
background: #afafaf;
border-radius: 5px;
border: transparent;
padding: 5px 15px;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #ffffff;
margin-left: 10px;
}
`;
export default Profile;
CodePudding user response:
You may check Formik
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
}}
validationSchema={SignupSchema}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched }) => (
<Form>
<Field name="firstName" />
{errors.firstName && touched.firstName ? (
<div>{errors.firstName}</div>
) : null}
<Field name="lastName" />
{errors.lastName && touched.lastName ? (
<div>{errors.lastName}</div>
) : null}
<Field name="email" type="email" />
{errors.email && touched.email ? <div>{errors.email}</div> : null}
<button type="submit">Submit</button>
</Form>
)}
</Formik>