jeudi 20 juillet 2023

How to unmark checkbox input while editing

im on a Laravel/Nextjs project.

Im retrieving data so the user can edit if he wish.

After several tries, i've managed to show the data on the form, and i can edit the input name, and select different degrees.

The problem is with the checkbox input, when i try to deselect it does it in order and not by the one i've clicked on it. + I can't select more than 1 checkbox.

I will show you the component, the form component and the data i get from the backend.

Any information would help me a lot. Thanks !

"use client";
import { useEffect, useState } from "react";
import axios from "axios";
import { useSnackbar } from "notistack";
import { useParams, useRouter } from "next/navigation";
import Form from "@/app/form";
import Header from "@/app/Admin/header";

export default function EditYear() {
  const { enqueueSnackbar } = useSnackbar();
  const router = useRouter();
  const { id } = useParams();

  const backendURL = process.env.NEXT_PUBLIC_BACKEND_URL;
  const token =
    typeof window !== "undefined" ? localStorage.getItem("auth_token") : null;
  const type =
    typeof window !== "undefined" ? localStorage.getItem("type") : null;

  const [yearData, setYearData] = useState({});
  const [degrees, setDegrees] = useState([]);
  const [selectedDegree, setSelectedDegree] = useState("");
  const [selectedSubjects, setSelectedSubjects] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get(
          `${backendURL}/api/year/edit/${id}`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
              "X-Type": type,
            },
          }
        );

        if (response.status === 200) {
          const data = response.data;
          setYearData(data.year_data);
          setDegrees(data.degrees);
          setSelectedDegree(data.year_data.degree_id);
          setSelectedSubjects(data.year_data.subjects.map((subject) => subject.id));
        } else {
          console.error("Error: Unable to fetch data");
        }
      } catch (error) {
        console.error("Error: ", error.message);
      }
    };

    fetchData();
  }, []);

  const handleFormSubmit = async (e) => {
    e.preventDefault();
    // Your form submission logic here
  };

  const handleInputChange = (e) => {
    // Update the form field value based on the input name
    const { name, value } = e.target;
    setYearData((prevData) => ({
      ...prevData,
      [name]: value,
    }));
  };

  const handleDegreeChange = (e) => {
    // Update the selected degree value
    const selectedDegreeId = parseInt(e.target.value);
    setSelectedDegree(selectedDegreeId);
    // Filter and update the selected subjects based on the selected degree
    const selectedDegree = degrees.find((degree) => degree.id === selectedDegreeId);
    setSelectedSubjects(selectedDegree ? selectedDegree.subjects.map((subject) => subject.id) : []);
  };

  const handleSubjectChange = (e) => {
    // Update the selected subjects array
    const selectedSubjectId = parseInt(e.target.value);
    setSelectedSubjects((prevSubjects) =>
      prevSubjects.includes(selectedSubjectId)
        ? prevSubjects.filter((id) => id !== selectedSubjectId)
        : [...prevSubjects, selectedSubjectId]
    );
  };
  

  const fields = [
    {
      label: "Name",
      type: "text",
      name: "year_name",
      value: yearData.year_name || "",
      onChange: handleInputChange,
    },
    {
      label: "Degree",
      type: "select",
      name: "degree_id",
      value: selectedDegree,
      options: degrees.map((degree) => ({
        label: degree.name,
        value: degree.id,
      })),
      onChange: handleDegreeChange,
    },
    {
      label: "Subjects",
      type: "checkbox",
      name: "subjects",
      options: degrees
        .find((degree) => degree.id === selectedDegree)
        ?.subjects.map((subject) => ({
          label: subject.name,
          value: subject.id,
        })) || [],
      value: selectedSubjects,
      onChange: handleSubjectChange,
    },

  ];

  return (
    <>
      <Header title="Create Year" />

      <Form
        onSubmit={handleFormSubmit}
        fields={fields}
        type="Create Year"
        send="Add a Year"
      />
    </>
  );
}

Here is the form.

