crane-cloud/frontend

View on GitHub
src/components/ProjectListing/ProjectList.js

Summary

Maintainability
C
1 day
Test Coverage
F
0%
import React, { useState, useEffect, useCallback } from "react";
import "./ProjectList.css";
import InformationBar from "../../components/InformationBar";
import Header from "../../components/Header";
import getAdminProjectsList from "../../redux/actions/adminProjectsList";
import getUsersList from "../../redux/actions/users";
import Spinner from "../../components/Spinner";
import { useSelector, useDispatch } from "react-redux";
// import { Link } from "react-router-dom";
import usePaginator from "../../hooks/usePaginator";
import Pagination from "../../components/Pagination";
import { handleGetRequest } from "../../apis/apis.js";
import { ReactComponent as SearchButton } from "../../assets/images/search.svg";
import { namedOrganisations } from "../../helpers/projectOrganisations.js";
import { retrieveProjectTypes } from "../../helpers/projecttypes.js";
import { filterGraphData } from "../../helpers/filterGraphData.js";
// import MetricsCard from "../../components/MetricsCard";
import { retrieveMonthNames } from "../../helpers/monthNames.js";
import NewResourceCard from "../../components/NewResourceCard";
import Select from "../../components/Select";
import { useHistory } from "react-router-dom/cjs/react-router-dom.min";
import { Link } from "react-router-dom/cjs/react-router-dom.min";
import { ReactComponent as BackButton } from "../../assets/images/arrow-left.svg";
import {
  projectPieCategories,
  projectGraphCategories,
  projectLists,
} from "../../helpers/projectPieCat";
import {
  Line,
  CartesianGrid,
  XAxis,
  YAxis,
  AreaChart,
  Area,
  Tooltip,
  PieChart,
  Pie,
  Cell,
} from "recharts";
import AppFooter from "../appFooter";

