I can create course but can't update it. (Express, React)

31 Views Asked by At

I already tested the code in postman and works, but when i do it through React it tells me 400 and passes the validation i created the field title is required. I also checked form data and is being received correctly. The problem is that on submit req.body is undefined.

index.js

index.js

import express from "express";
import cors from "cors"
import bodyParser from "body-parser"
import mongoose from "mongoose";
import dotenv from "dotenv";
import userRoutes from "./routes/user.route.js";
import authRoutes from "./routes/auth.route.js";
import courseRoutes from "./routes/course.route.js";
import cookieParser from "cookie-parser";
import path from "path";

dotenv.config();

mongoose
  .connect(process.env.DB_URI)
  .then(() => {
    console.log("Connected to MongoDB");
  })
  .catch((err) => {
    console.log(err);
  });

const __dirname = path.resolve();

//! BASIC CONFIG OF APP
const app = express();
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }));
const corsOptions = {
  origin: "*",
  credentials: true,
  optionSuccessStatus: 200
}
app.use(cors(corsOptions))
app.use(cookieParser());


// Serve static files from the 'uploads' directory
app.use("/uploads", express.static(path.join(__dirname, "uploads")));

// routes
app.use("/api/user", userRoutes);
app.use("/api/auth", authRoutes);
app.use("/api/course", courseRoutes);

// error formatter for console
app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const message = err.message || "Internal Server Error";
  return res.status(statusCode).json({
    success: false,
    message,
    statusCode,
  });
});

app.listen(process.env.PORT, () => {
  console.log("Server listening on port", process.env.PORT);
});


export default app

CourseUpdate.js

import React, {  useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";

const CourseUpdate = () => {
  const { currentUser } = useSelector((state) => state.user);
  const { id } = useParams();
  const [errorMessage, setErrorMessage] = useState("");
  const [course, setCourse] = useState(null);
  const [successMessage, setSuccessMessage] = useState("");

  const renderImage = (formData) => {
    const file = formData.get("image");
    const image = URL.createObjectURL(file);
    $image.current.setAttribute("src", image);
  };

  const $image = useRef(null);

  useEffect(() => {
    // Fetch course data when the component mounts
    const fetchCourse = async () => {
      try {
        const response = await fetch(`http://localhost:3006/api/course/${id}`);
        if (response.ok) {
          const data = await response.json();
          setCourse(data.course);
        } else {
          throw new Error("Failed to fetch course data");
        }
      } catch (error) {
        console.error("Error fetching course:", error);
        setErrorMessage("Failed to fetch course data");
      }
    };

    fetchCourse();
  }, [id]);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setCourse((prevCourse) => ({
      ...prevCourse,
      [name]: value,
    }));
  };
  

  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);

    const imageFile = formData.get("image");
    const videoFile = formData.get("video");

    if (imageFile) {
      formData.set("image", imageFile, imageFile.name);
    }

    if (videoFile) {
      formData.set("video", videoFile, videoFile.name);
    }

    formData.append("title", course.title);

    renderImage(formData);

    const response = await fetch(
      `http://localhost:3006/api/course/update/${id}`,
      {
        method: "PUT",
        body: formData,
      }
    );
    if (response.ok) {
      const data = await response.json();
      setSuccessMessage(encodeURIComponent(data.message));
      window.location.href = data.redirectUrl;
    } else {
      const errorData = await response.json();
      setErrorMessage(errorData.message);
    }
  };
  // Render the form only when course data is fetched
  return (
    course && (
      <div id="update-course-container-page">
        {errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}
        {successMessage && <p style={{ color: "green" }}>{successMessage}</p>}
        <div id="update-course-container" className="mt-8 mx-5">
          {currentUser && <p className="text-primary">Hello, {currentUser._id}!</p>}

          <h1 className="section-title">Actualizando Curso</h1>
          <div>
            <form className="form" method="POST" onSubmit={handleSubmit}>
              {errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}

              {/* CONTENT */}
              <h3>Titulo & contenido:</h3>
              <div className="row">
                <div className="col-lg-6">
                  <label htmlFor="title">titulo:</label>
                  <input
                    name="title"
                    value={course.title}
                    onChange={handleChange}
                    type="text"
                    className="form-control"
                  />
                </div>
                <div className="col-lg-6">
                  <label htmlFor="description">Descripcion:</label>
                  <input
                    name="description"
                    value={course.description}
                    onChange={handleChange}
                    type="text"
                    className="form-control"
                  />
                </div>
              </div>
              <div className="row">
                <div className="col-lg-12">
                  <label htmlFor="text_content">contenido texto:</label>
                  <textarea
                    name="text_content"
                    value={course.text_content}
                    onChange={handleChange}
                    type="text"
                    className="form-control"
                  ></textarea>
                </div>
              </div>
              <hr />

              {/* UPLOAD */}
              <h3>Subir Archivos:</h3>
              {errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}

              <div className="row col-lg-12 items-center">
                <div className="">
                  <label htmlFor="video">subir video :</label>
                  <input
                    type="file"
                    name="video"
                    accept="video/*"
                    onChange={handleChange}
                  />
                </div>
                <br />
                <br />
                <div className="">
                  <label htmlFor="image">subir miniatura:</label>
                  <input
                    type="file"
                    id="file"
                    name="image"
                    accept="image/*"
                    onChange={handleChange}
                  />
                </div>
              </div>
              <div className="row">
                <div className="col-lg-12">
                  <div className="preview">
                    <img id="img" ref={$image} style={{ width: 300 }} />
                  </div>
                </div>
              </div>
              <hr />

              {/* PRICE */}
              <h3>Configurar precio</h3>
              {errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}

              <div className="row col-lg-12 items-center">
                <div className="">
                  <label htmlFor="ars_price">ARS Price:</label>
                  <input
                    type="number"
                    id="ars_price"
                    name="ars_price"
                    value={course.ars_price}
                    onChange={handleChange}
                  />
                </div>
                <div className="">
                  <label htmlFor="usd_price">USD Price:</label>
                  <input
                    type="number"
                    id="usd_price"
                    name="usd_price"
                    value={course.usd_price}
                    onChange={handleChange}
                  />
                </div>
              </div>
              <hr />

              {/* DISCOUNT */}
              <h3>Adicionales & descuentos</h3>
              {errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}

              <div className="row items-center col-lg-12">
                <div className="">
                  <label htmlFor="discount_ars">
                    descuento_ars opcional (numeros enteros):
                  </label>
                  <br />
                  <strong>% ARS </strong>
                  <input
                    type="number"
                    id="discount_ars"
                    name="discount_ars"
                    value={course.discount_ars}
                    onChange={handleChange}
                  />
                </div>
                <div className="">
                  <label htmlFor="discount_usd">
                    descuento_usd opcional (numeros enteros):
                  </label>
                  <br />
                  <strong>% USD </strong>
                  <input
                    type="number"
                    id="discount_usd"
                    name="discount_usd"
                    value={course.discount_usd}
                    onChange={handleChange}
                  />
                </div>
              </div>

              <input
                type="hidden"
                name="author"
                value={currentUser._id}
              />
              <br />
              <br />

              {/* submit */}
              <div className="items-center text-center mt-20">
                <button type="submit" className="btn btn-success">
                  Update Course
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
    )
  );
};

