marco.pms.web/src/pages/project/ProjectPage.jsx

212 lines
7.7 KiB
JavaScript

import React, { createContext, useContext, useEffect, useState } from "react";
import Breadcrumb from "../../components/common/Breadcrumb";
import {
ITEMS_PER_PAGE,
MANAGE_PROJECT,
PROJECT_STATUS,
} from "../../utils/constants";
import ProjectListView from "../../components/Project/ProjectListView";
import GlobalModel from "../../components/common/GlobalModel";
import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
import ProjectCardView from "../../components/Project/ProjectCardView";
import usePagination from "../../hooks/usePagination";
import { useProjects } from "../../hooks/useProjects";
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { SpinnerLoader } from "../../components/common/Loader";
import { useServiceProjects } from "../../hooks/useServiceProject";
import ManageServiceProject from "../../components/ServiceProject/ManageServiceProject";
import ProjectsDisplay from "./ProjectsDisplay";
import ServiceProjectDisplay from "../ServiceProject/ServiceProjectDisplay";
const ProjectContext = createContext();
export const useProjectContext = () => {
const context = useContext(ProjectContext);
if (!context) {
throw new Error("useProjectContext must be used within an ProjectProvider");
}
return context;
};
const ProjectPage = () => {
const [manageProject, setMangeProject] = useState({
isOpen: false,
project: null,
});
const [manageServiceProject, setManageServiceProject] = useState({
isOpen: false,
project: null,
});
const [projectList, setProjectList] = useState([]);
const [listView, setListView] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [coreProjects, setCoreProjects] = useState(() => {
const storedValue = sessionStorage.getItem('whichProjectDisplay');
return storedValue === 'true';
});
const HasManageProject = useHasUserPermission(MANAGE_PROJECT);
const [currentPage, setCurrentPage] = useState(1);
const [selectedStatuses, setSelectedStatuses] = useState(
PROJECT_STATUS.map((s) => s.id)
);
const handleStatusChange = (statusId) => {
setSelectedStatuses((prev) =>
prev.includes(statusId)
? prev.filter((id) => id !== statusId)
: [...prev, statusId]
);
};
const contextDispatcher = {
setMangeProject,
setManageServiceProject,
manageProject,
manageServiceProject,
};
const handleToggleProject = (value) => {
setCoreProjects(value);
sessionStorage.setItem("whichProjectDisplay", String(value));
};
return (
<ProjectContext.Provider value={contextDispatcher}>
<div className="container-fluid">
<Breadcrumb
data={[
{ label: "Home", link: "/dashboard" },
{ label: "Projects", link: null },
]}
/>
<div className="card cursor-pointer mb-5">
<div className="card-body py-3 px-6 pb-1">
<div className="d-flex flex-wrap justify-content-between align-items-center">
{/* LEFT SIDE — DATE TOGGLE BUTTONS */}
<div className="mb-2">
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
{/* Service Project Button */}
<button
type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${!coreProjects ? "btn-primary text-white" : ""
}`}
onClick={() => handleToggleProject(false)}
>
Service Project
</button>
{/* Organization Project Button */}
<button
type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${coreProjects ? "btn-primary text-white" : ""
}`}
onClick={() => handleToggleProject(true)}
>
Infra Project
</button>
</div>
</div>
{/* RIGHT SIDE — SEARCH + CARD/LIST + DROPDOWN */}
<div className="d-flex flex-wrap align-items-center justify-content-end">
{/* Search */}
<div className="me-2" style={{ minWidth: "200px" }}>
<input
type="search"
className="form-control form-control-sm"
placeholder="Search projects..."
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
setCurrentPage(1);
}}
/>
</div>
{/* Card/List Buttons */}
<div className="d-flex gap-2">
<button
type="button"
className={`btn btn-sm p-1 ${!listView ? "btn-primary" : "btn-outline-primary"}`}
onClick={() => setListView(false)}
title="Card View"
>
<i className="bx bx-grid-alt fs-5"></i>
</button>
<button
type="button"
className={`btn btn-sm p-1 ${listView ? "btn-primary" : "btn-outline-primary"}`}
onClick={() => setListView(true)}
title="List View"
>
<i className="bx bx-list-ul fs-5"></i>
</button>
</div>
{/* Dropdown Filter */}
<div className="dropdown me-2">
<a
className="dropdown-toggle hide-arrow cursor-pointer p-1"
data-bs-toggle="dropdown"
aria-expanded="false"
title="Filter"
>
<i className="bx bx-slider-alt fs-5"></i>
</a>
<ul className="dropdown-menu p-2 text-capitalize">
{PROJECT_STATUS.map(({ id, label }) => (
<li key={id}>
<div className="form-check">
<input
className="form-check-input"
type="checkbox"
checked={selectedStatuses.includes(id)}
onChange={() => handleStatusChange(id)}
/>
<label className="form-check-label">{label}</label>
</div>
</li>
))}
</ul>
</div>
{HasManageProject && (
<button
type="button"
className="btn btn-primary btn-sm d-flex align-items-center my-2"
onClick={() =>
coreProjects
? setMangeProject({ isOpen: true, Project: null }) // Organization Project → Infra
: setManageServiceProject({ isOpen: true, Project: null }) // Service Project
}
>
<i className="bx bx-plus-circle me-2"></i>
New Project
</button>
)}
</div>
</div>
</div>
</div>
{coreProjects ? <ProjectsDisplay listView={listView}
searchTerm={searchTerm}
selectedStatuses={selectedStatuses}
handleStatusChange={handleStatusChange} currentPage={currentPage}
setCurrentPage={setCurrentPage} /> : <ServiceProjectDisplay listView={listView} searchTerm={searchTerm}
selectedStatuses={selectedStatuses} />}
</div>
</ProjectContext.Provider>
);
};
export default ProjectPage;