const AdminProjectsOverview = () => {
  const [currentPage, handleChangePage] = usePaginator();
  const dispatch = useDispatch();
  const [word, setWord] = useState("");
  const [feedback, setFeedback] = useState("");
  const [loading, setLoading] = useState(false);
  const [sectionValue, setSectionValue] = useState("Projects");
  const [sectionValue1, setSectionValue1] = useState("Projects");
  const [sectionValue2, setSectionValue2] = useState("");
  const projectTypeCounts = {};
  const projectOrganisationCount = {};
  const [project, setProject] = useState([]);
  const [period, setPeriod] = useState("all");
  const graphDataArray = [];
  const graphData = {};
  const newGraphData = {};
  const newGraphDataArray = [];
  let createPieChartData = [];
  let createNewPieChartData = [];
  let filteredGraphData = [];
  let newFilteredGraphData = [];
  const history = useHistory();

  const COLORS = [
    "#0088FE",
    "#0DBC00",
    "#F9991A",
    "#AE0000",
    "#000000",
    "#800080",
  ];

  const availablePieChartCategories = projectPieCategories();
  const availableGraphCategories = projectGraphCategories();
  const availableProjectListings = projectLists();

  const handleSectionChange = (selectedOption) => {
    const selectedValue = selectedOption.value;
    setSectionValue(selectedValue);
  };

  const handleGraphChange = (selectedOption) => {
    const selectedValue = selectedOption.value;
    setSectionValue1(selectedValue);
  };

  const handleListChange = (selectedOption) => {
    const selectedList = selectedOption.value;
    setSectionValue2(selectedList);
  };

  const { isRetrieved, isRetrieving, projects, pagination } = useSelector(
    (state) => state.adminProjectsReducer
  );

  const AdminProjects = useCallback(
    (page, state = "", keyword = "") =>
      dispatch(getAdminProjectsList(page, keyword, state)),
    [dispatch]
  );

  const getUsersProps = useCallback(() => dispatch(getUsersList), [dispatch]);

  const [users, setUsers] = useState([]);

  const getAllProjects = useCallback(async () => {
    setLoading(true);
    try {
      const response = await handleGetRequest(`/projects`);
      if (response.data.data.projects.length > 0) {
        const totalNumberOfProjects = response.data.data.pagination.total;
        handleGetRequest(`/projects?per_page=${totalNumberOfProjects}`)
          .then((response) => {
            if (response.data.data.projects.length > 0) {
              setProject(response.data.data.projects);
              setLoading(false);
            } else {
              throw new Error("No projects found");
            }
          })
          .catch(() => {
            setFeedback("Failed to fetch all projects, please try again");
          });
      } else {
        setFeedback("No projects found");
      }
    } catch (error) {
      setFeedback("Failed to fetch projects, please try again");
    }
  }, [setProject, setLoading, setFeedback]);

  // create graph data for first graph
  const createGraphData = () => {
    if (!project) {
      return [];
    }

    project.forEach((p) => {
      const date = new Date(p.date_created);
      const year = date.getFullYear();
      const month = parseInt(
        date.toLocaleString("default", { month: "2-digit" }),
        10
      );

      const projectType = p.project_type;
      if (!graphData[year]) {
        graphData[year] = {};
      }
      if (!graphData[year][month]) {
        graphData[year][month] = {};
      }
      if (!graphData[year][month][projectType]) {
        graphData[year][month][projectType] = 1;
      } else {
        graphData[year][month][projectType]++;
      }
    });

    Object.keys(graphData).forEach((year) => {
      Object.keys(graphData[year]).forEach((month) => {
        const monthData = graphData[year][month];
        const totalProjects = Object.values(monthData).reduce(
          (acc, val) => acc + val,
          0
        );
        graphDataArray.push({
          Month: `${month}`,
          Year: year,
          Value: totalProjects,
        });
      });
    });

    return graphDataArray;
  };

  // create graph data for second graph
  const createNewGraphData = () => {
    if (!project) {
      return [];
    }

    project.forEach((p) => {
      const date = new Date(p.date_created);
      const year = date.getFullYear();
      const month = parseInt(
        date.toLocaleString("default", { month: "2-digit" }),
        10
      );

      const projectType = p.project_type;
      if (!newGraphData[year]) {
        newGraphData[year] = {};
      }
      if (!newGraphData[year][month]) {
        newGraphData[year][month] = {};
      }
      if (!newGraphData[year][month][projectType]) {
        newGraphData[year][month][projectType] = 1;
      } else {
        newGraphData[year][month][projectType]++;
      }
    });

    Object.keys(newGraphData).forEach((year) => {
      Object.keys(newGraphData[year]).forEach((month) => {
        const monthData = newGraphData[year][month];

        const personalCount = monthData["Personal"] || 0;
        const researchCount = monthData["Research"] || 0;
        const studentCount = monthData["Student"] || 0;
        const commercialCount = monthData["Commercial"] || 0;
        const charityCount = monthData["Charity"] || 0;
        const otherCount = monthData["Other"] || 0;

        newGraphDataArray.push({
          Month: `${month}`,
          Year: year,
          Personal: personalCount,
          Research: researchCount,
          Student: studentCount,
          Commercial: commercialCount,
          Charity: charityCount,
          Other: otherCount,
        });
      });
    });

    return newGraphDataArray;
  };

  // this function call will creates the graph data for first graph
  createGraphData();

  // this function call will creates the graph data for second graph
  createNewGraphData();

  // these function calls will filter the first & second graph data basing on a particular period
  filteredGraphData = filterGraphData(graphDataArray, period);
  newFilteredGraphData = filterGraphData(newGraphDataArray, period);

  const handleChange = ({ target }) => {
    setPeriod(target.getAttribute("value"));
  };
  const handleProjectFilterAndFetch = useCallback(
    (page, keyword = "") => {
      if (sectionValue2 === "Disabled Projects") {
        AdminProjects(page, "true", keyword);
      } else if (sectionValue2 === "Active Projects") {
        AdminProjects(page, "false", keyword);
      } else {
        AdminProjects(page, "", keyword);
      }
    },
    [AdminProjects, sectionValue2]
  );

  useEffect(() => {
    handleProjectFilterAndFetch(currentPage);
  }, [sectionValue2, currentPage, handleProjectFilterAndFetch]);

  useEffect(() => {
    getUsersProps();
    fetchUsersList();
    handleProjectFilterAndFetch(currentPage);
    getAllProjects();
  }, [getUsersProps, handleProjectFilterAndFetch, getAllProjects, currentPage]);

  const filteredData = project.filter((p) => {
    const allowedProjectTypes = retrieveProjectTypes().map(
      (type) => type.value
    );
    return allowedProjectTypes.includes(p.project_type);
  });

  filteredData.forEach((p) => {
    const projectType = p.project_type;
    if (!projectTypeCounts[projectType]) {
      projectTypeCounts[projectType] = 1;
    } else {
      projectTypeCounts[projectType]++;
    }
  });

  const othersCount = project.length - filteredData.length;

  if (othersCount > 0) {
    projectTypeCounts["Others"] = othersCount;
  }

  const filteredOrganisationData = project.filter((p) => {
    const defaultProjectOrganisations = namedOrganisations().map(
      (organisation) => organisation.value
    );
    return defaultProjectOrganisations.includes(p.organisation);
  });

  filteredOrganisationData.forEach((p) => {
    const projectOrganisation = p.organisation;

    if (!projectOrganisationCount[projectOrganisation]) {
      projectOrganisationCount[projectOrganisation] = 1;
    } else {
      projectOrganisationCount[projectOrganisation]++;
    }
  });

  const otherOrganisationCount =
    project.length - filteredOrganisationData.length;
  if (otherOrganisationCount > 0) {
    projectOrganisationCount["Others"] = otherOrganisationCount;
  }

  const fetchUsersList = () => {
    handleGetRequest("/users")
      .then((response) => {
        if (response.data.data.users.length > 0) {
          let totalNumberOfUsers = response.data.data.pagination.total;
          handleGetRequest("/users?per_page=" + totalNumberOfUsers)
            .then((response) => {
              if (response.data.data.users.length > 0) {
                setUsers(response.data.data.users);
              } else {
                throw new Error("No users found");
              }
            })
            .catch((error) => {
              throw new Error("Failed to fetch all users, please try again");
            });
        } else {
          throw new Error("No users found");
        }
      })
      .catch((error) => {
        throw new Error("Failed to fetch users, please try again");
      });
  };

  const searchThroughProjects = (keyword) => {
    handleChangePage(1);
    handleProjectFilterAndFetch(1, keyword);
  };

  const handleCallbackSearchword = ({ target }) => {
    const { value } = target;
    setWord(value);
    if (value !== "") {
      searchThroughProjects(value);
    }
    if (value === "") {
      handleChangePage(1);
      handleProjectFilterAndFetch(1);
    }
  };

  const getUserName = (id) => {
    let userName = "";
    users.forEach((user) => {
      if (user.id === id) {
        userName = user.name;
      }
    });
    return userName;
  };

  const handlePageChange = (currentPage) => {
    handleChangePage(currentPage);
    handleProjectFilterAndFetch(currentPage);
  };

  createPieChartData = () => {
    const degrees = {};
    if (!projectTypeCounts) {
      return [];
    }
    const totalCount = Object.values(projectTypeCounts).reduce(
      (total, count) => total + count,
      0
    );
    for (const type in projectTypeCounts) {
      const count = projectTypeCounts[type];
      const degree = (count / totalCount) * 100;
      degrees[type] = degree.toFixed(1);
    }
    const pieChartData = Object.entries(degrees).map(([type, degrees]) => ({
      category: type,
      value: parseFloat(degrees),
    }));
    return pieChartData;
  };

  createPieChartData();

  createNewPieChartData = () => {
    const percentage = {};
    if (!projectOrganisationCount) {
      return [];
    }

    const totalCount = Object.entries(projectOrganisationCount).reduce(
      (totalCount, [organisation, countOrganisation]) =>
        totalCount + countOrganisation,
      0
    );
    for (const organisation in projectOrganisationCount) {
      const countOrganisation = projectOrganisationCount[organisation];
      const percentages = (countOrganisation / totalCount) * 100;
      percentage[organisation] = percentages.toFixed(1);
    }

    const newPieChartData = Object.entries(percentage).map(
      ([organisation, percentage]) => ({
        category: organisation,
        value: parseFloat(percentage),
      })
    );
    return newPieChartData;
  };

  createNewPieChartData();

  return (
    <div className="APage">
      <div className="TopRow">
        <Header />
        <InformationBar
          header={
            <span className="ProjectsInformationBarTitle">
              <Link className={`breadcrumb flex_back_link`} to={`/clusters`}>
                <BackButton />
                <div className="back_link">Project Listing</div>
              </Link>
            </span>
          }
          showBtn={false}
        />
      </div>
      <div className="AMainSection">
        <div className="ContentSection">
          <div className="TitleArea">
            <div className="SectionTitle">Project Categories</div>
          </div>
          {loading ? (
            <div className="ResourceSpinnerWrapper">
              <Spinner size="big" />
            </div>
          ) : feedback !== "" ? (
            <div className="NoResourcesMessage">{feedback}</div>
          ) : Object.keys(projectTypeCounts).length > 0 ? (
            <div className="ResourceClusterContainer">
              {Object.keys(projectTypeCounts).map((projectType) => (
                <NewResourceCard
                  key={projectType}
                  title={projectType}
                  count={projectTypeCounts[projectType]}
                />
              ))}
            </div>
          ) : null}

          <div className="TitleArea">
            <div className="SectionTitle">Organisation Categories</div>
          </div>
          {loading ? (
            <div className="ResourceSpinnerWrapper">
              <Spinner size="big" />
            </div>
          ) : feedback !== "" ? (
            <div className="NoResourcesMessage">{feedback}</div>
          ) : Object.keys(projectOrganisationCount).length > 0 ? (
            <div className="ResourceClusterContainer">
              {Object.keys(projectOrganisationCount).map(
                (projectOrganisation) => (
                  <NewResourceCard
                    key={projectOrganisation}
                    title={projectOrganisation}
                    count={projectOrganisationCount[projectOrganisation]}
                  />
                )
              )}
            </div>
          ) : null}

          <div className="TitleArea">
            <div className="SectionTitle">
              Project Categories And PieChart Summary
              <span>
                <Select
                  placeholder="Project Categories"
                  options={availablePieChartCategories}
                  onChange={(selectedOption) =>
                    handleSectionChange(selectedOption)
                  }
                />
              </span>
            </div>
          </div>
          <div className="ChartContainer">
            <div className="VisualArea">
              <div className="VisualAreaContentSection">
                <div className="VisualAreaHeader">
                  <span className="SectionTitle">
                    <div className="ChartDropDown">
                      <Select
                        placeholder="Platform Projects"
                        options={availableGraphCategories}
                        onChange={(selectedOption) =>
                          handleGraphChange(selectedOption)
                        }
                      />
                    </div>
                  </span>
                  <span>
                    <div className="PeriodContainer">
                      <div className="PeriodButtonsSection">
                        <div
                          className={`${
                            period === "3" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="3month"
                          value="3"
                          role="presentation"
                          onClick={handleChange}
                        >
                          3m
                        </div>
                        <div
                          className={`${
                            period === "4" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="4months"
                          value="4"
                          role="presentation"
                          onClick={handleChange}
                        >
                          4m
                        </div>
                        <div
                          className={`${
                            period === "6" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="6months"
                          value="6"
                          role="presentation"
                          onClick={handleChange}
                        >
                          6m
                        </div>
                        <div
                          className={`${
                            period === "8" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="8months"
                          value="8"
                          role="presentation"
                          onClick={handleChange}
                        >
                          8m
                        </div>
                        <div
                          className={`${
                            period === "12" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="1year"
                          value="12"
                          role="presentation"
                          onClick={handleChange}
                        >
                          1y
                        </div>
                        <div
                          className={`${
                            period === "all" && "PeriodButtonActive"
                          } PeriodButton`}
                          name="all"
                          value="all"
                          role="presentation"
                          onClick={handleChange}
                        >
                          all
                        </div>
                      </div>
                    </div>
                  </span>
                </div>
              </div>
              <div className="ChartsArea">
                {sectionValue1 === "Projects" ? (
                  <div>
                    {graphDataArray.length > 0 ? (
                      <AreaChart
                        width={550}
                        height={380}
                        syncId="anyId"
                        data={
                          period !== "all" ? filteredGraphData : graphDataArray
                        }
                      >
                        <Line
                          type="monotone"
                          dataKey="Value"
                          stroke="#8884d8"
                        />
                        <CartesianGrid stroke="#ccc" />
                        <XAxis dataKey="Month" />
                        <XAxis
                          xAxisId={1}
                          dx={10}
                          label={{
                            value: "Time",
                            angle: 0,
                            position: "bottom",
                          }}
                          interval={12}
                          dataKey="Year"
                          tickLine={false}
                          tick={{ fontSize: 12, angle: 0 }}
                        />
                        <CartesianGrid strokeDasharray="3 3" />
                        <YAxis
                          label={{
                            value: "Number of Projects",
                            angle: 270,
                            position: "outside",
                          }}
                          width={100}
                        />
                        <Area
                          type="monotone"
                          dataKey="Value"
                          stroke="#82ca9d"
                          fill="#82ca9d"
                        />
                        <Tooltip
                          labelFormatter={(value) => {
                            const monthNames = retrieveMonthNames();
                            const month = parseInt(value) - 1;
                            return monthNames[month].name;
                          }}
                          formatter={(value) => {
                            return [`${value} projects`];
                          }}
                        />
                      </AreaChart>
                    ) : (
                      <div className="ResourceSpinnerWrapper">
                        <Spinner size="big" />
                      </div>
                    )}
                  </div>
                ) : (
                  <div className="ChartsArea">
                    {newGraphDataArray.length > 0 ? (
                      <AreaChart
                        width={550}
                        height={380}
                        data={
                          period !== "all"
                            ? newFilteredGraphData
                            : newGraphDataArray
                        }
                        margin={{
                          top: 10,
                          right: 30,
                          left: 0,
                          bottom: 0,
                        }}
                      >
                        <CartesianGrid stroke="#ccc" />
                        <XAxis dataKey="Month" />
                        <XAxis
                          xAxisId={1}
                          dx={10}
                          label={{
                            value: "Time",
                            angle: 0,
                            position: "bottom",
                          }}
                          interval={12}
                          dataKey="Year"
                          tickLine={false}
                          tick={{ fontSize: 12, angle: 0 }}
                        />
                        <YAxis
                          label={{
                            value: "Numbers per Project Type",
                            angle: 270,
                            position: "outside",
                          }}
                          width={100}
                        />
                        <Tooltip
                          labelFormatter={(value) => {
                            const monthNames = retrieveMonthNames();
                            const month = parseInt(value) - 1;
                            return monthNames[month].name;
                          }}
                        />
                        <Area
                          type="monotone"
                          dataKey="Personal"
                          stackId="1"
                          stroke="#8884d8"
                          fill="#8884d8"
                        />
                        <Area
                          type="monotone"
                          dataKey="Research"
                          stackId="1"
                          stroke="#82ca9d"
                          fill="#82ca9d"
                        />
                        <Area
                          type="monotone"
                          dataKey="Student"
                          stackId="1"
                          stroke="#ffc658"
                          fill="#ffc658"
                        />
                        <Area
                          type="monotone"
                          dataKey="Commercial"
                          stackId="1"
                          stroke="#ffc999"
                          fill="#ffc999"
                        />
                        <Area
                          type="monotone"
                          dataKey="Charity"
                          stackId="1"
                          stroke="#ffc302"
                          fill="#ffc302"
                        />
                      </AreaChart>
                    ) : (
                      <div className="ResourceSpinnerWrapper">
                        <Spinner size="big" />
                      </div>
                    )}
                  </div>
                )}
              </div>
            </div>

            <div className="VisualArea">
              {sectionValue === "Projects" &&
              Object.keys(projectTypeCounts).length === 0 ? (
                <div className="ResourceSpinnerWrapper">
                  <Spinner size="big" />
                </div>
              ) : Object.keys(projectTypeCounts).length !== 0 ? (
                <>
                  <div className="PieContainer">
                    <div className="ChartColumn">
                      <PieChart width={300} height={300}>
                        <Pie
                          data={createPieChartData()}
                          dataKey="value"
                          nameKey="category"
                          cx="50%"
                          cy="50%"
                          outerRadius={140}
                          paddingAngle={3}
                          fill="#8884d8"
                        >
                          {createPieChartData().map((entry, index) => (
                            <Cell
                              key={`cell-${index}`}
                              fill={COLORS[index % COLORS.length]}
                            />
                          ))}
                        </Pie>
                        <Tooltip />
                      </PieChart>
                    </div>
                    <div className="PercentageColumn">
                      <ul className="KeyItems">
                        {createPieChartData().map((entry, index) => (
                          <>
                            <li key={`list-item-${index}`}>
                              <span
                                style={{ color: COLORS[index % COLORS.length] }}
                              >
                                {entry.category} :{" "}
                              </span>
                              {entry.value} %
                            </li>
                            <hr style={{ width: "100%" }} />
                          </>
                        ))}
                      </ul>
                    </div>
                  </div>
                </>
              ) : null}

              {sectionValue === "Organisations" ? (
                <>
                  <div className="PieContainer">
                    <div className="ChartColumn">
                      <PieChart width={300} height={300}>
                        <Pie
                          data={createNewPieChartData()}
                          dataKey="value"
                          nameKey="category"
                          cx="50%"
                          cy="50%"
                          outerRadius={140}
                          paddingAngle={3}
                          fill="#8884d8"
                        >
                          {createNewPieChartData().map((entry, index) => (
                            <Cell
                              key={`cell-${index}`}
                              fill={COLORS[index % COLORS.length]}
                            />
                          ))}
                        </Pie>
                        <Tooltip />
                      </PieChart>
                    </div>
                    <div className="PercentageColumn">
                      <ul className="KeyItems">
                        {createNewPieChartData().map((entry, index) => (
                          <>
                            <li key={`list-item-${index}`}>
                              <span
                                style={{
                                  color: COLORS[index % COLORS.length],
                                }}
                              >
                                {entry.category} :{" "}
                              </span>
                              {entry.value} %
                            </li>
                            <hr style={{ width: "100%" }} />
                          </>
                        ))}
                      </ul>
                    </div>
                  </div>
                </>
              ) : null}
            </div>
          </div>

          <div className="TitleArea">
            <div className="SectionTitle">
              <span>
                <Select
                  placeholder="Projects Listing"
                  options={availableProjectListings}
                  onChange={(selectedOption) =>
                    handleListChange(selectedOption)
                  }
                />
              </span>
              <span>
                <div className="XSearchBar">
                  <div className="AdminSearchInput">
                    <input
                      type="text"
                      className="searchTerm"
                      name="Searchword"
                      placeholder="Search for project"
                      value={word}
                      onChange={(e) => {
                        handleCallbackSearchword(e);
                      }}
                    />
                    <SearchButton className="SearchIcon" />
                  </div>
                </div>
              </span>
            </div>
          </div>

          <div className="ContentSection">
            <div className="ResourceTable">
              <div
                className={
                  isRetrieving
                    ? "ResourcesTable LoadingResourcesTable"
                    : "ResourcesTable"
                }
              >
                <table>
                  <thead className="uppercase">
                    <tr>
                      <th>name</th>
                      <th>owner</th>
                      <th>description</th>
                      <th>status</th>
                    </tr>
                  </thead>
                  {isRetrieving ? (
                    <tbody>
                      <tr className="TableLoading">
                        <td className="TableTdSpinner">
                          <div className="SpinnerWrapper">
                            <Spinner size="big" />
                          </div>
                        </td>
                      </tr>
                    </tbody>
                  ) : (
                    <tbody>
                      {isRetrieved &&
                        projects !== undefined &&
                        projects.map((project) => (
                          <tr
                            onClick={() => {
                              history.push(
                                `/projects-overview/${project.id}/details`
                              );
                            }}
                            key={projects.indexOf(project)}
                          >
                            <td>{project?.name}</td>
                            <td>{getUserName(project?.owner_id)}</td>
                            <td>{project?.description}</td>
                            <td>
                              <span
                                className={
                                  project?.disabled === false
                                    ? "ProjectStatus"
                                    : "ProjectStatusDisabled"
                                }
                              >
                                {project?.disabled === false
                                  ? "Active"
                                  : "Disabled"}
                              </span>
                            </td>
                          </tr>
                        ))}
                    </tbody>
                  )}
                </table>
                {isRetrieved && projects.length === 0 && (
                  <div className="AdminNoResourcesMessage">
                    <p>No projects available</p>
                  </div>
                )}
                {!isRetrieving && !isRetrieved && (
                  <div className="AdminNoResourcesMessage">
                    <p>
                      Oops! Something went wrong! Failed to retrieve projects.
                    </p>
                  </div>
                )}
              </div>
            </div>
            {pagination?.pages > 1 && (
              <div className="AdminPaginationSection">
                <Pagination
                  total={pagination.pages}
                  current={currentPage}
                  onPageChange={handlePageChange}
                />
              </div>
            )}
          </div>
        </div>
      </div>
      <AppFooter />
    </div>
  );
};

export default AdminProjectsOverview;