atlp-rwanda/atlp-devpulse-fn

View on GitHub
src/pages/TraineApplicant/Trainee.tsx

Summary

Maintainability
F
3 days
Test Coverage
/* eslint-disable */
import React, { useState, useEffect } from "react";
import { HiDotsVertical } from "react-icons/hi";
import * as icons from "react-icons/ai";
import { AiOutlinePlus } from "react-icons/ai";
import { BrowserRouter as Router, Link, useNavigate } from "react-router-dom";
import pagination from "../../components/pagination";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { connect, useSelector } from "react-redux";
import NavBar from "../../components/sidebar/navHeader";
import {
  softdeletetraine,
  deletetraine,
  fetchtraine,
  createtraine,
} from "../../redux/actions/deletetraine";
import { useAppDispatch } from "../../hooks/hooks";
import { getAllCycles } from "../../redux/actions/cyclesActions";
import Select from "react-select";
import { customTheme, darkTheme } from "../FilterTeainee/FilterTrainee";
import { useTheme } from "../../hooks/darkmode";
import {
  DOTS,
  useCustomPagination,
} from "../../components/Pagination/useCustomPagination";
import * as AiIcons from "react-icons/ai";
import { ApplicationsSkeleton } from "../../skeletons/applicationsSkeleton";

const AddTrainee = (props: any) => {
  const [addNewTraineeModel, setAddNewTraineeModel] = useState(false);
  const Open = () => {
    setAddNewTraineeModel(true);
  };
  const removeModel = () => {
    let newState = !addNewTraineeModel;
    setAddNewTraineeModel(newState);
  };
  const [firstName, setFirstname] = useState("");
  const [lastName, setLastname] = useState("");
  const [email, setEmail] = useState("");
  const [cycle_id, setCycleId] = useState("");

  // New state for search input and search field
  const [searchQuery, setSearchQuery] = useState("");
  const [searchField, setSearchField] = useState("firstName");

  // LIST ALL TRAINEE
  const { alltrainees, delettraine, softdeletettraine, traines, cycles } =
    props;
  const dispatch = useAppDispatch();
  const navigate = useNavigate();
  const [page, setPage] = useState(0);
  const [itemsPerPage, setItemsPerPage] = useState<number>(10);
  const [All, setAll] = useState(false);
  const [loading, setLoading] = useState(false);
  const { theme, setTheme } = useTheme();

  const input = {
    page: page + 1,
    itemsPerPage: itemsPerPage,
    All: All,
  };

  useEffect(() => {
    props.getAllCycles();
  }, []);

  const cycle = cycles.data;
  const traine = traines.message;
  // useEffect(() => {
  //   dispatch(fetchtraine(input));
  // }, [delettraine, softdeletettraine, page, itemsPerPage, itemsPerPage]);

   const [moredrop, setmoredrop] = useState("");

    useEffect(() => {
    setLoading(true); 
    dispatch(fetchtraine(input))
      .finally(() => setLoading(false));
  }, [delettraine, softdeletettraine, page, itemsPerPage]);

  const onSubmitHandler = (userid: any) => {
    if (!moredrop) setmoredrop(userid);
    if (moredrop) setmoredrop("");
  };
  const onSubmitHandle = async (userId: any) => {
    await dispatch(deletetraine(userId));
    setmoredrop("");
  };
  const onSubmitHandlesoft = async (userId: any) => {
    await dispatch(softdeletetraine(userId));
    setmoredrop("");
  };

  const validation = () => {
    if (firstName === "") {
      toast.error("Enter your firstname");
      return;
    }
    if (lastName === "") {
      toast.error("Enter your Lastname");
      return;
    }
    if (email === "") {
      toast.error("Enter your Email");
      return;
    }
    if (cycle_id === "") {
      toast.error("select a cycle");
      return;
    } else {
      createNewTrainee();
    }
  };

  const createNewTrainee = () => {
    const data = {
      firstName: firstName,
      lastName: lastName,
      email: email,
      cycle_id: cycle_id,
    };
    if (props.createtraine(data)) {
      setFirstname("");
      setLastname("");
      setEmail("");
      setAddNewTraineeModel(false);
    }
  };

  // Filter trainees by selected search field
  const filteredTrainees = traine?.filter((item: any) => {
    const fieldValue = item[searchField]?.toString().toLowerCase();
    return fieldValue?.includes(searchQuery.toLowerCase());
  });

  const paginationRange = useCustomPagination({
    totalPageCount: Math.ceil(traines?.pagination.totalItems / itemsPerPage),
    currentPage: page,
  });

  if (loading) {
    return <ApplicationsSkeleton/>
  }

  return (
    <>
      <ToastContainer />
      <div className="w-full">
        {/* =========================== Start:: addnewtraineeModel =============================== */}
        <div className="relative">
          <div
            className={`h-screen w-[100%] z-20 bg-black bg-opacity-30 backdrop-blur-sm absolute flex justify-center items-center  px-4 ${
              addNewTraineeModel === true ? "block" : "hidden"
            }`}
          >
            <div className="bg-white dark:bg-dark-bg w-full sm:w-[50%] xl:w-4/12 rounded-lg p-4 pb-8">
              <div className="card-title w-full flex  flex-wrap justify-center items-center  ">
                <h3 className="font-bold text-sm dark:text-white text-center w-11/12 ">
                  <icons.AiOutlineClose
                    className="float-right text-3xl cursor-pointer"
                    onClick={() => removeModel()}
                  />
                  {"New Trainee"}
                </h3>
                <hr className=" bg-primary border-b my-3 w-full" />
              </div>
              <div className="card-body">
                <section className=" py-3 px-8">
                  <div className="input my-3 h-9 ">
                    <div className="grouped-input flex items-center h-full w-full rounded-md">
                      <input
                        type="text"
                        name="gpa"
                        className=" dark:bg-dark-tertiary border border-primary rounded outline-none px-5 font-sans text-xs py-2 w-full pt-4"
                        placeholder={"FirstName"}
                        value={firstName}
                        onChange={(e) => {
                          setFirstname(e.target.value);
                        }}
                      />
                    </div>
                  </div>
                  <div className="input my-3 h-9 ">
                    <div className="grouped-input flex items-center h-full w-full rounded-md">
                      <input
                        type="text"
                        name="definition"
                        className=" dark:bg-dark-tertiary border border-primary py-2 rounded outline-none px-5 font-sans text-xs w-full pt-4"
                        placeholder={"LastName"}
                        value={lastName}
                        onChange={(e) => {
                          setLastname(e.target.value);
                        }}
                      />
                    </div>
                  </div>
                  <div className="input my-3 h-9 ">
                    <div className="grouped-input flex items-center h-full w-full rounded-md">
                      <input
                        type="text"
                        name="grade"
                        className=" dark:bg-dark-tertiary border border-primary py-2 rounded outline-none px-5 font-sans text-xs w-full pt-4"
                        placeholder={"Email"}
                        value={email}
                        onChange={(e) => {
                          setEmail(e.target.value);
                        }}
                      />
                    </div>
                  </div>
                  <div className="input my-3 h-9 ">
                    <div className="grouped-input flex items-center h-full w-full rounded-md">
                      <select
                        name="cycle"
                        id="cycle"
                        value={cycle_id}
                        className=" dark:bg-dark-tertiary border dark:text-white border-primary py-2 rounded outline-none px-5 font-sans text-xs w-full pt-4"
                        onChange={(e) => setCycleId(e.target.value)}
                      >
                        <option className="dark:text-white " value="">
                          --Please choose a cycle--
                        </option>
                        {cycle?.map((cycle: any) => (
                          <option className="dark:text-white " value={cycle.id}>
                            {cycle.name}
                          </option>
                        ))}
                      </select>
                    </div>
                  </div>
                  <button
                    className="flex bg-primary dark:bg-[#56C870] rounded-md py-2 px-4 text-white font-medium cursor-pointer m-auto"
                    onClick={validation}
                  >
                    save
                  </button>
                </section>
              </div>
            </div>
          </div>
        </div>
        {/* =========================== End:: addnewtraineeModel =============================== */}
       
        <div className="flex flex-col  h-screen w-[100%]">
          <div className="flex flex-row">
            <div className="w-full">
              <div>
                <div className="bg-light-bg dark:bg-dark-frame-bg  min-h-screen overflow-y-hidden overflow-x-hidden">
                  <div className="w-full px-4 sm:px-6 lg:px-8 py-4">
                    <div className="flex flex-col sm:flex-row items-start sm:items-center space-y-4 sm:space-y-0 sm:space-x-4">
                      <button
                        onClick={Open}
                        className="inline-flex items-center justify-center bg-primary dark:bg-[#56C870] rounded-md py-2 px-3 sm:px-4 text-white font-medium cursor-pointer text-sm sm:text-base whitespace-nowrap"
                      >
                        <icons.AiOutlinePlus className="mr-1.5 text-lg flex-shrink-0" />
                        <span className="truncate">Trainee-applicant</span>
                      </button>
                      <Select
                        menuPlacement="auto"
                        className="text-sm rounded-md dark:text-ltb"
                        options={[
                          { value: "firstName", label: "First Name" },
                          { value: "lastName", label: "Last Name" },
                          { value: "email", label: "Email" },
                        ]}
                        defaultValue={{
                          value: "firstName",
                          label: "First Name",
                        }}
                        onChange={(e: any) => setSearchField(e?.value)}
                        theme={theme ? customTheme : darkTheme}
                      />
                      <div className="w-full sm:w-auto flex-grow">
                        <div className="relative">
                          <input
                            type="text"
                            placeholder={`Search by ${searchField.replace(
                              "_",
                              " "
                            )}`}
                            value={searchQuery}
                            onChange={(e) => setSearchQuery(e.target.value)}
                            className="w-full bg-row-gray dark:bg-[#293647] dark:text-ltb border border-bdr dark:border-cg dark:border-opacity-5 rounded-md py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-[#56C870] text-sm"
                          />
                          <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                            <svg
                              className="h-5 w-5 text-gray-400"
                              fill="none"
                              stroke="currentColor"
                              viewBox="0 0 24 24"
                              xmlns="http://www.w3.org/2000/svg"
                            >
                              <path
                                strokeLinecap="round"
                                strokeLinejoin="round"
                                strokeWidth={2}
                                d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
                              />
                            </svg>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  {loading ? <ApplicationsSkeleton/> : (
                  <div className="px-8">
                    <div className="bg-white  dark:bg-dark-bg shadow-lg px-5 py-8 rounded-md w-[100%] mx-auto">
                      <div>
                        <div className="-mx-4 sm:-mx-8 px-4 sm:px-8 py-4 overflow-x-auto">
                          <div className="inline-block w-full h-[55vh] lg:min-w-full shadow rounded-lg overflow-y-scroll">
                            <div>
                              <table className="min-w-full leading-normal">
                                <thead className=" w-full px-32 sticky top-0">
                                  <tr>
                                    <th className="p-6 border-b-2 border-gray-200 bg-gray-100 dark:bg-dark-tertiary text-left text-xs font-semibold text-gray-600 dark:text-white uppercase tracking-wider">
                                      {"firstname"}
                                    </th>

                                    <th className="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 dark:bg-dark-tertiary  text-left text-xs font-semibold text-gray-600 dark:text-white uppercase md:table-cell tracking-wider">
                                      {"lastname"}
                                    </th>

                                    <th className="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 dark:bg-dark-tertiary  text-left text-xs font-semibold text-gray-600 dark:text-white uppercase tracking-wider">
                                      {"email"}
                                    </th>
                                    {
                                      <th className="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 dark:bg-dark-tertiary  text-left text-xs font-semibold text-gray-600 dark:text-white uppercase tracking-wider">
                                        {"cycle"}
                                      </th>
                                    }
                                    <th className="border-b-2 sm:text-center border-gray-200 bg-gray-100 dark:bg-dark-tertiary  text-left text-xs font-semibold text-gray-600 dark:text-white uppercase tracking-wider">
                                      {"action"}
                                    </th>
                                  </tr>
                                </thead>
                                <tbody className="overflow-y-auto">
                                  {filteredTrainees?.length > 0 ? (
                                    filteredTrainees.map((item: any) =>
                                      item?.delete_at == false ? (
                                        <tr key={item._id}>
                                          <td className="px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-sm">
                                            <div className="flex">
                                              <div className="">
                                                <p className="text-gray-900 text-center dark:text-white whitespace-no-wrap">
                                                  {item.firstName}
                                                </p>
                                              </div>
                                            </div>
                                          </td>
                                          <td className="px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-sm">
                                            <div className="flex items-center">
                                              <div className="">
                                                <p className="text-gray-900 text-center dark:text-white whitespace-no-wrap">
                                                  {item.lastName}
                                                </p>
                                              </div>
                                            </div>
                                          </td>

                                          <td className="px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-sm">
                                            <div className="flex items-center">
                                              <div className="">
                                                <p className="text-gray-900 items-center dark:text-white whitespace-no-wrap">
                                                  {item.email}
                                                </p>
                                              </div>
                                            </div>
                                          </td>

                                          <td className="px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-sm">
                                            <div className="flex items-center">
                                              <div className="">
                                                <p className="text-gray-900 items-center dark:text-white whitespace-no-wrap">
                                                  {item.cycle_id
                                                    ? item.cycle_id.name
                                                    : "-"}
                                                </p>
                                              </div>
                                            </div>
                                          </td>

                                          <td>
                                            <div>
                                              <HiDotsVertical
                                                className=" text-black dark:text-white text-3xl ml-6 font-size-6 cursor-pointer"
                                                onClick={(e: any) => {
                                                  e.preventDefault();
                                                  onSubmitHandler(item._id);
                                                }}
                                              />
                                              <div
                                                className={`${
                                                  moredrop === item._id
                                                    ? "block"
                                                    : "hidden"
                                                } absolute  bg-white dark:bg-dark-tertiary  dark:text-white text-base z-50 list-none divide-y divide-gray-100 rounded shadow my-4`}
                                                id="dropdown"
                                              >
                                                <ul
                                                  className="py-1"
                                                  aria-labelledby="dropdown"
                                                >
                                                  <li>
                                                    <Link
                                                      to={`/admin/trainee-applicant/${item._id}/edit`}
                                                      className="text-sm hover:bg-gray-100 text-gray-700 dark:hover:bg-gray-500 dark:text-white  block px-4 py-2"
                                                    >
                                                      Edit
                                                    </Link>
                                                  </li>
                                                  <li>
                                                    <Link
                                                      to={`/admin/trainee-applicant-details/${item._id}`}
                                                      className="text-sm hover:bg-gray-100 text-gray-700  dark:text-white   dark:hover:bg-gray-500 block px-4 py-2"
                                                    >
                                                      View
                                                    </Link>
                                                  </li>
                                                  <li>
                                                    <div
                                                      className="text-sm hover:bg-gray-100 text-gray-700  dark:hover:bg-gray-500 dark:text-white  block px-4 py-2"
                                                      onClick={(e: any) => {
                                                        e.preventDefault();
                                                        onSubmitHandlesoft(
                                                          item._id
                                                        );
                                                      }}
                                                    >
                                                      Soft Delete
                                                    </div>
                                                  </li>
                                                  <li>
                                                    <div
                                                      className="text-sm hover:bg-gray-100 text-gray-700   dark:hover:bg-gray-500 dark:text-white  block px-4 py-2"
                                                      onClick={(e: any) => {
                                                        e.preventDefault();
                                                        onSubmitHandle(
                                                          item._id
                                                        );
                                                      }}
                                                    >
                                                      Hard Delete
                                                    </div>
                                                  </li>
                                                </ul>
                                              </div>
                                            </div>
                                          </td>
                                        </tr>
                                      ) : null
                                    )
                                  ) : (
                                    <tr>
                                      <td
                                        colSpan={5}
                                        className="text-center text-white"
                                      >
                                        No trainees found
                                      </td>
                                    </tr>
                                  )}
                                </tbody>
                              </table>
                            </div>
                          </div>
                        </div>
                      </div>
                      <div className="py-3 flex items-center text-center justify-center pt-10">
                        <div className="pb-1">
                          <label htmlFor="" className="dark:text-zinc-100">
                            rows per page
                          </label>
                          <Select
                            menuPlacement="top"
                            className="sm:text-sm  w-13 rounded-bt-rd absolute active dark:bg-dark-frame-bg"
                            options={[
                              { value: "10", label: "10" },
                              { value: "50", label: "50" },
                              { value: "100", label: "100" },
                              { value: "500", label: "500" },
                              { value: "1000", label: "1000" },
                            ]}
                            defaultValue={{ value: "", label: "10" }}
                            onChange={(e: any) =>
                              setItemsPerPage(Number(e?.value))
                            }
                          />
                        </div>
                        <div
                          className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"
                          aria-label="Pagination"
                        >
                          <div
                            className="relative z-0 inline-flex items-center ml-auto mr-auto  rounded-[2px] shadow-sm space-x-2"
                            aria-label="Pagination"
                          >
                            <button
                              className="my-0 mx-[5px] px-[5px] py-0 text-[#333] h-[38px] border-solid border-[1px]  border-[#a8a8a8] dark:disabled:bg-[#485970]  disabled:bg-[#E7E7E7] disabled:text-[#a8a8a8] dark:text-zinc-100"
                              onClick={() => setPage(0)}
                              disabled={page <= 0}
                            >
                              <AiIcons.AiOutlineDoubleLeft />
                            </button>
                            <button
                              className=" border-solid border-[1px]  border-[#a8a8a8] py-0 px-[10px] text-[#333] rounded-l-[5px] h-[38px] disabled:bg-[#E7E7E7] disabled:text-[#a8a8a8] dark:text-zinc-100"
                              onClick={() => setPage(page - 1)}
                              disabled={page <= 0}
                            >
                              <AiIcons.AiOutlineLeft />
                            </button>
                            {paginationRange?.map((pageNumber, idx) => {
                              if (pageNumber === DOTS) {
                                return (
                                  <div
                                    key={idx}
                                    className="dark:text-zinc-100 md:hidden"
                                  >
                                    ...
                                  </div>
                                );
                              }

                              if (pageNumber - 1 === page) {
                                return (
                                  <button
                                    key={idx}
                                    className={`border-solid border-[1px] cursor-pointer border-[#a8a8a8] bg-[#fff] min-w-[35px] h-[38px]  active:bg-[#333] active:text-[#fff]-500 rounded-[2px] md:hidden
                        ${page && "bg-[#d6dfdf] text-black"} 
                        ${page === 0 && "bg-[#d6dfdf] text-black"} 
                          `}
                                    onClick={() => setPage(pageNumber - 1)}
                                  >
                                    {pageNumber}
                                  </button>
                                );
                              }

                              return (
                                <button
                                  key={idx}
                                  className={`border-solid border-[1px]  cursor-pointer border-[#a8a8a8] bg-[#fff] min-w-[35px] h-[38px]  active:bg-[#333] active:text-[#fff]-500 rounded-[2px] md:hidden`}
                                  onClick={() => setPage(pageNumber - 1)}
                                >
                                  {pageNumber}
                                </button>
                              );
                            })}
                            <button
                              className=" border-solid border-[1px]  border-[#a8a8a8] py-0 px-[10px] text-[#333] rounded-r-[5px] h-[38px]  disabled:bg-[#E7E7E7] disabled:text-[#a8a8a8] dark:disabled:bg-[#485970] dark:text-zinc-100"
                              onClick={() => setPage(page + 1)}
                              disabled={
                                page >=
                                Math.ceil(
                                  traines?.pagination.totalItems / itemsPerPage
                                ) -
                                  1
                              }
                            >
                              <AiIcons.AiOutlineRight />
                            </button>
                            <button
                              className="my-0 mx-[5px] px-[5px] py-0 text-[#333] h-[38px] border-solid border-[1px]  border-[#a8a8a8]  disabled:bg-[#E7E7E7] disabled:text-[#a8a8a8] dark:disabled:bg-[#485970] dark:text-zinc-100"
                              onClick={() =>
                                setPage(
                                  Math.ceil(
                                    traines?.pagination.totalItems /
                                      itemsPerPage
                                  ) - 1
                                )
                              }
                              disabled={
                                page >=
                                Math.ceil(
                                  traines?.pagination.totalItems / itemsPerPage
                                ) -
                                  1
                              }
                            >
                              <AiIcons.AiOutlineDoubleRight />
                            </button>
                          </div>
                        </div>
                      </div>
                    </div>
                    {/* //pagination */}
                  </div>
                  )}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

// export default AddTrainee;

const mapState = (state: any) => ({
  delettraine: state.deletetraine,
  softdeletettraine: state.softdeletetraine,
  traines: state.traine,
  cycles: state.cycles,
});

export default connect(mapState, {
  deletetraine,
  softdeletetraine,
  fetchtraine,
  getAllCycles,
  createtraine,
})(AddTrainee);