atlp-rwanda/atlp-devpulse-fn

View on GitHub
src/pages/Applications.tsx

Summary

Maintainability
F
A
-3 days
Test Coverage
import React, { useEffect, useState } from "react";
import { ToastContainer } from "react-toastify";
import * as icons from "react-icons/ai";
import { Link } from "react-router-dom";
import Select from "react-select";
import * as AiIcons from "react-icons/ai";
import {
  deleteApplication,
  getMyApplications,
  getSingleApplication,
} from "../redux/actions/applications";
import { useAppDispatch } from "../hooks/hooks";
import { useNavigate } from "react-router-dom";
import { connect, useSelector } from "react-redux";
import { HiDotsVertical } from "react-icons/hi";
import Box from "@mui/material/Box";
import { useCustomPagination } from "components/Pagination/useCustomPagination";
import { useTheme } from "../hooks/darkmode";
type Props = {};

interface Update {
  id: string;
  open: boolean;
}
const Applications = (props: any) => {
  const dispatch = useAppDispatch();
  const navigate = useNavigate();

  const { myApplications, currentApplication, loading } = props;
  console.log("My Applications:", myApplications);

  const [moredrop, setmoredrop] = useState("");
  const [filter, setFilter] = useState("submitted");
  const [pagination, setPagination] = useState({
    pageSize: 5,
    page: 1,
  });
  const { theme, setTheme } = useTheme();
  const customTheme = (theme: any) => {
    return {
      ...theme,
      colors: {
        ...theme.colors,
        text: "light-gray",
        primary25: "#E5E7EB",
        primary: "#d6dfdf",
        neutral0: "white",
      },
    };
  };

  const darkTheme = (theme: any) => {
    return {
      ...theme,
      colors: {
        primary25: "#404657",
        primary: "#d6dfdf",
        neutral0: "#293647",
      },
    };
  };
  const [deleteWarn, setDeleteWarn] = useState<Update>({
    id: "",
    open: false,
  });

  const [displayApplication, setDisplayApplication] = useState({
    open: false,
  });
  const handleViewApplication = (application_id: any) => {
    try {
      dispatch(getSingleApplication(application_id));
    } catch (e) {
      console.log(e);
    }
  };
  const handleMoreOptions = (item_id: any) => {
    if (!moredrop) setmoredrop(item_id);
    if (moredrop) setmoredrop("");
  };

  const handleDeleteApplication = (item_id: any) => {
    try {
      dispatch(deleteApplication(item_id));
    } catch (e) {
      console.log(e);
    }
  };
  const handleDateOfSubmission = (dateString: any) => {
    const datePart = dateString.slice(0, dateString.indexOf("T"));
    return datePart;
  };
  useEffect(() => {
    const result = dispatch(getMyApplications(filter, pagination));

    if (
      result.error === "Oops! You must be logged in to proceed" ||
      result.error === "Session expired. Please login again to continue."
    ) {
      setTimeout(() => {
        navigate("/login");
      }, 5000);
    }
  }, [filter, pagination, dispatch]);

  return (
    <>
      <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="flex items-left px-8 pt-1">
                  <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">
                      <Select
                        className="sm:text-sm w-full sm:w-40 rounded-bt-rd dark:text-ltb"
                        options={[{ value: "", label: "Select by" }]}
                        defaultValue={{ value: "", label: "Select by" }}
                        theme={theme ? customTheme : darkTheme}
                      />
                      <div className="w-full sm:w-auto flex-grow">
                        <div className="relative">
                          <input
                            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-9 pr-4 focus:outline-none focus:ring-2 focus:ring-primary dark:focus:ring-[#56C870] text-sm"
                            placeholder="Search"
                            type="text"
                            name="search"
                          />
                          <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>
                </div>
                {/* Filter Bar */}
                <div>
                  <ul className=" flex dark:text-white semi-md:space-x-5 p-5  text-sm  lg:px-8 semi-md:flex-row sm:flex-col ">
                    <li
                      className={`${
                        filter === "submitted"
                          ? "underline underline-offset-8 decoration-green"
                          : ""
                      } cursor-pointer`}
                      onClick={() => setFilter("submitted")}
                    >
                      Submitted
                    </li>
                    <li
                      className={`${
                        filter === "withdrawn"
                          ? "underline underline-offset-8 decoration-green"
                          : ""
                      } cursor-pointer`}
                      onClick={() => setFilter("withdrawn")}
                    >
                      Withdrawn
                    </li>
                  </ul>
                </div>

                <div className="px-8">
                  <div className="bg-white  dark:bg-dark-bg shadow-lg px-7 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">
                          <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">
                                  {"Title"}
                                </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">
                                  {'Description'}
                                </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">
                                  {"Date of submission"}
                                </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">
                                    {"status"}
                                  </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">
                              {loading ? (
                                <tr>
                                  <td
                                    colSpan={4}
                                    className="text-center px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-lg text-gray-500"
                                  >
                                    Processing...
                                  </td>
                                </tr>
                              ) : myApplications.data?.totalCount === 0 ? (
                                <tr>
                                  <td
                                    colSpan={4}
                                    className="text-center px-5 py-5 border-b border-gray-200 dark:border-dark-tertiary text-lg text-[#fff]"
                                  >
                                    Found 0 applications.
                                  </td>
                                </tr>
                              ) : (
                                myApplications.data?.applications.map(
                                  (item: any) => (
                                    <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.associatedForm.title}
                                            </p>
                                          </div>
                                        </div>
                                      </td>
                                      {/* Other table data cells */}
                                      <td>
                                        <div>
                                          <HiDotsVertical
                                            className="text-black dark:text-white text-3xl ml-6 font-size-6 cursor-pointer"
                                            onClick={(e: any) => {
                                              e.preventDefault();
                                              handleMoreOptions(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>
                                                <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();
                                                    setDisplayApplication({
                                                      open: true,
                                                    });
                                                    handleViewApplication(
                                                      item?._id
                                                    );
                                                  }}
                                                >
                                                  View
                                                </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();
                                                    setDeleteWarn({
                                                      id: item?._id,
                                                      open: true,
                                                    });
                                                  }}
                                                >
                                                  Withdraw
                                                </div>
                                              </li>
                                            </ul>
                                          </div>
                                        </div>
                                      </td>
                                    </tr>
                                  )
                                )
                              )}
                            </tbody>
                          </table>
                          {deleteWarn.open && (
                            <div
                              className={`h-screen w-screen z-50 bg-black bg-opacity-10 backdrop-blur-sm absolute flex items-center justify-center  px-4 top-0 left-0 ${
                                deleteWarn.open === true ? "block" : "hidden"
                              }`}
                            >
                              <Box className="absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] rounded-[5px] dark:bg-dark-bg bg-[#f0f0f0]">
                                <div className="block w-[300px] h-[200px] dark:bg-dark-bg  dark:text-white bg-[#f0f0f0] rounded-[5px]">
                                  <div className="text-center">
                                    <icons.AiFillExclamationCircle className="w-[40px] my-[20px] mx-auto text-[40px]" />
                                    <p className="w-[60%] m-auto font-bold">
                                      Are you sure you want to withdraw this
                                      application?
                                    </p>
                                  </div>
                                  <div className="flex flex-wrap my-[20px] mx-0">
                                    <button
                                      className="block text-white bg-[#940000] my-[10px] mx-auto rounded-[5px] w-[100px] h-[40px]"
                                      onClick={() => {
                                        console.log(deleteWarn.id);
                                        handleDeleteApplication(deleteWarn?.id);
                                        setDeleteWarn({
                                          ...deleteWarn,
                                          open: false,
                                        });
                                        setmoredrop("");
                                      }}
                                    >
                                      Withdraw
                                    </button>
                                    <button
                                      className="h-[40px] w-[100px] block rounded-[5px] my-[10px] mx-auto bg-[#ABB8C3] text-[#fff]"
                                      onClick={() => {
                                        setDeleteWarn({
                                          ...deleteWarn,
                                          open: false,
                                        });
                                        setmoredrop("");
                                      }}
                                    >
                                      Cancel
                                    </button>
                                  </div>
                                </div>
                              </Box>
                            </div>
                          )}
                          {displayApplication.open && (
                            <div
                              className={`h-screen w-screen z-50 bg-black bg-opacity-10 backdrop-blur-sm absolute flex items-center justify-center  px-4 top-0 left-0 ${
                                displayApplication.open === true
                                  ? "block"
                                  : "hidden"
                              }`}
                            >
                              <Box className="absolute top-[55%] left-[50%] translate-x-[-50%] translate-y-[-50%] rounded-[5px] dark:bg-dark-bg bg-[#f0f0f0]">
                                <div className="flex flex-col w-[100%] h-[100%] dark:bg-dark-tertiary  dark:text-white bg-[#f0f0f0] rounded-[5px] px-10">
                                  <div className="absolute right-0 top-0">
                                    <icons.AiOutlineClose
                                      className="mx-2 my-2  text-xl cursor-pointer hover:text-red-600"
                                      onClick={() =>
                                        setDisplayApplication({
                                          ...displayApplication,
                                          open: false,
                                        })
                                      }
                                    />
                                  </div>
                                  <div className="text-center">
                                    <p className="w-[80%] m-auto font-bold underline px-3 py-3 text-lg">
                                      {
                                        currentApplication.data?.associatedForm
                                          .title
                                      }
                                    </p>
                                  </div>
                                  <div className=" flex flex-col space-y-5  py-10">
                                    {/* FirstName */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">
                                        First Name:
                                      </p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.firstName}
                                      </p>
                                    </div>
                                    {/* LastName */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">
                                        Last Name:
                                      </p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.lastName}
                                      </p>
                                    </div>
                                    {/* Email */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">Email:</p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.email}
                                      </p>
                                    </div>
                                    {/* Address */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">Address:</p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.address}
                                      </p>
                                    </div>
                                    {/* Phone Number */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">
                                        Phone Number:
                                      </p>
                                      <p className="font-sans">
                                        {currentApplication.data?.telephone}
                                      </p>
                                    </div>
                                    {/* Gender */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">Gender:</p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.gender}
                                      </p>
                                    </div>
                                    {/* Interview Date */}
                                    <div className="flex space-x-3 md:space-x-2">
                                      <p className="font-semibold">
                                        Availability Date For Inteview:
                                      </p>
                                      <p className="font-sans">
                                        {
                                          currentApplication.data
                                            ?.availability_for_interview
                                        }
                                      </p>
                                    </div>
                                    {/* Submitted At */}
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">
                                        Submitted At:
                                      </p>
                                      <p className="font-sans">
                                        {currentApplication.data
                                          ?.dateOfSubmission !== undefined
                                          ? handleDateOfSubmission(
                                              currentApplication.data
                                                ?.dateOfSubmission
                                            )
                                          : null}
                                      </p>
                                    </div>
                                    <div className="flex space-x-3">
                                      <p className="font-semibold">Status:</p>
                                      <p className="font-sans">
                                        {" "}
                                        {currentApplication.data?.status}{" "}
                                      </p>
                                    </div>
                                  </div>
                                </div>
                              </Box>
                            </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: "5", label: "5" },
                            { value: "50", label: "50" },
                            { value: "100", label: "100" },
                            { value: "500", label: "500" },
                            { value: "1000", label: "1000" },
                          ]}
                          defaultValue={{ value: "", label: "5" }}
                          onChange={(e: any) =>
                            setPagination({
                              page: 1,
                              pageSize: 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=" cursor-pointer disabled:cursor-default 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={() =>
                              setPagination({
                                page: 1,
                                pageSize: pagination.pageSize,
                              })
                            }
                            disabled={pagination.page <= 1}
                          >
                            <AiIcons.AiOutlineDoubleLeft />
                          </button>
                          <button
                            className=" cursor-pointer disabled:cursor-default 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 dark:disabled:bg-[#485970]"
                            onClick={() =>
                              setPagination({
                                page: pagination.page - 1,
                                pageSize: pagination.pageSize,
                              })
                            }
                            disabled={pagination.page <= 1}
                          >
                            <AiIcons.AiOutlineLeft />
                          </button>

                          <button
                            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`}
                          >
                            {pagination.page}
                          </button>
                          <button
                            className=" cursor-pointer disabled:cursor-default 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={() =>
                              setPagination({
                                page: pagination.page + 1,
                                pageSize: pagination.pageSize,
                              })
                            }
                            disabled={
                              pagination.page >=
                              Math.ceil(
                                myApplications?.data?.totalCount /
                                  pagination.pageSize
                              )
                            }
                          >
                            <AiIcons.AiOutlineRight />
                          </button>
                          <button
                            className=" cursor-pointer disabled:cursor-default 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={() =>
                              setPagination({
                                pageSize: pagination.pageSize,
                                page: Math.ceil(
                                  myApplications?.data?.totalCount /
                                    pagination.pageSize
                                ),
                              })
                            }
                            disabled={
                              pagination.page >=
                              Math.ceil(
                                myApplications?.data?.totalCount /
                                  pagination.pageSize
                              )
                            }
                          >
                            <AiIcons.AiOutlineDoubleRight />
                          </button>
                        </div>
                      </div>
                    </div>
                  </div>
                  {/* //pagination */}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

// export default Applications;

const mapState = (state: any) => ({
  myApplications: state.myApplications,
  currentApplication: state.currentApplication,
  loading: state.myApplications.loading,
});

export default connect(mapState, {
  getMyApplications,
  deleteApplication,
  getSingleApplication,
})(Applications);