Compare commits
No commits in common. "b30f3b8d98a4a58aea03c39e6537c953c222d883" and "148058d1d22430d0c2a314cdade3509b38c5d090" have entirely different histories.
b30f3b8d98
...
148058d1d2
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { getProjectStatusName } from "../../utils/projectStatus";
|
import { ProjectStatus } from "../../utils/projectStatus";
|
||||||
const AboutProject = ({ data }) => {
|
const AboutProject = ({ data }) => {
|
||||||
const [CurrentProject, setCurrentProject] = useState(data);
|
const [CurrentProject, setCurrentProject] = useState(data);
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ const AboutProject = ({ data }) => {
|
|||||||
<li className="d-flex align-items-center mb-2">
|
<li className="d-flex align-items-center mb-2">
|
||||||
<i className="bx bx-trophy"></i>
|
<i className="bx bx-trophy"></i>
|
||||||
<span className="fw-medium mx-2">Status:</span>{" "}
|
<span className="fw-medium mx-2">Status:</span>{" "}
|
||||||
<span>{getProjectStatusName(data.projectStatusId)}</span>
|
<span>{ProjectStatus(data.projectStatusId)}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-4">
|
||||||
<i className="bx bx-user"></i>
|
<i className="bx bx-user"></i>
|
||||||
|
|||||||
@ -9,7 +9,8 @@ import { cacheData, getCachedData } from "../../slices/apiDataManager";
|
|||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import { MANAGE_PROJECT } from "../../utils/constants";
|
import { MANAGE_PROJECT } from "../../utils/constants";
|
||||||
import { getProjectStatusColor,getProjectStatusName } from "../../utils/projectStatus";
|
|
||||||
|
|
||||||
|
|
||||||
const ProjectCard = ({ projectData }) => {
|
const ProjectCard = ({ projectData }) => {
|
||||||
const [projectInfo, setProjectInfo] = useState(projectData);
|
const [projectInfo, setProjectInfo] = useState(projectData);
|
||||||
@ -20,9 +21,7 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
|
|
||||||
const handleShow = async () => {
|
const handleShow = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await ProjectRepository.getProjectByprojectId(
|
const response = await ProjectRepository.getProjectByprojectId(projectInfo.id);
|
||||||
projectInfo.id
|
|
||||||
);
|
|
||||||
setProjectDetails(response.data);
|
setProjectDetails(response.data);
|
||||||
setShowModal(true);
|
setShowModal(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -39,11 +38,41 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
|
|
||||||
const handleClose = () => setShowModal(false);
|
const handleClose = () => setShowModal(false);
|
||||||
|
|
||||||
|
const getProjectStatusName = (statusId) => {
|
||||||
|
switch (statusId) {
|
||||||
|
case 1:
|
||||||
|
return "Active";
|
||||||
|
case 2:
|
||||||
|
return "On Hold";
|
||||||
|
// case 3:
|
||||||
|
// return "Suspended";
|
||||||
|
case 3:
|
||||||
|
return "Inactive";
|
||||||
|
case 4:
|
||||||
|
return "Completed";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProjectStatusColor = (statusId) => {
|
||||||
|
switch (statusId) {
|
||||||
|
case 1:
|
||||||
|
return "bg-label-success";
|
||||||
|
case 2:
|
||||||
|
return "bg-label-warning";
|
||||||
|
case 3:
|
||||||
|
return "bg-label-info";
|
||||||
|
case 4:
|
||||||
|
return "bg-label-secondary";
|
||||||
|
case 5:
|
||||||
|
return "bg-label-dark";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleViewProject = () => {
|
const handleViewProject = () => {
|
||||||
navigate(`/projects/${projectData.id}`);
|
navigate(`/projects/${projectData.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleFormSubmit = (updatedProject) => {
|
const handleFormSubmit = (updatedProject) => {
|
||||||
if (projectInfo?.id) {
|
if (projectInfo?.id) {
|
||||||
ProjectRepository.updateProject(projectInfo.id, updatedProject)
|
ProjectRepository.updateProject(projectInfo.id, updatedProject)
|
||||||
@ -131,20 +160,14 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
data-bs-toggle="dropdown"
|
data-bs-toggle="dropdown"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
>
|
>
|
||||||
<i
|
<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>
|
||||||
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>
|
</button>
|
||||||
<ul className="dropdown-menu dropdown-menu-end">
|
<ul className="dropdown-menu dropdown-menu-end">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
aria-label="click to View details"
|
aria-label="click to View details"
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
|
|
||||||
onClick={handleViewProject}
|
onClick={handleViewProject}
|
||||||
>
|
>
|
||||||
<i className="bx bx-detail me-2"></i>
|
<i className="bx bx-detail me-2"></i>
|
||||||
@ -158,13 +181,7 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
<span className="align-left">Modify</span>
|
<span className="align-left">Modify</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li onClick={()=>navigate(`/activities/records?project=${projectInfo.id}`)}>
|
||||||
onClick={() =>
|
|
||||||
navigate(
|
|
||||||
`/activities/records?project=${projectInfo.id}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<a className="dropdown-item">
|
<a className="dropdown-item">
|
||||||
<i className="bx bx-task me-2"></i>
|
<i className="bx bx-task me-2"></i>
|
||||||
<span className="align-left" >Activities</span>
|
<span className="align-left" >Activities</span>
|
||||||
@ -192,7 +209,9 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
: "NA"}
|
: "NA"}
|
||||||
</p>
|
</p>
|
||||||
<p className="mb-0">{projectInfo.projectAddress}</p>
|
<p className="mb-0">{projectInfo.projectAddress}</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body border-top">
|
<div className="card-body border-top">
|
||||||
@ -207,45 +226,29 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
{getProjectStatusName(projectInfo.projectStatusId)}
|
{getProjectStatusName(projectInfo.projectStatusId)}
|
||||||
</span>
|
</span>
|
||||||
</p>{" "}
|
</p>{" "}
|
||||||
{getDateDifferenceInDays(projectInfo.endDate, Date()) >= 0 && (
|
{getDateDifferenceInDays(projectInfo.endDate, Date()) >= 0 &&
|
||||||
<span className="badge bg-label-success ms-auto">
|
( <span className="badge bg-label-success ms-auto">
|
||||||
{projectInfo.endDate &&
|
{projectInfo.endDate &&
|
||||||
getDateDifferenceInDays(projectInfo.endDate, Date())}{" "}
|
getDateDifferenceInDays(projectInfo.endDate, Date())}{" "}
|
||||||
Days left
|
Days left
|
||||||
</span>
|
</span>) }
|
||||||
)}
|
{getDateDifferenceInDays(projectInfo.endDate, Date()) < 0 &&
|
||||||
{getDateDifferenceInDays(projectInfo.endDate, Date()) < 0 && (
|
( <span className="badge bg-label-danger ms-auto">
|
||||||
<span className="badge bg-label-danger ms-auto">
|
|
||||||
{projectInfo.endDate &&
|
{projectInfo.endDate &&
|
||||||
getDateDifferenceInDays(projectInfo.endDate, Date())}{" "}
|
getDateDifferenceInDays(projectInfo.endDate, Date())}{" "}
|
||||||
Days overdue
|
Days overdue
|
||||||
</span>
|
</span>)}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex justify-content-between align-items-center mb-2">
|
<div className="d-flex justify-content-between align-items-center mb-2">
|
||||||
<small className="text-body">
|
<small className="text-body">Task: {projectInfo.completedWork} / {projectInfo.plannedWork}</small>
|
||||||
Task: {projectInfo.completedWork} / {projectInfo.plannedWork}
|
<small className="text-body">{Math.floor(getProgressInNumber(projectInfo.plannedWork, projectInfo.completedWork)) || 0} % Completed</small>
|
||||||
</small>
|
|
||||||
<small className="text-body">
|
|
||||||
{Math.floor(
|
|
||||||
getProgressInNumber(
|
|
||||||
projectInfo.plannedWork,
|
|
||||||
projectInfo.completedWork
|
|
||||||
)
|
|
||||||
) || 0}{" "}
|
|
||||||
% Completed
|
|
||||||
</small>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="progress mb-4 rounded" style={{ height: "8px" }}>
|
<div className="progress mb-4 rounded" style={{ height: "8px" }}>
|
||||||
<div
|
<div
|
||||||
className="progress-bar rounded"
|
className="progress-bar rounded"
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
style={{
|
style={{ width: getProgress(projectInfo.plannedWork, projectInfo.completedWork) }}
|
||||||
width: getProgress(
|
|
||||||
projectInfo.plannedWork,
|
|
||||||
projectInfo.completedWork
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
aria-valuenow={projectInfo.completedWork}
|
aria-valuenow={projectInfo.completedWork}
|
||||||
aria-valuemin="0"
|
aria-valuemin="0"
|
||||||
aria-valuemax={projectInfo.plannedWork}
|
aria-valuemax={projectInfo.plannedWork}
|
||||||
@ -255,16 +258,21 @@ const ProjectCard = ({ projectData }) => {
|
|||||||
{/* <div className="d-flex align-items-center ">
|
{/* <div className="d-flex align-items-center ">
|
||||||
</div> */}
|
</div> */}
|
||||||
<div >
|
<div >
|
||||||
<a className="text-muted d-flex " alt="Active team size">
|
<a
|
||||||
<i className="bx bx-group bx-sm me-1_5"></i>
|
|
||||||
{projectInfo?.teamSize} Members
|
className="text-muted d-flex " alt="Active team size"
|
||||||
|
>
|
||||||
|
<i className="bx bx-group bx-sm me-1_5"></i>{projectInfo?.teamSize} Members
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div >
|
<div >
|
||||||
<a className="text-muted d-flex align-items-center">
|
<a
|
||||||
<i className="bx bx-chat me-1 "></i>{" "}
|
className="text-muted d-flex align-items-center"
|
||||||
<span className="text-decoration-line-through">15</span>
|
>
|
||||||
|
<i className="bx bx-chat me-1 "></i> <span className="text-decoration-line-through">15</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,37 +1,30 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const ProgressBar = ({
|
const ProgressBar = ( {completeValue, totalValue} ) =>
|
||||||
plannedWork = 100,
|
{
|
||||||
completedWork = 0,
|
|
||||||
height = "8px",
|
|
||||||
className = "mb-4",
|
|
||||||
rounded = true,
|
|
||||||
}) => {
|
|
||||||
const getProgress = (planned, completed) => {
|
|
||||||
if (!planned || planned === 0) return "0%";
|
|
||||||
return `${Math.min((completed / planned) * 100, 100).toFixed(2)}%`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const progressStyle = {
|
|
||||||
width: getProgress(plannedWork, completedWork),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const getProgress = (complete, total) => {
|
||||||
|
return (total * 100) / complete + "%";
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
|
<div className="progress mb-4 rounded" style={{height: "8px"}}>
|
||||||
|
<div className="progress p-0">
|
||||||
<div
|
<div
|
||||||
className={`progress ${className} ${rounded ? "rounded" : ""}`}
|
className="progress-bar"
|
||||||
style={{ height }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`progress-bar ${rounded ? "rounded" : ""}`}
|
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
style={progressStyle}
|
style={{
|
||||||
aria-valuenow={completedWork}
|
width: `${getProgress( totalValue,completeValue)}`,
|
||||||
|
height: "10px",
|
||||||
|
}}
|
||||||
|
aria-valuenow={completeValue}
|
||||||
aria-valuemin="0"
|
aria-valuemin="0"
|
||||||
aria-valuemax={plannedWork}
|
aria-valuemax={totalValue}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProgressBar;
|
export default ProgressBar;
|
||||||
|
|
||||||
|
|||||||
@ -11,12 +11,7 @@ import { hasUserPermission } from "../../utils/authUtils";
|
|||||||
import { MANAGE_EMPLOYEES } from "../../utils/constants";
|
import { MANAGE_EMPLOYEES } from "../../utils/constants";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import SuspendEmp from "../../components/Employee/SuspendEmp";
|
import SuspendEmp from "../../components/Employee/SuspendEmp";
|
||||||
import {
|
import {exportToCSV,exportToExcel,printTable,exportToPDF} from "../../utils/tableExportUtils";
|
||||||
exportToCSV,
|
|
||||||
exportToExcel,
|
|
||||||
printTable,
|
|
||||||
exportToPDF,
|
|
||||||
} from "../../utils/tableExportUtils";
|
|
||||||
|
|
||||||
const EmployeeList = () => {
|
const EmployeeList = () => {
|
||||||
const { profile: loginUser } = useProfile();
|
const { profile: loginUser } = useProfile();
|
||||||
@ -129,6 +124,7 @@ const EmployeeList = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isCreateModalOpen && (
|
{isCreateModalOpen && (
|
||||||
@ -183,11 +179,7 @@ const EmployeeList = () => {
|
|||||||
<option value="">All Employees</option>
|
<option value="">All Employees</option>
|
||||||
{Array.isArray(projects) &&
|
{Array.isArray(projects) &&
|
||||||
projects
|
projects
|
||||||
.filter((item) =>
|
.filter((item) => loginUser?.projects?.includes(String(item.id)))
|
||||||
loginUser?.projects?.includes(
|
|
||||||
String(item.id)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<option key={item.id} value={item.id}>
|
<option key={item.id} value={item.id}>
|
||||||
{item.name}
|
{item.name}
|
||||||
@ -231,39 +223,22 @@ const EmployeeList = () => {
|
|||||||
</button>
|
</button>
|
||||||
<ul className="dropdown-menu">
|
<ul className="dropdown-menu">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a className="dropdown-item" href="#" onClick={() => handleExport("print")}>
|
||||||
className="dropdown-item"
|
|
||||||
href="#"
|
|
||||||
onClick={() => handleExport("print")}
|
|
||||||
>
|
|
||||||
<i className="bx bx-printer me-1"></i> Print
|
<i className="bx bx-printer me-1"></i> Print
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a className="dropdown-item" href="#" onClick={() => handleExport("csv")}>
|
||||||
className="dropdown-item"
|
|
||||||
href="#"
|
|
||||||
onClick={() => handleExport("csv")}
|
|
||||||
>
|
|
||||||
<i className="bx bx-file me-1"></i> CSV
|
<i className="bx bx-file me-1"></i> CSV
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a className="dropdown-item" href="#" onClick={() => handleExport("excel")}>
|
||||||
className="dropdown-item"
|
<i className="bx bxs-file-export me-1"></i> Excel
|
||||||
href="#"
|
|
||||||
onClick={() => handleExport("excel")}
|
|
||||||
>
|
|
||||||
<i className="bx bxs-file-export me-1"></i>{" "}
|
|
||||||
Excel
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a className="dropdown-item" href="#" onClick={() => handleExport("pdf")}>
|
||||||
className="dropdown-item"
|
|
||||||
href="#"
|
|
||||||
onClick={() => handleExport("pdf")}
|
|
||||||
>
|
|
||||||
<i className="bx bxs-file-pdf me-1"></i> PDF
|
<i className="bx bxs-file-pdf me-1"></i> PDF
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -493,13 +468,13 @@ const EmployeeList = () => {
|
|||||||
to={`/employee/manage/${item.id}`}
|
to={`/employee/manage/${item.id}`}
|
||||||
className="dropdown-item py-1"
|
className="dropdown-item py-1"
|
||||||
>
|
>
|
||||||
<i class="bx bx-edit bx-sm"></i> Edit
|
<i class='bx bx-edit bx-sm'></i> Edit
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
className="dropdown-item py-1"
|
className="dropdown-item py-1"
|
||||||
onClick={handleShow}
|
onClick={handleShow}
|
||||||
>
|
>
|
||||||
<i class="bx bx-task-x bx-sm"></i> Suspend
|
<i class='bx bx-task-x bx-sm'></i> Suspend
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="dropdown-item py-1"
|
className="dropdown-item py-1"
|
||||||
@ -508,7 +483,7 @@ const EmployeeList = () => {
|
|||||||
data-bs-target="#managerole-modal"
|
data-bs-target="#managerole-modal"
|
||||||
onClick={() => handleConfigData(item.id)}
|
onClick={() => handleConfigData(item.id)}
|
||||||
>
|
>
|
||||||
<i class="bx bx-cog bx-sm"></i> Manage Role
|
<i class='bx bx-cog bx-sm'></i> Manage Role
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,73 +7,85 @@ import { useProjects } from "../../hooks/useProjects";
|
|||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import { getCachedData, cacheData} from "../../slices/apiDataManager";
|
import { getCachedData, cacheData} from "../../slices/apiDataManager";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import {useHasUserPermission} from "../../hooks/useHasUserPermission"
|
||||||
import { useProfile } from "../../hooks/useProfile";
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
import {MANAGE_PROJECT} from "../../utils/constants";
|
import {MANAGE_PROJECT} from "../../utils/constants";
|
||||||
import ProjectListView from "./ProjectListView";
|
|
||||||
|
|
||||||
const ProjectList = () => {
|
const ProjectList = () =>
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
const {profile: loginUser} = useProfile();
|
const {profile: loginUser} = useProfile();
|
||||||
const [listView, setListView] = useState(true);
|
|
||||||
const [showModal, setShowModal] = useState(false);
|
const [showModal, setShowModal] = useState(false);
|
||||||
const {projects, loading, error, refetch} = useProjects();
|
const {projects, loading, error, refetch} = useProjects();
|
||||||
|
const [refresh, setRefresh] = useState(false);
|
||||||
const [ projectList, setProjectList ] = useState( [] );
|
const [ projectList, setProjectList ] = useState( [] );
|
||||||
const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT);
|
const HasManageProjectPermission = useHasUserPermission( MANAGE_PROJECT )
|
||||||
const [HasManageProject, setHasManageProject] = useState(
|
const[HasManageProject,setHasManageProject] = useState(HasManageProjectPermission)
|
||||||
HasManageProjectPermission
|
|
||||||
);
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [itemsPerPage] = useState(6);
|
const [itemsPerPage] = useState(6);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [selectedStatuses, setSelectedStatuses] = useState([1, 2, 3, 4]);
|
|
||||||
|
|
||||||
const handleShow = () => setShowModal(true);
|
const handleShow = () => setShowModal(true);
|
||||||
const handleClose = () => setShowModal( false );
|
const handleClose = () => setShowModal( false );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && Array.isArray(projects)) {
|
if (!loading && Array.isArray(projects)) {
|
||||||
|
// Step 1: Group projects by statusId
|
||||||
const grouped = {};
|
const grouped = {};
|
||||||
|
|
||||||
projects.forEach((project) => {
|
projects.forEach((project) => {
|
||||||
const statusId = project.projectStatusId;
|
const statusId = project.projectStatusId;
|
||||||
if (!grouped[statusId]) grouped[statusId] = [];
|
if (!grouped[statusId]) {
|
||||||
|
grouped[statusId] = [];
|
||||||
|
}
|
||||||
grouped[statusId].push(project);
|
grouped[statusId].push(project);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Step 2: Sort each group by name
|
||||||
const sortedGrouped = Object.keys(grouped)
|
const sortedGrouped = Object.keys(grouped)
|
||||||
.sort()
|
.sort() // sort group keys (status IDs)
|
||||||
.flatMap((statusId) =>
|
.flatMap((statusId) =>
|
||||||
grouped[statusId].sort((a, b) =>
|
grouped[statusId].sort((a, b) =>
|
||||||
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
setProjectList(sortedGrouped);
|
setProjectList(sortedGrouped); // final sorted flat list
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [ projects, loginUser?.projects, loading ] );
|
}, [ projects, loginUser?.projects, loading ] );
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loginUser) {
|
if (loginUser) {
|
||||||
setHasManageProject(HasManageProjectPermission);
|
setHasManageProject(HasManageProjectPermission);
|
||||||
} else {
|
} else {
|
||||||
setHasManageProject(false);
|
setHasManageProject(false); }
|
||||||
}
|
|
||||||
}, [loginUser, HasManageProjectPermission]);
|
}, [loginUser, HasManageProjectPermission]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmitForm = (newProject) => {
|
const handleSubmitForm = (newProject) => {
|
||||||
ProjectRepository.manageProject(newProject)
|
ProjectRepository.manageProject(newProject)
|
||||||
.then((response) => {
|
.then( ( response ) =>
|
||||||
const cachedProjects = getCachedData("projectslist") || [];
|
{
|
||||||
const updatedProjects = [...cachedProjects, response.data];
|
|
||||||
cacheData("projectslist", updatedProjects);
|
const cachedProjects_list = getCachedData( "projectslist" ) || [];
|
||||||
setProjectList((prev) => [...prev, response.data]);
|
|
||||||
|
const updated_Projects_list = [ ...cachedProjects_list, response.data ];
|
||||||
|
|
||||||
|
cacheData("projectslist", updated_Projects_list);
|
||||||
|
setProjectList((prevProjectList) => [...prevProjectList, response.data]);
|
||||||
|
|
||||||
showToast("Project Created successfully.", "success");
|
showToast("Project Created successfully.", "success");
|
||||||
setShowModal(false);
|
setShowModal(false)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
closeModal();
|
||||||
showToast(error.message, "error");
|
showToast(error.message, "error");
|
||||||
setShowModal(false);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,58 +93,36 @@ const ProjectList = () => {
|
|||||||
if (!projects || projects.length === 0) {
|
if (!projects || projects.length === 0) {
|
||||||
refetch();
|
refetch();
|
||||||
}
|
}
|
||||||
|
setRefresh((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStatusChange = (statusId) => {
|
|
||||||
setCurrentPage(1);
|
|
||||||
setSelectedStatuses((prev) =>
|
|
||||||
prev.includes(statusId)
|
|
||||||
? prev.filter((id) => id !== statusId)
|
|
||||||
: [...prev, statusId]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStatusFilterFromChild = (statusesFromChild) => {
|
|
||||||
setSelectedStatuses(statusesFromChild);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredProjects = projectList.filter((project) => {
|
|
||||||
const matchesStatus = selectedStatuses.includes(project.projectStatusId);
|
|
||||||
const matchesSearch = project.name
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchTerm.toLowerCase());
|
|
||||||
return matchesStatus && matchesSearch;
|
|
||||||
});
|
|
||||||
|
|
||||||
const indexOfLastItem = currentPage * itemsPerPage;
|
const indexOfLastItem = currentPage * itemsPerPage;
|
||||||
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
|
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
|
||||||
const currentItems = filteredProjects.slice(
|
const currentItems = Array.isArray(projectList)
|
||||||
indexOfFirstItem,
|
? projectList.slice(indexOfFirstItem, indexOfLastItem)
|
||||||
indexOfLastItem
|
: [];
|
||||||
);
|
|
||||||
const totalPages = Math.ceil(filteredProjects.length / itemsPerPage);
|
const paginate = (pageNumber) => setCurrentPage(pageNumber);
|
||||||
|
const totalPages = Array.isArray(projectList)
|
||||||
|
? Math.ceil(projectList.length / itemsPerPage)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const tooltipTriggerList = Array.from(
|
|
||||||
document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
|
||||||
);
|
|
||||||
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`modal fade ${showModal ? "show" : ""}`}
|
className={`modal fade ${showModal ? 'show' : ''}`}
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
style={{ display: showModal ? "block" : "none" }}
|
style={{ display: showModal ? 'block' : 'none' }}
|
||||||
aria-hidden={!showModal}
|
aria-hidden={!showModal}
|
||||||
>
|
>
|
||||||
<ManageProjectInfo
|
<ManageProjectInfo
|
||||||
project={null}
|
project={null}
|
||||||
handleSubmitForm={handleSubmitForm}
|
handleSubmitForm={handleSubmitForm}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
/>
|
></ManageProjectInfo>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container-xxl flex-grow-1 container-p-y">
|
<div className="container-xxl flex-grow-1 container-p-y">
|
||||||
@ -141,62 +131,20 @@ const ProjectList = () => {
|
|||||||
{ label: "Home", link: "/dashboard" },
|
{ label: "Home", link: "/dashboard" },
|
||||||
{ label: "Projects", link: null },
|
{ label: "Projects", link: null },
|
||||||
]}
|
]}
|
||||||
/>
|
></Breadcrumb>
|
||||||
|
|
||||||
<div className="d-flex flex-wrap justify-content-between align-items-start mb-4">
|
<div className="row">
|
||||||
<div className="d-flex flex-wrap align-items-start">
|
<div
|
||||||
<div className="flex-grow-1 me-2 mb-2">
|
className={`col-md-12 col-lg-12 col-xl-12 order-0 mb-4 ${
|
||||||
<input
|
!error && !projects ? "text-center" : "text-end"
|
||||||
type="search"
|
|
||||||
className="form-control form-control-sm"
|
|
||||||
placeholder="Search projects..."
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={(e) => {
|
|
||||||
setSearchTerm(e.target.value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="d-flex gap-2 mb-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`btn btn-sm ${
|
|
||||||
listView ? "btn-primary" : "btn-outline-primary"
|
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setListView(true)}
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-offset="0,8"
|
|
||||||
data-bs-placement="top"
|
|
||||||
data-bs-custom-class="tooltip"
|
|
||||||
title="List View"
|
|
||||||
>
|
>
|
||||||
<i className="bx bx-list-ul"></i>
|
{" "}
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`btn btn-sm ${
|
className={`btn btn-xs btn-primary ${!HasManageProject && 'd-none' }`}
|
||||||
!listView ? "btn-primary" : "btn-outline-primary"
|
data-bs-toggle="modal"
|
||||||
}`}
|
data-bs-target="#create-project-model"
|
||||||
onClick={() => setListView(false)}
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-offset="0,8"
|
|
||||||
data-bs-placement="top"
|
|
||||||
data-bs-custom-class="tooltip"
|
|
||||||
title="Card View"
|
|
||||||
>
|
|
||||||
<i className="bx bx-grid-alt"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`btn btn-sm btn-primary ${
|
|
||||||
!HasManageProject && "d-none"
|
|
||||||
}`}
|
|
||||||
onClick={handleShow}
|
onClick={handleShow}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
@ -205,123 +153,76 @@ const ProjectList = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loading && <p className="text-center">Loading...</p>}
|
{((error && !loading) || !projects) && (
|
||||||
{!loading && filteredProjects.length === 0 && !listView && (
|
<p className="text-center text-body-secondary">
|
||||||
<p className="text-center text-muted">No projects found.</p>
|
There was an error loading the projects. Please try again.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!projects || projects.length === 0 || projectList.length == 0) &&
|
||||||
|
!loading &&
|
||||||
|
error && (
|
||||||
|
<div className="text-center">
|
||||||
|
<button
|
||||||
|
className="btn btn-xs btn-label-secondary"
|
||||||
|
onClick={handleReFresh}
|
||||||
|
>
|
||||||
|
Retry Fetching Projects
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{listView ? (
|
{loading && <p className="text-center">Loading...</p>}
|
||||||
<div className="table-responsive text-nowrap py-2 ">
|
|
||||||
<table className="table px-2">
|
|
||||||
<thead>
|
{Array.isArray(currentItems) && loginUser?.projects && (
|
||||||
<tr>
|
currentItems
|
||||||
<th className="text-start" colSpan={5}>
|
.filter((item) => loginUser.projects.includes(String(item.id)))
|
||||||
Project Name
|
.map((item) => (
|
||||||
</th>
|
<ProjectCard projectData={item} key={item.id} />
|
||||||
<th className="mx-2">Project Manger</th>
|
))
|
||||||
<th className="mx-2">START DATE</th>
|
)}
|
||||||
<th className="mx-2">DEADLINE</th>
|
|
||||||
<th className="mx-2">Task</th>
|
|
||||||
<th className="mx-2">Progress</th>
|
|
||||||
<th className="mx-2">
|
|
||||||
<div className="dropdown">
|
|
||||||
<a
|
|
||||||
className="dropdown-toggle hide-arrow cursor-pointer"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
Status <i className="bx bx-filter"></i>
|
|
||||||
</a>
|
|
||||||
<ul className="dropdown-menu p-2 text-capitalize">
|
|
||||||
{[
|
|
||||||
{ id: 1, label: "Active" },
|
|
||||||
{ id: 2, label: "On Hold" },
|
|
||||||
{ id: 3, label: "Inactive" },
|
|
||||||
{ id: 4, label: "Completed" },
|
|
||||||
].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>
|
</div>
|
||||||
</li>
|
{/* Pagination */}
|
||||||
))}
|
{!loading && (
|
||||||
</ul>
|
<nav aria-label="Page ">
|
||||||
</div>
|
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||||
</th>
|
<li
|
||||||
<th
|
className={`page-item ${
|
||||||
className={`mx-2 ${
|
currentPage === 1 ? "disabled" : ""
|
||||||
HasManageProject ? "d-sm-table-cell" : "d-none"
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Action
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="table-border-bottom-0 overflow-auto ">
|
|
||||||
{currentItems.length === 0 ? (
|
|
||||||
<tr>
|
|
||||||
<td colSpan="12" className="text-center py-4">
|
|
||||||
No projects found
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
) : (
|
|
||||||
currentItems.map((project) => (
|
|
||||||
<ProjectListView key={project.id} projectData={project} />
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
currentItems.map((project) => (
|
|
||||||
<ProjectCard key={project.id} projectData={project} />
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!loading && totalPages > 1 && (
|
|
||||||
<nav>
|
|
||||||
<ul className="pagination pagination-sm justify-content-end py-2">
|
|
||||||
<li className={`page-item ${currentPage === 1 && "disabled"}`}>
|
|
||||||
<button
|
<button
|
||||||
className="page-link"
|
className="page-link btn-xs"
|
||||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
onClick={() => paginate(currentPage - 1)}
|
||||||
>
|
>
|
||||||
«
|
«
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{[...Array(totalPages)].map((_, i) => (
|
{[...Array(totalPages)]?.map((_, index) => (
|
||||||
<li
|
<li
|
||||||
key={i}
|
key={index}
|
||||||
className={`page-item ${currentPage === i + 1 && "active"}`}
|
className={`page-item ${
|
||||||
|
currentPage === index + 1 ? "active" : ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="page-link "
|
className="page-link "
|
||||||
onClick={() => setCurrentPage(i + 1)}
|
onClick={() => paginate(index + 1)}
|
||||||
>
|
>
|
||||||
{i + 1}
|
{index + 1}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li
|
<li
|
||||||
className={`page-item ${
|
className={`page-item ${
|
||||||
currentPage === totalPages && "disabled"
|
currentPage === totalPages ? "disabled" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="page-link "
|
className="page-link "
|
||||||
onClick={() =>
|
onClick={() => paginate(currentPage + 1)}
|
||||||
setCurrentPage((p) => Math.min(totalPages, p + 1))
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
»
|
»
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,199 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import moment from "moment";
|
|
||||||
import { useProjects } from "../../hooks/useProjects";
|
|
||||||
import {
|
|
||||||
getProjectStatusName,
|
|
||||||
getProjectStatusColor,
|
|
||||||
} from "../../utils/projectStatus";
|
|
||||||
import ProgressBar from "../../components/common/ProgressBar";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import ManageProject from "../../components/Project/ManageProject";
|
|
||||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
|
||||||
import { MANAGE_PROJECT } from "../../utils/constants";
|
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
|
||||||
import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
|
|
||||||
import showToast from "../../services/toastService";
|
|
||||||
import { getCachedData, cacheData } from "../../slices/apiDataManager";
|
|
||||||
|
|
||||||
const ProjectListView = ({ projectData }) => {
|
|
||||||
const [projectInfo, setProjectInfo] = useState(projectData);
|
|
||||||
const [projectDetails, setProjectDetails] = useState(null);
|
|
||||||
const [showModal, setShowModal] = useState(false);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const ManageProject = useHasUserPermission(MANAGE_PROJECT);
|
|
||||||
|
|
||||||
const handleShow = async () => {
|
|
||||||
try {
|
|
||||||
const response = await ProjectRepository.getProjectByprojectId(
|
|
||||||
projectInfo.id
|
|
||||||
);
|
|
||||||
setProjectDetails(response.data);
|
|
||||||
setShowModal(true);
|
|
||||||
} catch (error) {
|
|
||||||
showToast("Failed to load project details", "error");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProgress = (planned, completed) => {
|
|
||||||
return (completed * 100) / planned + "%";
|
|
||||||
};
|
|
||||||
const getProgressInNumber = (planned, completed) => {
|
|
||||||
return (completed * 100) / planned;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => setShowModal(false);
|
|
||||||
|
|
||||||
|
|
||||||
const handleViewProject = () => {
|
|
||||||
navigate(`/projects/${projectData.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFormSubmit = (updatedProject) => {
|
|
||||||
if (projectInfo?.id) {
|
|
||||||
ProjectRepository.updateProject(projectInfo.id, updatedProject)
|
|
||||||
.then((response) => {
|
|
||||||
const updatedProjectData = {
|
|
||||||
...projectInfo,
|
|
||||||
...response.data,
|
|
||||||
building: projectDetails?.building,
|
|
||||||
};
|
|
||||||
|
|
||||||
setProjectInfo( updatedProjectData );
|
|
||||||
|
|
||||||
if (getCachedData(`projectinfo-${projectInfo.id}`)) {
|
|
||||||
cacheData(`projectinfo-${projectInfo.id}`, updatedProjectData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const projects_list = getCachedData("projectslist");
|
|
||||||
if (projects_list) {
|
|
||||||
const updatedProjectsList = projects_list.map((project) =>
|
|
||||||
project.id === projectInfo.id
|
|
||||||
? { ...project, ...response.data, tenant: project.tenant }
|
|
||||||
: project
|
|
||||||
);
|
|
||||||
cacheData("projectslist", updatedProjectsList);
|
|
||||||
}
|
|
||||||
showToast("Project updated successfully.", "success");
|
|
||||||
setShowModal(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
showToast(error.message, "error");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{showModal && projectDetails && (
|
|
||||||
<div
|
|
||||||
className="modal fade show"
|
|
||||||
tabIndex="-1"
|
|
||||||
role="dialog"
|
|
||||||
style={{ display: "block" }}
|
|
||||||
aria-hidden="false"
|
|
||||||
>
|
|
||||||
<ManageProjectInfo
|
|
||||||
project={projectDetails}
|
|
||||||
handleSubmitForm={handleFormSubmit}
|
|
||||||
onClose={handleClose}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<tr className="py-8">
|
|
||||||
<td className="text-start" colSpan={5}>
|
|
||||||
<strong
|
|
||||||
className="text-primary cursor-pointer"
|
|
||||||
onClick={() => navigate(`/projects/${projectInfo.id}`)}
|
|
||||||
>
|
|
||||||
{projectInfo.name}
|
|
||||||
</strong>
|
|
||||||
</td>
|
|
||||||
<td className="text-start small">{projectInfo.contactPerson}</td>
|
|
||||||
<td className="small text-start">
|
|
||||||
<small>
|
|
||||||
{projectInfo.startDate
|
|
||||||
? moment(projectInfo.startDate).format("DD-MMM-YYYY")
|
|
||||||
: "NA"}
|
|
||||||
</small>
|
|
||||||
</td>
|
|
||||||
<td className="mx-2 text-start small">
|
|
||||||
{projectInfo.endDate
|
|
||||||
? moment(projectInfo.endDate).format("DD-MMM-YYYY")
|
|
||||||
: "NA"}
|
|
||||||
</td>
|
|
||||||
<td className="mx-2 text-start small">{projectInfo.plannedWork}</td>
|
|
||||||
<td className="py-6 mx-2 text-start small align-items-center">
|
|
||||||
<ProgressBar
|
|
||||||
plannedWork={projectInfo.plannedWork}
|
|
||||||
completedWork={projectInfo.completedWork}
|
|
||||||
className="mb-0"
|
|
||||||
height="4px"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td className="mx-6">
|
|
||||||
<p className="mb-0">
|
|
||||||
<span
|
|
||||||
className={`badge ${getProjectStatusColor(
|
|
||||||
projectInfo.projectStatusId
|
|
||||||
)}`}
|
|
||||||
>
|
|
||||||
{getProjectStatusName(projectInfo.projectStatusId)}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td className={`mx-2 ${ManageProject ? "d-sm-table-cell":"d-none"}`}>
|
|
||||||
<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>
|
|
||||||
<a
|
|
||||||
aria-label="click to View details"
|
|
||||||
className="dropdown-item"
|
|
||||||
onClick={() => navigate(`/projects/${projectInfo.id}`)}
|
|
||||||
>
|
|
||||||
<i className="bx bx-detail me-2"></i>
|
|
||||||
<span className="align-left">View details</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li onClick={handleShow}>
|
|
||||||
<a className="dropdown-item">
|
|
||||||
<i className="bx bx-pencil me-2"></i>
|
|
||||||
<span className="align-left">Modify</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
onClick={() =>
|
|
||||||
navigate(`/activities/records?project=${projectInfo.id}`)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<a className="dropdown-item">
|
|
||||||
<i className="bx bx-task me-2"></i>
|
|
||||||
<span className="align-left">Activities</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProjectListView;
|
|
||||||
@ -1,32 +1,25 @@
|
|||||||
export const getProjectStatusName = (statusId) => {
|
export const ProjectStatus =(statusId)=>{
|
||||||
switch (statusId) {
|
switch (statusId) {
|
||||||
case 1:
|
case 1:
|
||||||
return "Active";
|
return "Active"
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return "On Hold";
|
return "On Hold"
|
||||||
|
break;
|
||||||
// case 3:
|
// case 3:
|
||||||
// return "Suspended";
|
// return "Suspended"
|
||||||
|
// break;
|
||||||
case 3:
|
case 3:
|
||||||
return "Inactive";
|
return "Inactive"
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
return "Completed";
|
return "Completed"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const getProjectStatusColor = (statusId) => {
|
|
||||||
switch (statusId) {
|
|
||||||
case 1:
|
|
||||||
return "bg-label-success";
|
|
||||||
case 2:
|
|
||||||
return "bg-label-warning";
|
|
||||||
case 3:
|
|
||||||
return "bg-label-info";
|
|
||||||
case 4:
|
|
||||||
return "bg-label-secondary";
|
|
||||||
case 5:
|
|
||||||
return "bg-label-dark";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// for different color for each user
|
// for different color for each user
|
||||||
export function hashString(str) {
|
export function hashString(str) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user