Untitled

 avatar
unknown
plain_text
a month ago
18 kB
5
Indexable

import React, { useState, useEffect } from "react";
import axios from "axios";
import { useRouter } from "next/router";
import NavBar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import { ToastContainer, toast } from "react-toastify";
import routes from "@/routes";

const AddCategory = () => {
  const [categoryName, setCategoryName] = useState("");
  const [description, setDescription] = useState("");
  const [photos, setPhotos] = useState([]); // Changed to array for multiple images
  const [errors, setErrors] = useState({});
  const router = useRouter();
  const [componentName, setComponentName] = useState("");
  const [sectionID, setSectionID] = useState("");
  const [AllSections, setAllSection] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const [prevSectionID, setPrevSectionID] = useState("");
  const [discountType, setDiscountType] = useState("percentage");
  const [discountValue, setDiscountValue] = useState(0);

  const getComponentNameBySectionID = async (sectionID) => {
    try {
      const res = await axios.get(
        `${process.env.NEXT_PUBLIC_BASE_URL}/section/${sectionID}`
      );
      return res.data.componentName;
    } catch (error) {
      console.error("Error fetching componentName:", error);
      return null;
    }
  };

  useEffect(() => {
    const fetchData = async () => {
      if (router.query.data) {
        const {
          _id,
          name,
          photo,
          sectionID: querySectionID,
          description: queryDescription,
          discount,
        } = JSON.parse(router.query.data);
        setCategoryName(name);
        // Initialize photos array with existing photo if it exists
        setPhotos(photo ? [photo] : []);
        setSectionID(querySectionID);
        setPrevSectionID(querySectionID);
        setDescription(queryDescription);

        if (discount) {
          setDiscountType(discount.type);
          setDiscountValue(discount.value);
        }
        const fetchedComponentName = await getComponentNameBySectionID(
          querySectionID
        );
        if (fetchedComponentName) {
          setComponentName(fetchedComponentName);
          await getAllSectionWithComponent(fetchedComponentName);
        }
      }
      setIsLoading(false);
    };

    fetchData();
  }, [router.query.data]);

  const validateForm = () => {
    const newErrors = {};
    if (!categoryName) newErrors.categoryName = "Category name is required";
    if (photos.length === 0) newErrors.photo = "At least one photo is required";
    if (!componentName) newErrors.componentName = "Component name is required";
    if (!sectionID) newErrors.sectionID = "Please select a Section";
    if (!discountValue) newErrors.discountValue = "Discount value is required.";
    if (discountValue < 0)
      newErrors.discountValue = "Discount value cannot be negative.";
    if (!description) newErrors.description = "Description is required.";
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleCategoryNameChange = (e) => {
    setCategoryName(e.target.value);
    setErrors((prev) => ({ ...prev, categoryName: "" }));
  };

  const handleDescriptionChange = (e) => {
    setDescription(e.target.value);
    setErrors((prev) => ({ ...prev, description: "" }));
  };

  const handlePhotoChange = async (e) => {
    const files = Array.from(e.target.files);

    for (const file of files) {
      if (file && file.type.startsWith("image/")) {
        try {
          setErrors((prev) => ({ ...prev, photo: "" }));

          const token = localStorage.getItem("token");
          const formDataToSend = new FormData();

          // Add all necessary category data to formData
          formDataToSend.append("image", file);
          formDataToSend.append("name", categoryName);
          formDataToSend.append("componentName", componentName);
          formDataToSend.append("sectionID", sectionID);
          formDataToSend.append("description", description);
          formDataToSend.append("discountType", discountType);
          formDataToSend.append("discountValue", discountValue);

          let response;
          if (router.query.data) {
            // If editing existing category
            const { _id } = JSON.parse(router.query.data);
            response = await axios.put(
              `${process.env.NEXT_PUBLIC_BASE_URL}${routes.category.edit(_id)}`,
              formDataToSend,
              {
                headers: {
                  Authorization: `Bearer ${token}`,
                  "Content-Type": "multipart/form-data",
                },
              }
            );
          } else {
            // If creating new category
            response = await axios.post(
              `${process.env.NEXT_PUBLIC_BASE_URL}${routes.s3.create}`,
              formDataToSend,
              {
                headers: {
                  Authorization: `Bearer ${token}`,
                  "Content-Type": "multipart/form-data",
                },
              }
            );
          }

          // Assuming the response includes the image URL
          const imageUrl = response.data.photo || response.data.imageUrl;
          setPhotos((prevPhotos) => [...prevPhotos, imageUrl]);

          toast.success("Image uploaded successfully");
        } catch (error) {
          console.error("Error uploading image:", error);
          toast.error(
            "There was an error uploading the image. Please try again."
          );
        }
      } else {
        toast.error("Please select a valid image file");
      }
    }
  };

  const handleRemovePhoto = (indexToRemove) => {
    setPhotos((prevPhotos) =>
      prevPhotos.filter((_, index) => index !== indexToRemove)
    );
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!validateForm()) {
      return;
    }

    const token = localStorage.getItem("token");
    const formData = new FormData();

    // Add all form data
    formData.append("name", categoryName);
    formData.append("componentName", componentName);
    formData.append("sectionID", sectionID);
    formData.append("description", description);
    formData.append("discountType", discountType);
    formData.append("discountValue", discountValue);

    // Add all photos
    photos.forEach((photo, index) => {
      formData.append(`photos[${index}]`, photo);
    });

    try {
      let response;
      if (router.query.data) {
        const { _id } = JSON.parse(router.query.data);
        response = await axios.put(
          `${process.env.NEXT_PUBLIC_BASE_URL}${routes.category.edit(_id)}`,
          formData,
          {
            headers: {
              Authorization: `Bearer ${token}`,
              "Content-Type": "multipart/form-data",
            },
          }
        );
      } else {
        response = await axios.post(
          `${process.env.NEXT_PUBLIC_BASE_URL}${routes.s3.create}`,
          formData,
          {
            headers: {
              Authorization: `Bearer ${token}`,
              "Content-Type": "multipart/form-data",
            },
          }
        );
      }

      toast.success(response.data.message || "Category saved successfully");
      setTimeout(() => {
        router.push("/categories");
      }, 1000);
    } catch (error) {
      toast.error("Error saving category");
      console.error("Error saving category:", error);
    }
  };

  const getAllSectionWithComponent = async (compName) => {
    try {
      const res = await axios.get(
        `${process.env.NEXT_PUBLIC_BASE_URL}/section?componentName=${compName}`
      );
      setAllSection(res.data);
    } catch (error) {
      console.error("Error fetching sections:", error);
      toast.error("Error loading sections");
    }
  };

  useEffect(() => {
    if (componentName) {
      getAllSectionWithComponent(componentName);
    }
  }, [componentName]);

  const handleComponentChange = (e) => {
    const newComponentName = e.target.value;
    setComponentName(newComponentName);
    setSectionID("");
    setErrors((prev) => ({ ...prev, componentName: "", sectionID: "" }));
  };

  const handleSectionChange = (e) => {
    setSectionID(e.target.value);
    setErrors((prev) => ({ ...prev, sectionID: "" }));
  };

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div className="flex flex-1 h-screen overflow-y-scroll custom-scrollbar">
      <ToastContainer />
      <Sidebar />
      <div className="flex flex-1 flex-col">
        <NavBar />
        <div className="flex-1 px-4 bg-[#f6f6f6] py-4">
          <div className="p-4 mt-24 flex flex-col">
            <p className="text-black text-xl font-semibold">
              {router.query.data ? "Edit" : "Add"} Category Form
            </p>
            <p className="text-neutral-400 text-xs font-normal mt-2">
              {router.query.data ? "Edit" : "Add"} form for categories
            </p>
            <div className="w-full h-fit bg-white rounded-lg mt-5">
              <form
                onSubmit={handleSubmit}
                className="w-[92%] mx-auto flex flex-col mt-6"
              >
                <div>
                  <span className="text-neutral-800 text-sm font-medium">
                    Category Name
                  </span>
                  <span className="text-red-400 text-sm font-medium">*</span>
                </div>
                <div className="mt-2">
                  <input
                    className="outline-none w-[464px] h-12 bg-white rounded-lg border border-zinc-300 px-2"
                    placeholder="Enter category name"
                    required={true}
                    value={categoryName}
                    onChange={handleCategoryNameChange}
                  />
                  {errors.categoryName && (
                    <p className="text-red-500 text-sm mt-1">
                      {errors.categoryName}
                    </p>
                  )}
                </div>
                <div>
                  <span className="text-neutral-800 text-sm font-medium">
                    Category Description
                  </span>
                  <span className="text-red-400 text-sm font-medium">*</span>
                </div>
                <div className="mt-2">
                  <input
                    className="outline-none w-[464px] h-12 bg-white rounded-lg border border-zinc-300 px-2"
                    placeholder="Enter category description"
                    required={true}
                    value={description}
                    onChange={handleDescriptionChange}
                  />
                  {errors.description && (
                    <p className="text-red-500 text-sm mt-1">
                      {errors.description}
                    </p>
                  )}
                </div>
                <div className="mt-5">
                  <span className="text-neutral-800 text-sm font-medium">
                    Component Name
                  </span>
                  <span className="text-red-400 text-sm font-medium">*</span>
                </div>
                <div className="mt-2">
                  <select
                    className="outline-none w-[464px] h-12 bg-white rounded-lg border border-zinc-300 px-2"
                    value={componentName}
                    onChange={handleComponentChange}
                    required
                  >
                    <option value="">Select a component</option>
                    <option value="categorylist1">Category List 1</option>
                    <option value="categorylist2">Category List 2</option>
                    <option value="categorylist3">Category List 3</option>
                  </select>
                  {errors.componentName && (
                    <p className="text-red-500 text-sm mt-1">
                      {errors.componentName}
                    </p>
                  )}
                </div>

                <div className="mt-5">
                  <span className="text-neutral-800 text-sm font-medium">
                    Select Section ID
                  </span>
                  <span className="text-red-400 text-sm font-medium">*</span>
                </div>
                <div className="mt-2">
                  <select
                    className="outline-none w-[464px] h-12 bg-white rounded-lg border border-zinc-300 px-2"
                    value={sectionID}
                    onChange={handleSectionChange}
                    required
                  >
                    <option value="">Select a Section</option>
                    {AllSections.map((section) => (
                      <option key={section._id} value={section._id}>
                        {section.title}
                      </option>
                    ))}
                  </select>
                  {errors.sectionID && (
                    <p className="text-red-500 text-sm mt-1">
                      {errors.sectionID}
                    </p>
                  )}

                  <div className="flex flex-col w-[45.5%] gap-1 mt-2">
                    <p className="text-neutral-800 text-sm font-medium">
                      Discount Type
                    </p>
                    <select
                      value={discountType}
                      onChange={(e) => setDiscountType(e.target.value)}
                      className="outline-none border rounded-md h-[50px] w-[90%] px-2"
                    >
                      <option value="percentage">Percentage</option>
                      <option value="flat">Flat</option>
                    </select>

                    <p className="text-neutral-800 text-sm font-medium mt-2">
                      Discount Value
                    </p>
                    <input
                      className="outline-none border rounded-md h-[50px] w-[90%] px-2"
                      placeholder="Enter discount value"
                      type="number"
                      value={discountValue}
                      onChange={(e) => setDiscountValue(e.target.value)}
                    />
                    {errors.discountValue && (
                      <p className="text-red-500 text-sm mt-1">
                        {errors.discountValue}
                      </p>
                    )}
                  </div>
                </div>

                <div className="mt-5">
                  <span className="text-neutral-800 text-sm font-medium">
                    Upload photos
                  </span>
                  <span className="text-red-400 text-sm font-medium">*</span>
                  <div className="w-[465px] h-[125px] bg-neutral-50 rounded-lg custom-dotted-border mt-2 border-pink-700 flex justify-center items-center">
                    <label htmlFor="photoInput">
                      <img src="/images/upload.svg" alt="Upload" />
                    </label>
                    <input
                      id="photoInput"
                      type="file"
                      className="hidden"
                      onChange={handlePhotoChange}
                      multiple
                    />
                  </div>
                  {errors.photo && (
                    <p className="text-red-500 text-sm mt-1">{errors.photo}</p>
                  )}
                  <div className="flex flex-wrap gap-3 mt-3">
                    {photos.map((photo, index) => (
                      <div
                        key={index}
                        className="relative border border-pink-700 rounded-lg"
                      >
                        <img
                          src={photo}
                          alt={`Uploaded Photo ${index + 1}`}
                          className="h-12 w-18 rounded-lg"
                        />
                        <button
                          type="button"
                          className="absolute -top-1 -right-1 bg-white rounded-full w-5 h-5 flex items-center justify-center text-red-500 text-sm border border-red-500"
                          onClick={() => handleRemovePhoto(index)}
                        >
                          ×
                        </button>
                        {typeof photo === "string" && (
                          <span className="ml-2 text-xs">
                            {photo.split("/").pop()}
                          </span>
                        )}
                      </div>
                    ))}
                  </div>
                </div>

                <div className="flex justify-end my-5 gap-5 mx-5">
                  <div className="w-[184px] h-[43px] pl-[63px] pr-16 pt-2.5 pb-[9px] bg-pink-700 rounded-md border justify-center items-center inline-flex">
                    <button
                      type="submit"
                      className="text-white text-base font-medium"
                    >
                      {router.query.data ? "Update" : "Submit"}
                    </button>
                  </div>
                  <button
                    type="button"
                    className="text-pink-700 font-medium underline"
                    onClick={() => {
                      setCategoryName("");
                      setPhotos([]);
                      setComponentName("");
                      setSectionID("");
                      setErrors({});
                    }}
                  >
                    Clear
                  </button>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default AddCategory;
Leave a Comment