export default function Form({ onSubmit, fields, type, send, initialValue }) {
  const handleCheckboxChange = (e, field) => {
    const { value, checked } = e.target;
    field.onChange({
      target: {
        name: field.name,
        value: checked
          ? [...field.value, value]
          : field.value.filter((item) => item !== value),
      },
    });
  };

  return (
    <div className="flex flex-col w-4/5 h-auto p-4 mx-auto my-0 lg:shadow-none gap-y-4 lg:w-2/3">
      <div className="text-lg font-semibold uppercase lg:text-xl">
        <h1>{type}</h1>
      </div>

      <form className="flex flex-col lg:gap-y-4 gap-y-6" onSubmit={onSubmit}>
        {fields.map((field) => (
          <div key={field.name} className="flex flex-col gap-y-2">
            <label className="text-sm lg:text-base">{field.label}</label>
            {field.type === "checkbox" ? (
              field.options.map((option) => (
                <div key={option.value} className="flex items-center">
                  <input
                    className="mr-2"
                    type="checkbox"
                    name={field.name}
                    value={option.value}
                    checked={field.value.includes(option.value)}
                    onChange={(e) => handleCheckboxChange(e, field)}
                  />
                  <label>{option.label}</label>
                </div>
              ))
            ) : field.type === "select" ? (
              <select
                className="h-8 pl-4 border-2 border-gray-500 border-solid rounded-md outline-none focus:border-verde lg:h-12"
                name={field.name}
                value={field.value}
                onChange={field.onChange}
              >
                <option value="">{initialValue}</option>
                {field.options.map((option) => (
                  <option key={option.value} value={option.value}>
                    {option.label}
                  </option>
                ))}
              </select>
            ) : (
              <input
                className="h-8 pl-4 border-2 border-gray-500 border-solid rounded-md outline-none focus:border-verde lg:h-12"
                placeholder={field.placeholder}
                type={field.type}
                name={field.name}
                value={field.value}
                onChange={field.onChange}
              />
            )}
          </div>
        ))}

        <button
          type="submit"
          className="flex items-center justify-center w-1/2 h-10 mx-auto my-0 text-sm font-medium text-white transition-colors duration-300 rounded-lg lg:w-1/4 bg-verde hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-green-500 active:bg-green-700"
        >
          {send}
        </button>
      </form>
    </div>
  );
}

And the data in json.

{
    "year_data": {
        "year_id": 2,
        "year_name": "Medicina-2",
        "degree_id": 1,
        "degree_name": "Medicinal",
        "subjects": []
    },
    "degrees": [
        {
            "id": 1,
            "branch_id": 1,
            "name": "Medicinal",
            "created_at": "2023-06-25T16:43:51.000000Z",
            "updated_at": "2023-07-10T09:28:42.000000Z",
            "subjects": [
                {
                    "id": 6,
                    "degree_id": 1,
                    "name": "Aniouno",
                    "created_at": "2023-07-20T22:06:08.000000Z",
                    "updated_at": "2023-07-20T22:06:08.000000Z"
                },
                {
                    "id": 7,
                    "degree_id": 1,
                    "name": "anio2",
                    "created_at": "2023-07-20T22:06:08.000000Z",
                    "updated_at": "2023-07-20T22:06:08.000000Z"
                },
                {
                    "id": 8,
                    "degree_id": 1,
                    "name": "mok",
                    "created_at": "2023-07-20T22:06:08.000000Z",
                    "updated_at": "2023-07-20T22:06:08.000000Z"
                },
                {
                    "id": 9,
                    "degree_id": 1,
                    "name": "bok",
                    "created_at": "2023-07-20T22:06:08.000000Z",
                    "updated_at": "2023-07-20T22:06:08.000000Z"
                }
            ]
        },
        {
            "id": 8,
            "branch_id": 1,
            "name": "Anatomias",
            "created_at": "2023-07-10T05:52:52.000000Z",
            "updated_at": "2023-07-10T05:52:52.000000Z",
            "subjects": [
                {
                    "id": 2,
                    "degree_id": 8,
                    "name": "Dentistas",
                    "created_at": "2023-06-25T16:50:45.000000Z",
                    "updated_at": "2023-07-11T11:04:44.000000Z"
                }
            ]
        },
        {
            "id": 9,
            "branch_id": 1,
            "name": "Aeroplanes",
            "created_at": "2023-07-10T05:52:52.000000Z",
            "updated_at": "2023-07-10T05:52:52.000000Z",
            "subjects": []
        },
        {
            "id": 10,
            "branch_id": 1,
            "name": "Arquitectura",
            "created_at": "2023-07-10T05:52:52.000000Z",
            "updated_at": "2023-07-10T05:52:52.000000Z",
            "subjects": [
                {
                    "id": 4,
                    "degree_id": 10,
                    "name": "Ahorasi",
                    "created_at": "2023-06-25T16:50:45.000000Z",
                    "updated_at": "2023-07-11T11:04:32.000000Z"
                }
            ]
        }
    ]
}



Aucun commentaire:

Enregistrer un commentaire