I am making a react social media app which allows users to update their profile. I have setup a backend api using Django rest framework. My current issue is that when I add the date_of_birth field, the form won't submit, without this field everything works correctly so I think I have wrongly setup something to do with the handleDateChange. I have installed react-datepicker to help but I think this might also be the problem. Below is my code for ProfileEditForm.js :
import React, { useState, useEffect, useRef } from "react";
import { useHistory, useParams } from "react-router-dom";
import {
Form,
Button,
Image,
Row,
Col,
Container,
Alert,
} from "react-bootstrap";
import { axiosReq } from "../../api/axiosDefaults";
import {
useCurrentUser,
useSetCurrentUser,
} from "../../contexts/CurrentUserContext";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import btnStyles from "../../styles/Button.module.css";
import appStyles from "../../App.module.css";
const ProfileEditForm = () => {
const currentUser = useCurrentUser();
const setCurrentUser = useSetCurrentUser();
const { id } = useParams();
const history = useHistory();
const imageFile = useRef();
const [profileData, setProfileData] = useState({
name: "",
location: "",
favourite_location: "",
date_of_birth: null,
bio: "",
image: "",
});
const { name, location, favourite_location, date_of_birth, bio, image } =
profileData;
const [errors, setErrors] = useState({});
useEffect(() => {
const handleMount = async () => {
if (currentUser?.profile_id?.toString() === id) {
try {
const { data } = await axiosReq.get(`/profiles/${id}/`);
const {
name,
location,
favourite_location,
date_of_birth,
bio,
image,
} = data;
setProfileData({
name,
location,
favourite_location,
date_of_birth,
bio,
image,
});
} catch (err) {
console.log(err);
history.push("/");
}
} else {
history.push("/");
}
};
handleMount();
}, [currentUser, history, id]);
const handleChange = (event) => {
setProfileData({
...profileData,
[event.target.name]: event.target.value,
});
};
const handleDateChange = (date) => {
console.log(date);
setProfileData({
...profileData,
date_of_birth: date,
});
};
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append("name", name);
formData.append("location", location);
formData.append("favourite_location", favourite_location);
formData.append("date_of_birth", date_of_birth);
formData.append("bio", bio);
if (imageFile?.current?.files[0]) {
formData.append("image", imageFile?.current?.files[0]);
}
try {
const { data } = await axiosReq.put(`/profiles/${id}/`, formData);
setCurrentUser((currentUser) => ({
...currentUser,
profile_image: data.image,
}));
history.goBack();
} catch (err) {
console.log(err);
setErrors(err.response?.data);
}
};
const textFields = (
<>
<Form.Group>
<Form.Label>Name</Form.Label>
<Form.Control
className={appStyles.Input}
type="text"
value={name}
onChange={handleChange}
name="name"
aria-label="name"
/>
</Form.Group>
{errors?.name?.map((message, idx) => (
<Alert variant="danger" key={idx}>
{message}
</Alert>
))}
<Form.Group>
<Form.Label>Location</Form.Label>
<Form.Control
as="select"
value={location}
onChange={handleChange}
name="location"
rows={7}
>
<option value="">Choose location</option>
<option value="Afghanistan">Afghanistan</option>
<option value="Albania">Albania</option>
<option value="Zimbabwe">Zimbabwe</option>
</Form.Control>
</Form.Group>
{errors?.location?.map((message, idx) => (
<Alert variant="danger" key={idx}>
{message}
</Alert>
))}
<Form.Group>
<Form.Label>Favourite Location</Form.Label>
<Form.Control
as="textarea"
value={favourite_location}
onChange={handleChange}
name="favourite_location"
rows={7}
/>
</Form.Group>
{errors?.favourite_location?.map((message, idx) => (
<Alert variant="warning" key={idx}>
{message}
</Alert>
))}
<Form.Group>
<Form.Label>Date of birth</Form.Label>
<DatePicker
selected={date_of_birth}
value={date_of_birth}
onChange={handleDateChange}
name="date_of_birth"
rows={7}
/>
</Form.Group>
<Form.Group>
<Form.Label>Bio</Form.Label>
<Form.Control
as="textarea"
value={bio}
onChange={handleChange}
name="bio"
rows={7}
/>
</Form.Group>
{errors?.bio?.map((message, idx) => (
<Alert variant="warning" key={idx}>
{message}
</Alert>
))}
<Button
className={`${btnStyles.Button} ${btnStyles.Blue}`}
onClick={() => history.goBack()}
>
cancel
</Button>
<Button className={`${btnStyles.Button} ${btnStyles.Blue}`} type="submit">
save
</Button>
</>
);
return (
<Form onSubmit={handleSubmit}>
<Row>
<Col className="py-2 p-0 p-md-2 text-center" md={7} lg={6}>
<Container className={appStyles.Content}>
<Form.Group>
{image && (
<figure>
<Image src={image} fluid />
</figure>
)}
{errors?.image?.map((message, idx) => (
<Alert variant="warning" key={idx}>
{message}
</Alert>
))}
<div>
<Form.Label
className={`${btnStyles.Button} ${btnStyles.Blue} btn my-auto`}
htmlFor="image-upload"
>
Change the image
</Form.Label>
</div>
<Form.File
id="image-upload"
ref={imageFile}
accept="image/*"
onChange={(e) => {
if (e.target.files.length) {
setProfileData({
...profileData,
image: URL.createObjectURL(e.target.files[0]),
});
}
}}
/>
</Form.Group>
<div className="d-md-none">{textFields}</div>
</Container>
</Col>
<Col md={5} lg={6} className="d-none d-md-block p-0 p-md-2 text-center">
<Container className={appStyles.Content}>{textFields}</Container>
</Col>
</Row>
</Form>
);
};
export default ProfileEditForm;
When handleChange is called for my other form items, the form submits correctly but when I submit using the handleDateChange, the form does not work. Errors in the console are :
In my drf-api, in the profiles model the date_of_birth field is the following:
date_of_birth = models.DateTimeField(blank=True, null=True)
I added console.log(date) and console.log(date_of_birth) within the handleDateChange to check that both items are returned as objects. I have checked the format of the date object which appears to correct on both sides ( front end and back end).