1

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).

chris-t93
  • 21
  • 5

0 Answers0