export default CourseUpdate;

course.model.js

import mongoose from 'mongoose';


const courseSchema = new mongoose.Schema(
  {
    title: { type: String, required: true },
    slug: { type: String, required: true, unique: true },
    description: { type: String, default: null },
    text_content: { type: String, default: null },
    ars_price: { type: Number, required: true },
    usd_price: { type: Number, required: true },
    discount_ars: { type: Number, default: null },
    discount_usd: { type: Number, default: null },
    thumbnail: { type: String, default: null, required:false },
    video: { type: String, default: null, required:false }, // Including the video field
    author_id: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }, // Assuming there's a User model
    author: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
  },
  { timestamps: true }
);

const Course = mongoose.model('Course', courseSchema);

export default Course;

course.controller.js

// Update
export const courseUpdate = async (req, res, next) => {

  try {
    const courseId = req.params.id;

    // Fetch existing course from the database
    const course = await Course.findById(courseId);

    if (!course) {
      return next(errorHandler(400, `Course not found.`));
    }

    // Extract necessary data from request body
    const {
      title,
      description,
      text_content,
      ars_price,
      usd_price,
      discount_ars,
      discount_usd,
      author,
    } = req.body;

    console.log("req.body",req.body)

    // Manage discount value
    const discountArs = discount_ars || null;
    const discountUsd = discount_usd || null;

    // Update course details
    const updatedCourse = await Course.findByIdAndUpdate(courseId, {
      title,
      description,
      text_content,
      ars_price,
      usd_price,
      discount_ars: discountArs,
      discount_usd: discountUsd,
    });
    
    await updatedCourse.save();

    console.log("\nUpdating course...");
    console.log("\nCourse:", updatedCourse);

    // Redirect after updating the course
    return res.status(200).json({
      message: "Course updated successfully",
      course: updatedCourse._id,
      redirectUrl: `/course/${courseId}`
    });
  } catch (error) {
    return next(error);
  }
};

course.route.js

import express from "express";
import {
  courseCreate,
  courseUpdate,
  courselist,
  courseOwned,
  courseDetail,
  courseDelete,
} from "../controllers/course.controller.js";
import upload from "../useMulter.js";

const router = express.Router();

router.post(
  "/create",
  upload.fields([
    { name: "image", maxCount: 1 },
    { name: "video", maxCount: 1 },
  ]),
  courseCreate
);
router.put("/update/:id", courseUpdate);
router.get("/all", courselist);
router.get("/owned", courseOwned);
router.get("/:id", courseDetail);
router.delete("/delete/:id", courseDelete);

export default router;
0

There are 0 best solutions below