282 lines
9.4 KiB
JavaScript
282 lines
9.4 KiB
JavaScript
import React, { useState } from "react";
|
|
import { MANAGE_PROJECT, PROJECT_STATUS } from "../../utils/constants";
|
|
import { useProjects } from "../../hooks/useProjects";
|
|
import { formatNumber, formatUTCToLocalTime } from "../../utils/dateUtils";
|
|
import ProgressBar from "../common/ProgressBar";
|
|
import {
|
|
getProjectStatusColor,
|
|
getProjectStatusName,
|
|
} from "../../utils/projectStatus";
|
|
import { useDispatch } from "react-redux";
|
|
import { setProjectId } from "../../slices/localVariablesSlice";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
|
import { useProjectContext } from "../../pages/project/ProjectPage";
|
|
import usePagination from "../../hooks/usePagination";
|
|
|
|
const ProjectListView = ({
|
|
currentItems,
|
|
selectedStatuses,
|
|
handleStatusChange,
|
|
setCurrentPage,
|
|
totalPages,
|
|
isLoading,
|
|
}) => {
|
|
const dispatch = useDispatch();
|
|
const navigate = useNavigate();
|
|
const { setMangeProject } = useProjectContext();
|
|
// const { data, isLoading, isError, error } = useProjects();
|
|
// check Permissions
|
|
// const canManageProject = useHasUserPermission(MANAGE_PROJECT);
|
|
|
|
const projectColumns = [
|
|
{
|
|
key: "projectName",
|
|
label: "Project Name",
|
|
className: "text-start py-3",
|
|
getValue: (p) => (
|
|
<div
|
|
className="text-primary cursor-pointer fw-bold py-3"
|
|
onClick={() => {
|
|
dispatch(setProjectId(p.id));
|
|
navigate(`/projects/details`);
|
|
}}
|
|
>
|
|
{p.shortName ? `${p.name} (${p.shortName})` : p.name}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: "contactPerson",
|
|
label: "Contact Person",
|
|
className: "text-start small",
|
|
getValue: (p) => `${p?.contactPerson ?? ""}`.trim() || "N/A",
|
|
},
|
|
{
|
|
key: "startDate",
|
|
label: "Start Date",
|
|
className: "text-center small",
|
|
getValue: (p) => formatUTCToLocalTime(p?.startDate) || "N/A",
|
|
},
|
|
{
|
|
key: "deadline",
|
|
label: "Deadline",
|
|
className: "text-center small",
|
|
getValue: (p) => formatUTCToLocalTime(p?.endDate) || "N/A",
|
|
},
|
|
{
|
|
key: "task",
|
|
label: "Task",
|
|
colSpan: 2,
|
|
className: "text-center small",
|
|
getValue: (p) => formatNumber(p?.plannedWork) || "0",
|
|
},
|
|
{
|
|
key: "progress",
|
|
label: "Progress",
|
|
className: "text-start small",
|
|
|
|
getValue: (p) => (
|
|
<ProgressBar
|
|
plannedWork={p.plannedWork}
|
|
completedWork={p.completedWork}
|
|
className="mb-0"
|
|
height="6px"
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
key: "status",
|
|
label: "Status",
|
|
className: "text-center small",
|
|
isFilter: true,
|
|
customRender: (_, selectedStatuses, handleStatusChange) => (
|
|
<div className="dropdown">
|
|
<a
|
|
className="dropdown-toggle hide-arrow cursor-pointer"
|
|
data-bs-toggle="dropdown"
|
|
aria-expanded="false"
|
|
>
|
|
Status <i className="bx bx-filter bx-sm"></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>
|
|
),
|
|
getValue: (p) => (
|
|
<span className={`badge ${getProjectStatusColor(p.projectStatusId)}`}>
|
|
{getProjectStatusName(p.projectStatusId)}
|
|
</span>
|
|
),
|
|
},
|
|
];
|
|
|
|
// const handleViewActivities = (project) => {
|
|
// dispatch(setProjectId(project));
|
|
// navigate(`/activities/records?project=${project}`);
|
|
// };
|
|
|
|
const handleMoveDetails = (project) => {
|
|
dispatch(setProjectId(project));
|
|
localStorage.setItem("lastActiveProjectTab", "profile")
|
|
navigate("/projects/details");
|
|
};
|
|
return (
|
|
<div className="card page-min-h py-4 px-6 shadow-sm">
|
|
<div className="table-responsive text-nowrap">
|
|
<table className="table table-hover align-middle m-0">
|
|
<thead className="border-bottom">
|
|
<tr>
|
|
{projectColumns.map((col) => (
|
|
<th key={col.key} colSpan={col.colSpan} className={col.className}>
|
|
{col.label}
|
|
</th>
|
|
))}
|
|
<th className="text-center py-3">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{currentItems?.map((project) => (
|
|
<tr key={project.id}>
|
|
{projectColumns.map((col) => (
|
|
<td
|
|
key={col.key}
|
|
colSpan={col.colSpan}
|
|
className={`${col.className} py-5`}
|
|
style={{ paddingTop: "20px", paddingBottom: "20px" }}
|
|
>
|
|
{col.getValue
|
|
? col.getValue(project)
|
|
: project[col.key] || "N/A"}
|
|
</td>
|
|
))}
|
|
<td className={`mx-2 ${"d-sm-table-cell"}`}>
|
|
<div className="dropdown z-2">
|
|
<button
|
|
type="button"
|
|
className="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0"
|
|
data-bs-toggle="dropdown"
|
|
aria-expanded="false"
|
|
>
|
|
<i
|
|
className="bx bx-dots-vertical-rounded bx-sm text-muted"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-offset="0,8"
|
|
data-bs-placement="top"
|
|
data-bs-custom-class="tooltip-dark"
|
|
title="More Action"
|
|
></i>
|
|
</button>
|
|
<ul className="dropdown-menu dropdown-menu-end">
|
|
<li onClick={() => handleMoveDetails(project.id)}>
|
|
<a
|
|
aria-label="click to View details"
|
|
className="dropdown-item cursor-pointer"
|
|
>
|
|
<i className="bx bx-detail me-2"></i>
|
|
<span className="align-left">View details</span>
|
|
</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a
|
|
className="dropdown-item cursor-pointer"
|
|
onClick={() =>
|
|
setMangeProject({
|
|
isOpen: true,
|
|
Project: project.id,
|
|
})
|
|
}
|
|
>
|
|
<i className="bx bx-pencil me-2"></i>
|
|
<span className="align-left">Modify</span>
|
|
</a>
|
|
</li>
|
|
{/* <li onClick={() => handleViewActivities(project.id)}>
|
|
<a className="dropdown-item cursor-pointer">
|
|
<i className="bx bx-task me-2"></i>
|
|
<span className="align-left">Activities</span>
|
|
</a>
|
|
</li> */}
|
|
</ul>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
|
|
{isLoading && (
|
|
<div className="py-4">
|
|
{" "}
|
|
{isLoading && <p className="text-center">Loading...</p>}
|
|
{!isLoading && filteredProjects.length === 0 && (
|
|
<p className="text-center text-muted">No projects found.</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
{!isLoading && currentItems.length === 0 && (
|
|
<div className="py-6">
|
|
<p className="text-center text-muted">No projects found.</p>
|
|
</div>
|
|
)}
|
|
{!isLoading && totalPages > 1 && (
|
|
<nav>
|
|
<ul className="pagination pagination-sm justify-content-end py-2">
|
|
<li className={`page-item ${currentPage === 1 && "disabled"}`}>
|
|
<button
|
|
className="page-link"
|
|
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
|
>
|
|
«
|
|
</button>
|
|
</li>
|
|
{[...Array(totalPages)].map((_, i) => (
|
|
<li
|
|
key={i}
|
|
className={`page-item ${currentPage === i + 1 && "active"}`}
|
|
>
|
|
<button
|
|
className="page-link"
|
|
onClick={() => setCurrentPage(i + 1)}
|
|
>
|
|
{i + 1}
|
|
</button>
|
|
</li>
|
|
))}
|
|
<li
|
|
className={`page-item ${currentPage === totalPages && "disabled"
|
|
}`}
|
|
>
|
|
<button
|
|
className="page-link"
|
|
onClick={() =>
|
|
setCurrentPage((p) => Math.min(totalPages, p + 1))
|
|
}
|
|
>
|
|
»
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ProjectListView;
|