Merge branch 'Service_Project_Managment' of https://git.marcoaiot.com/admin/marco.pms.web into Advance_Payment_List
This commit is contained in:
commit
4b5f8756b3
@ -6,11 +6,11 @@ import { ITEMS_PER_PAGE } from "../../utils/constants";
|
|||||||
const ProjectCompletionChart = () => {
|
const ProjectCompletionChart = () => {
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const { data: projects, isLoading: loading, isError, error } = useProjects(ITEMS_PER_PAGE,currentPage);
|
const { data: projects, isLoading: loading, isError, error } = useProjects(50,currentPage);
|
||||||
// Bar chart logic
|
// Bar chart logic
|
||||||
const projectNames = projects?.data.map((p) => p.name) || [];
|
const projectNames = projects?.data?.map((p) => p.name) || [];
|
||||||
const projectProgress =
|
const projectProgress =
|
||||||
projects?.map((p) => {
|
projects?.data?.map((p) => {
|
||||||
const completed = p.completedWork || 0;
|
const completed = p.completedWork || 0;
|
||||||
const planned = p.plannedWork || 1;
|
const planned = p.plannedWork || 1;
|
||||||
const percent = planned ? (completed / planned) * 100 : 0;
|
const percent = planned ? (completed / planned) * 100 : 0;
|
||||||
|
|||||||
@ -13,15 +13,9 @@ import { useNavigate } from "react-router-dom";
|
|||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import { useProjectContext } from "../../pages/project/ProjectPage";
|
import { useProjectContext } from "../../pages/project/ProjectPage";
|
||||||
import usePagination from "../../hooks/usePagination";
|
import usePagination from "../../hooks/usePagination";
|
||||||
|
import Pagination from "../common/Pagination";
|
||||||
|
|
||||||
const ProjectListView = ({
|
const ProjectListView = ({ data, currentPage, totalPages, paginate }) => {
|
||||||
currentItems,
|
|
||||||
selectedStatuses,
|
|
||||||
handleStatusChange,
|
|
||||||
setCurrentPage,
|
|
||||||
totalPages,
|
|
||||||
isLoading,
|
|
||||||
}) => {
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { setMangeProject } = useProjectContext();
|
const { setMangeProject } = useProjectContext();
|
||||||
@ -132,15 +126,16 @@ const ProjectListView = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card page-min-h py-4 px-6 shadow-sm">
|
<div className="card page-min-h py-4 px-6 shadow-sm">
|
||||||
|
<div className="table-responsive text-nowrap page-min-h">
|
||||||
<div
|
|
||||||
className="table-responsive text-nowrap page-min-h"
|
|
||||||
>
|
|
||||||
<table className="table table-hover align-middle m-0">
|
<table className="table table-hover align-middle m-0">
|
||||||
<thead className="border-bottom ">
|
<thead className="border-bottom ">
|
||||||
<tr>
|
<tr>
|
||||||
{projectColumns.map((col) => (
|
{projectColumns.map((col) => (
|
||||||
<th key={col.key} colSpan={col.colSpan} className={`${col.className} table_header_border`}>
|
<th
|
||||||
|
key={col.key}
|
||||||
|
colSpan={col.colSpan}
|
||||||
|
className={`${col.className} table_header_border`}
|
||||||
|
>
|
||||||
{col.label}
|
{col.label}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
@ -148,7 +143,7 @@ const ProjectListView = ({
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{currentItems?.map((project) => (
|
{data?.map((project) => (
|
||||||
<tr key={project.id}>
|
<tr key={project.id}>
|
||||||
{projectColumns.map((col) => (
|
{projectColumns.map((col) => (
|
||||||
<td
|
<td
|
||||||
@ -223,61 +218,11 @@ const ProjectListView = ({
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading && (
|
<Pagination
|
||||||
<div className="py-4">
|
currentPage={currentPage}
|
||||||
{" "}
|
totalPages={totalPages}
|
||||||
{isLoading && <p className="text-center">Loading...</p>}
|
paginate={paginate}
|
||||||
{!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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { daysLeft, getJobStatusBadge } from "../../utils/appUtils";
|
|||||||
import HoverPopup from "../common/HoverPopup";
|
import HoverPopup from "../common/HoverPopup";
|
||||||
import ChangeStatus from "./ChangeStatus";
|
import ChangeStatus from "./ChangeStatus";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { STATUS_JOB_DONE } from "../../utils/constants";
|
import { STATUS_JOB_CLOSED } from "../../utils/constants";
|
||||||
import Tooltip from "../common/Tooltip";
|
import Tooltip from "../common/Tooltip";
|
||||||
|
|
||||||
const ManageJobTicket = ({ Job }) => {
|
const ManageJobTicket = ({ Job }) => {
|
||||||
@ -58,7 +58,7 @@ const ManageJobTicket = ({ Job }) => {
|
|||||||
<span className={`badge ${getJobStatusBadge(data?.status?.id)}`}>
|
<span className={`badge ${getJobStatusBadge(data?.status?.id)}`}>
|
||||||
{data?.status?.displayName}
|
{data?.status?.displayName}
|
||||||
</span>
|
</span>
|
||||||
{STATUS_JOB_DONE !== data?.status?.id && (
|
{STATUS_JOB_CLOSED !== data?.status?.id && (
|
||||||
<HoverPopup
|
<HoverPopup
|
||||||
id="STATUS_CHANEG"
|
id="STATUS_CHANEG"
|
||||||
title="Change Status"
|
title="Change Status"
|
||||||
|
|||||||
@ -95,7 +95,7 @@ const ServiceProjectProfile = () => {
|
|||||||
|
|
||||||
<li className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
|
<li className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
|
||||||
|
|
||||||
<li className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
|
<a className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -107,7 +107,7 @@ const ServiceProjectProfile = () => {
|
|||||||
Modify Details
|
Modify Details
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</li>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
const InputFieldSuggesstion = () => {
|
|
||||||
return (
|
|
||||||
<div className="position-relative">
|
|
||||||
<input
|
|
||||||
className="form-control form-control-sm"
|
|
||||||
value={value}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
onBlur={() => setTimeout(() => setShowSuggestions(false), 150)}
|
|
||||||
onFocus={() => {
|
|
||||||
if (value) setShowSuggestions(true);
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
|
||||||
/>
|
|
||||||
{showSuggestions && filteredList.length > 0 && (
|
|
||||||
<ul
|
|
||||||
className="list-group shadow-sm position-absolute w-100 bg-white border zindex-tooltip"
|
|
||||||
style={{
|
|
||||||
maxHeight: "180px",
|
|
||||||
overflowY: "auto",
|
|
||||||
marginTop: "2px",
|
|
||||||
zIndex: 1000,
|
|
||||||
borderRadius:"0px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{filteredList.map((org) => (
|
|
||||||
<li
|
|
||||||
key={org}
|
|
||||||
className="list-group-item list-group-item-action border-none "
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
padding: "5px 12px",
|
|
||||||
fontSize: "14px",
|
|
||||||
transition: "background-color 0.2s",
|
|
||||||
}}
|
|
||||||
onMouseDown={() => handleSelectSuggestion(org)}
|
|
||||||
onMouseEnter={(e) =>
|
|
||||||
(e.currentTarget.style.backgroundColor = "#f8f9fa")
|
|
||||||
}
|
|
||||||
onMouseLeave={(e) =>
|
|
||||||
(e.currentTarget.style.backgroundColor = "transparent")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{org}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{error && <small className="danger-text">{error}</small>}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default InputFieldSuggesstion
|
|
||||||
90
src/components/common/Forms/InputSuggesstionField.jsx
Normal file
90
src/components/common/Forms/InputSuggesstionField.jsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
import Label from "../Label";
|
||||||
|
|
||||||
|
const InputSuggessionField = ({
|
||||||
|
organizationList = [],
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
error,
|
||||||
|
disabled=false
|
||||||
|
}) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const dropdownRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const selectedOption = options.find((opt) => opt[valueKey] === value);
|
||||||
|
|
||||||
|
const displayText = selectedOption ? selectedOption[labelKey] : placeholder;
|
||||||
|
|
||||||
|
const handleSelect = (option) => {
|
||||||
|
onChange(option[valueKey]);
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleDropdown = () => setOpen((prev) => !prev);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-3 position-relative" ref={dropdownRef}>
|
||||||
|
{label && (
|
||||||
|
<Label className="form-label" required={required}>
|
||||||
|
{label}
|
||||||
|
</Label>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`select2-icons form-select d-flex align-items-center justify-content-between ${
|
||||||
|
open ? "show" : ""
|
||||||
|
}`}
|
||||||
|
onClick={toggleDropdown}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`text-truncate ${!selectedOption ? "text-muted" : ""}`}
|
||||||
|
>
|
||||||
|
{isLoading ? "Loading..." : displayText}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{open && !isLoading && (
|
||||||
|
<ul
|
||||||
|
className="dropdown-menu w-100 shadow-sm show animate__fadeIn"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "100%",
|
||||||
|
left: 0,
|
||||||
|
zIndex: 1050,
|
||||||
|
marginTop: "4px",
|
||||||
|
borderRadius: "0.375rem",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{options.map((option, i) => (
|
||||||
|
<li key={i}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`dropdown-item ${
|
||||||
|
option[valueKey] === value ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => handleSelect(option)}
|
||||||
|
>
|
||||||
|
{option[labelKey]}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InputSuggessionField;
|
||||||
@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|||||||
import Label from "../Label";
|
import Label from "../Label";
|
||||||
import { useDebounce } from "../../../utils/appUtils";
|
import { useDebounce } from "../../../utils/appUtils";
|
||||||
import { useEmployeesName } from "../../../hooks/useEmployees";
|
import { useEmployeesName } from "../../../hooks/useEmployees";
|
||||||
|
import { useProjectBothName } from "../../../hooks/useProjects";
|
||||||
|
|
||||||
const SelectEmployeeServerSide = ({
|
const SelectEmployeeServerSide = ({
|
||||||
label = "Select",
|
label = "Select",
|
||||||
@ -154,7 +155,9 @@ const SelectEmployeeServerSide = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading && options.length === 0 && (
|
{!isLoading && options.length === 0 && (
|
||||||
<li className="dropdown-item text-muted text-center">No results found</li>
|
<li className="dropdown-item text-muted text-center">
|
||||||
|
No results found
|
||||||
|
</li>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
@ -183,24 +186,29 @@ const SelectEmployeeServerSide = ({
|
|||||||
};
|
};
|
||||||
export default SelectEmployeeServerSide;
|
export default SelectEmployeeServerSide;
|
||||||
|
|
||||||
|
export const SelectProjectField = ({
|
||||||
export const SelectProjectField = ()=>{
|
label = "Select",
|
||||||
|
placeholder = "Select Project",
|
||||||
|
required = false,
|
||||||
|
value = null,
|
||||||
|
onChange,
|
||||||
|
valueKey = "id",
|
||||||
|
isFullObject = false,
|
||||||
|
isMultiple = false,
|
||||||
|
isAllProject = false,
|
||||||
|
}) => {
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const debounce = useDebounce(searchText, 300);
|
const debounce = useDebounce(searchText, 300);
|
||||||
|
|
||||||
const { data, isLoading } = useEmployeesName(
|
const { data, isLoading } = useProjectBothName(debounce);
|
||||||
projectId,
|
|
||||||
debounce,
|
|
||||||
isAllEmployee
|
|
||||||
);
|
|
||||||
|
|
||||||
const options = data?.data ?? [];
|
const options = data ?? [];
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const dropdownRef = useRef(null);
|
const dropdownRef = useRef(null);
|
||||||
|
|
||||||
const getDisplayName = (emp) => {
|
const getDisplayName = (project) => {
|
||||||
if (!emp) return "";
|
if (!project) return "";
|
||||||
return `${emp.firstName || ""} ${emp.lastName || ""}`.trim();
|
return `${project.name || ""}`.trim();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** -----------------------------
|
/** -----------------------------
|
||||||
@ -304,7 +312,7 @@ export const SelectProjectField = ()=>{
|
|||||||
top: "100%",
|
top: "100%",
|
||||||
left: 0,
|
left: 0,
|
||||||
zIndex: 1050,
|
zIndex: 1050,
|
||||||
marginTop: "4px",
|
marginTop: "2px",
|
||||||
borderRadius: "0.375rem",
|
borderRadius: "0.375rem",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
@ -324,7 +332,9 @@ export const SelectProjectField = ()=>{
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading && options.length === 0 && (
|
{!isLoading && options.length === 0 && (
|
||||||
<li className="dropdown-item text-muted text-center">No results found</li>
|
<li className="dropdown-item text-muted text-center">
|
||||||
|
No results found
|
||||||
|
</li>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px;
|
padding: 4px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@ -101,7 +101,7 @@ const SelectMultiple = ({
|
|||||||
value={searchText}
|
value={searchText}
|
||||||
onChange={(e) => setSearchText(e.target.value)}
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
className="multi-select-dropdown-search-input"
|
className="multi-select-dropdown-search-input"
|
||||||
style={{ width: "100%", padding: 4 }}
|
style={{ width: "100%", }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ const SelectMultiple = ({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={val}
|
key={val}
|
||||||
className="badge bg-label-primary mx-1 py-2 mb-1"
|
className="badge bg-label-primary mx-1 py-2"
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -25,7 +25,10 @@ export const useProjects = (pageSize,pageNumber) => {
|
|||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["ProjectsList", pageSize, pageNumber],
|
queryKey: ["ProjectsList", pageSize, pageNumber],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await ProjectRepository.getProjectList(pageSize,pageNumber);
|
const response = await ProjectRepository.getProjectList(
|
||||||
|
pageSize,
|
||||||
|
pageNumber
|
||||||
|
);
|
||||||
return response?.data;
|
return response?.data;
|
||||||
},
|
},
|
||||||
enabled: !!loggedUser,
|
enabled: !!loggedUser,
|
||||||
@ -179,6 +182,19 @@ export const useProjectName = (provideAll=false) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useProjectBothName = (searchString) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["basic_bothProject", searchString],
|
||||||
|
queryFn: async () => {
|
||||||
|
const res = await ProjectRepository.projectNameListAll(searchString);
|
||||||
|
return res.data || res;
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
showToast(error.message || "Error while Fetching project Name", "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useProjectInfra = (projectId, serviceId) => {
|
export const useProjectInfra = (projectId, serviceId) => {
|
||||||
const {
|
const {
|
||||||
data: projectInfra,
|
data: projectInfra,
|
||||||
|
|||||||
@ -52,7 +52,7 @@ const ServiceProjectDisplay = ({ listView ,selectedStatuses }) => {
|
|||||||
<p>List</p>
|
<p>List</p>
|
||||||
) : (
|
) : (
|
||||||
filteredProjects?.map((project) => (
|
filteredProjects?.map((project) => (
|
||||||
<ServiceProjectCard project={project} isCore={false} />
|
<ServiceProjectCard key={project.id} project={project} isCore={false} />
|
||||||
))
|
))
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -83,7 +83,7 @@ const ProjectPage = () => {
|
|||||||
|
|
||||||
<div className="card cursor-pointer mb-5">
|
<div className="card cursor-pointer mb-5">
|
||||||
<div className="card-body py-3 px-6 pb-1">
|
<div className="card-body py-3 px-6 pb-1">
|
||||||
<div className="d-flex flex-wrap justify-content-between align-items-start">
|
<div className="d-flex flex-wrap justify-content-between align-items-center">
|
||||||
{/* LEFT SIDE — DATE TOGGLE BUTTONS */}
|
{/* LEFT SIDE — DATE TOGGLE BUTTONS */}
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
|
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
|
||||||
@ -179,7 +179,7 @@ const ProjectPage = () => {
|
|||||||
{HasManageProject && (
|
{HasManageProject && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary btn-sm d-flex align-items-center"
|
className="btn btn-primary btn-sm d-flex align-items-center my-2"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
coreProjects
|
coreProjects
|
||||||
? setMangeProject({ isOpen: true, Project: null }) // Organization Project → Infra
|
? setMangeProject({ isOpen: true, Project: null }) // Organization Project → Infra
|
||||||
|
|||||||
@ -11,7 +11,12 @@ import { ITEMS_PER_PAGE, PROJECT_STATUS } from "../../utils/constants";
|
|||||||
import usePagination from "../../hooks/usePagination";
|
import usePagination from "../../hooks/usePagination";
|
||||||
import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
|
import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
|
||||||
|
|
||||||
const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusChange }) => {
|
const ProjectsDisplay = ({
|
||||||
|
listView,
|
||||||
|
searchTerm,
|
||||||
|
selectedStatuses,
|
||||||
|
handleStatusChange,
|
||||||
|
}) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const {
|
const {
|
||||||
manageProject,
|
manageProject,
|
||||||
@ -22,15 +27,12 @@ const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusC
|
|||||||
|
|
||||||
const [projectList, setProjectList] = useState([]);
|
const [projectList, setProjectList] = useState([]);
|
||||||
|
|
||||||
|
|
||||||
const { data, isLoading, isError, error } = useProjects(ITEMS_PER_PAGE, 1);
|
const { data, isLoading, isError, error } = useProjects(ITEMS_PER_PAGE, 1);
|
||||||
|
|
||||||
const filteredProjects =
|
const filteredProjects =
|
||||||
data?.data?.filter((project) => {
|
data?.data?.filter((project) => {
|
||||||
const statusId =
|
const statusId =
|
||||||
project.projectStatusId ??
|
project.projectStatusId ?? project?.status?.id ?? project?.statusId;
|
||||||
project?.status?.id ??
|
|
||||||
project?.statusId;
|
|
||||||
|
|
||||||
const matchesStatus = selectedStatuses.includes(statusId);
|
const matchesStatus = selectedStatuses.includes(statusId);
|
||||||
|
|
||||||
@ -41,15 +43,12 @@ const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusC
|
|||||||
return matchesStatus && matchesSearch;
|
return matchesStatus && matchesSearch;
|
||||||
}) ?? [];
|
}) ?? [];
|
||||||
|
|
||||||
|
|
||||||
const paginate = (page) => {
|
const paginate = (page) => {
|
||||||
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
|
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
|
||||||
setCurrentPage(page);
|
setCurrentPage(page);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const sortingProject = (projects) => {
|
const sortingProject = (projects) => {
|
||||||
if (!isLoading && Array.isArray(projects)) {
|
if (!isLoading && Array.isArray(projects)) {
|
||||||
const grouped = {};
|
const grouped = {};
|
||||||
@ -102,12 +101,10 @@ const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusC
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
{listView ? (
|
{listView ? (
|
||||||
<ProjectListView
|
<ProjectListView
|
||||||
currentItems={currentItems}
|
data={projectList}
|
||||||
selectedStatuses={selectedStatuses}
|
currentPage={currentPage}
|
||||||
handleStatusChange={handleStatusChange}
|
totalPages={data?.totalPages}
|
||||||
setCurrentPage={setCurrentPage}
|
paginate={paginate}
|
||||||
totalPages={totalPages}
|
|
||||||
isLoading={isLoading}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProjectCardView
|
<ProjectCardView
|
||||||
@ -118,7 +115,6 @@ const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusC
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Project Manage Update or Create */}
|
|
||||||
{manageProject?.isOpen && (
|
{manageProject?.isOpen && (
|
||||||
<GlobalModel
|
<GlobalModel
|
||||||
size="md"
|
size="md"
|
||||||
@ -131,7 +127,6 @@ const ProjectsDisplay = ({ listView, searchTerm, selectedStatuses, handleStatusC
|
|||||||
/>
|
/>
|
||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,17 +1,24 @@
|
|||||||
import { api } from "../utils/axiosClient";
|
import { api } from "../utils/axiosClient";
|
||||||
|
|
||||||
const ProjectRepository = {
|
const ProjectRepository = {
|
||||||
getProjectList: (pageSize,pageNumber) => api.get(`/api/project/list?pageSize=${pageSize}&pageNumber=${pageNumber}`),
|
getProjectList: (pageSize, pageNumber) =>
|
||||||
|
api.get(`/api/project/list?pageSize=${pageSize}&pageNumber=${pageNumber}`),
|
||||||
getProjectByprojectId: (projetid) =>
|
getProjectByprojectId: (projetid) =>
|
||||||
api.get(`/api/project/details/${projetid}`),
|
api.get(`/api/project/details/${projetid}`),
|
||||||
|
|
||||||
getProjectAllocation: (projectId, serviceId, organizationId, employeeStatus) => {
|
getProjectAllocation: (
|
||||||
|
projectId,
|
||||||
|
serviceId,
|
||||||
|
organizationId,
|
||||||
|
employeeStatus
|
||||||
|
) => {
|
||||||
let url = `/api/project/allocation/${projectId}`;
|
let url = `/api/project/allocation/${projectId}`;
|
||||||
|
|
||||||
const params = [];
|
const params = [];
|
||||||
if (organizationId) params.push(`organizationId=${organizationId}`);
|
if (organizationId) params.push(`organizationId=${organizationId}`);
|
||||||
if (serviceId) params.push(`serviceId=${serviceId}`);
|
if (serviceId) params.push(`serviceId=${serviceId}`);
|
||||||
if (employeeStatus !== undefined) params.push(`includeInactive=${employeeStatus}`);
|
if (employeeStatus !== undefined)
|
||||||
|
params.push(`includeInactive=${employeeStatus}`);
|
||||||
|
|
||||||
if (params.length > 0) {
|
if (params.length > 0) {
|
||||||
url += `?${params.join("&")}`;
|
url += `?${params.join("&")}`;
|
||||||
@ -20,7 +27,6 @@ const ProjectRepository = {
|
|||||||
return api.get(url);
|
return api.get(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
getEmployeesByProject: (projectId) =>
|
getEmployeesByProject: (projectId) =>
|
||||||
api.get(`/api/Project/employees/get/${projectId}`),
|
api.get(`/api/Project/employees/get/${projectId}`),
|
||||||
|
|
||||||
@ -40,7 +46,10 @@ const ProjectRepository = {
|
|||||||
api.get(`/api/project/allocation-histery/${id}`),
|
api.get(`/api/project/allocation-histery/${id}`),
|
||||||
updateProjectsByEmployee: (id, data) =>
|
updateProjectsByEmployee: (id, data) =>
|
||||||
api.post(`/api/project/assign-projects/${id}`, data),
|
api.post(`/api/project/assign-projects/${id}`, data),
|
||||||
projectNameList: (provideAll) => api.get(`/api/project/list/basic?provideAll=${provideAll}`),
|
projectNameList: (provideAll) =>
|
||||||
|
api.get(`/api/project/list/basic?provideAll=${provideAll}`),
|
||||||
|
projectNameListAll: (searchString) =>
|
||||||
|
api.get(`/api/project/list/basic/all?searchString=${searchString}`),
|
||||||
|
|
||||||
getProjectDetails: (id) => api.get(`/api/project/details/${id}`),
|
getProjectDetails: (id) => api.get(`/api/project/details/${id}`),
|
||||||
|
|
||||||
|
|||||||
@ -208,6 +208,6 @@ export const PAYEE_RECURRING_EXPENSE = [
|
|||||||
|
|
||||||
|
|
||||||
//#region Service Project and Jobs
|
//#region Service Project and Jobs
|
||||||
export const STATUS_JOB_DONE = "ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"
|
export const STATUS_JOB_CLOSED = "3ddeefb5-ae3c-4e10-a922-35e0a452bb69"
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
Loading…
x
Reference in New Issue
Block a user