Compare commits
14 Commits
d06cfd97a7
...
4b3f8cc50f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b3f8cc50f | ||
|
|
8de7b4b5c3 | ||
|
|
498665c811 | ||
|
|
9ef09f9536 | ||
|
|
04a25d58f4 | ||
|
|
148f4b79e7 | ||
|
|
8607dbb49b | ||
|
|
8be60953ba | ||
|
|
4055a4532c | ||
|
|
4b9f5d737a | ||
|
|
e86d43c6e9 | ||
|
|
a96fa8efc7 | ||
|
|
294c13878d | ||
|
|
b3906f460e |
@ -104,7 +104,8 @@ const TaskModel = ({
|
||||
}));
|
||||
};
|
||||
|
||||
const onSubmitForm = async (data) => {
|
||||
const onSubmitForm = async ( data ) =>
|
||||
{
|
||||
setIsSubmitting(true);
|
||||
await onSubmit(data);
|
||||
setValue("plannedWork", 0);
|
||||
@ -114,9 +115,9 @@ const TaskModel = ({
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData(defaultModel);
|
||||
setSelectedBuilding("0");
|
||||
setSelectedFloor("0");
|
||||
setSelectedWorkArea("0");
|
||||
setSelectedBuilding(null); // not "0"
|
||||
setSelectedFloor(null);
|
||||
setSelectedWorkArea(null);
|
||||
setSelectedActivity(null);
|
||||
reset(defaultModel);
|
||||
};
|
||||
@ -255,10 +256,11 @@ const TaskModel = ({
|
||||
onChange={handleActivityChange}
|
||||
>
|
||||
<option value="0">Select Activity</option>
|
||||
{activityData && activityData.length > 0 ? (
|
||||
{activityData && activityData.length > 0 && (
|
||||
activityData
|
||||
?.slice()
|
||||
?.sort((a, b) => {
|
||||
?.sort( ( a, b ) =>
|
||||
{
|
||||
const nameA = a?.activityName || "";
|
||||
const nameB = b?.activityName || "";
|
||||
return nameA.localeCompare( nameB );
|
||||
@ -271,9 +273,11 @@ const TaskModel = ({
|
||||
`Unnamed (id: ${ activity.id })`}
|
||||
</option>
|
||||
) )
|
||||
) : (
|
||||
) }
|
||||
{(!loading && activities.length === 0 )&& (
|
||||
<option disabled>No activities available</option>
|
||||
)}
|
||||
{loading && ( <option disabled>Loading...</option>)}
|
||||
</select>
|
||||
|
||||
{errors.activityID && (
|
||||
@ -337,8 +341,6 @@ const TaskModel = ({
|
||||
<button type="submit" className="btn btn-sm btn-primary me-3">
|
||||
{isSubmitting
|
||||
? "Please Wait.."
|
||||
: formData.id !== "0" && formData.id !== ""
|
||||
? "Edit Task"
|
||||
: "Add Task"}
|
||||
</button>
|
||||
<button
|
||||
|
||||
@ -140,7 +140,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
{projectId && ManageInfra && (
|
||||
{ ManageInfra && (
|
||||
<>
|
||||
<button
|
||||
aria-label="Modify"
|
||||
|
||||
@ -11,6 +11,8 @@ const MapUsers = ({
|
||||
empJobRoles,
|
||||
onSubmit,
|
||||
allocation,
|
||||
assignedLoading,
|
||||
setAssignedLoading,
|
||||
}) => {
|
||||
const { employeesList, loading: employeeLoading, error } = useAllEmployees();
|
||||
const [selectedEmployees, setSelectedEmployees] = useState([]);
|
||||
@ -94,17 +96,19 @@ const MapUsers = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = () =>
|
||||
{
|
||||
setAssignedLoading(true)
|
||||
const selected = selectedEmployees
|
||||
.filter((emp) => emp.isSelected)
|
||||
.map((emp) => ({ empID: emp.id, jobRoleId: emp.jobRoleId }));
|
||||
if (selected.length > 0) {
|
||||
console.log(selected);
|
||||
onSubmit(selected);
|
||||
setSelectedEmployees([]);
|
||||
} else {
|
||||
showToast("Please select Employee", "error");
|
||||
}
|
||||
|
||||
};
|
||||
return (
|
||||
<>
|
||||
@ -112,14 +116,17 @@ const MapUsers = ({
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<div className="md-2 mb-1">
|
||||
{(filteredData.length > 0 ||
|
||||
allocationEmployeesData.length > 0)&& (
|
||||
<div className="input-group">
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm"
|
||||
placeholder="Search employees.."
|
||||
placeholder="Search employees..."
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-body p-sm-4 p-0">
|
||||
@ -131,19 +138,22 @@ const MapUsers = ({
|
||||
>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
{(employeeLoading && allocationEmployeesData.length === 0 ) && <p>Loading...</p>}
|
||||
{employeeLoading && allocationEmployeesData.length === 0 && (
|
||||
<p>Loading...</p>
|
||||
)}
|
||||
|
||||
{!employeeLoading &&
|
||||
allocationEmployeesData.length === 0 &&
|
||||
filteredData.length === 0 && <p>No employees available.</p>}
|
||||
|
||||
{!employeeLoading &&
|
||||
allocationEmployeesData.length > 0 &&
|
||||
filteredData.length === 0 && (
|
||||
<p>All employee assigned to Project.</p>
|
||||
)}
|
||||
|
||||
{!employeeLoading && allocationEmployeesData.length > 0 && filteredData.length === 0 && (
|
||||
<p>No matching employees found.</p>
|
||||
)}
|
||||
|
||||
{filteredData.length > 0 &&
|
||||
{(filteredData.length > 0 ||
|
||||
allocationEmployeesData.length > 0) &&
|
||||
filteredData.map((emp) => (
|
||||
<AssignEmployeeTable
|
||||
key={emp.id}
|
||||
@ -158,9 +168,16 @@ const MapUsers = ({
|
||||
</table>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button className="btn btn-sm btn-success" onClick={handleSubmit}>
|
||||
Assign to Project
|
||||
{(filteredData.length > 0 ||
|
||||
allocationEmployeesData.length > 0) && (
|
||||
<button
|
||||
className="btn btn-sm btn-success"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{assignedLoading ? "Please Wait...":"Assign to Project"}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-secondary"
|
||||
|
||||
@ -9,7 +9,10 @@ import { cacheData, getCachedData } from "../../slices/apiDataManager";
|
||||
import showToast from "../../services/toastService";
|
||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||
import { MANAGE_PROJECT } from "../../utils/constants";
|
||||
import { getProjectStatusColor,getProjectStatusName } from "../../utils/projectStatus";
|
||||
import {
|
||||
getProjectStatusColor,
|
||||
getProjectStatusName,
|
||||
} from "../../utils/projectStatus";
|
||||
|
||||
const ProjectCard = ({ projectData }) => {
|
||||
const [projectInfo, setProjectInfo] = useState(projectData);
|
||||
@ -17,13 +20,16 @@ const ProjectCard = ({ projectData }) => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const ManageProject = useHasUserPermission(MANAGE_PROJECT);
|
||||
const [modifyProjectLoading, setMdifyProjectLoading] = useState(false);
|
||||
|
||||
const handleShow = async () => {
|
||||
try {
|
||||
setMdifyProjectLoading(true);
|
||||
const response = await ProjectRepository.getProjectByprojectId(
|
||||
projectInfo.id
|
||||
);
|
||||
setProjectDetails(response.data);
|
||||
setMdifyProjectLoading(false);
|
||||
setShowModal(true);
|
||||
} catch (error) {
|
||||
showToast("Failed to load project details", "error");
|
||||
@ -39,7 +45,6 @@ const ProjectCard = ({ projectData }) => {
|
||||
|
||||
const handleClose = () => setShowModal(false);
|
||||
|
||||
|
||||
const handleViewProject = () => {
|
||||
navigate(`/projects/${projectData.id}`);
|
||||
};
|
||||
@ -64,7 +69,9 @@ const ProjectCard = ({ projectData }) => {
|
||||
if (projects_list) {
|
||||
const updatedProjectsList = projects_list.map((project) =>
|
||||
project.id === projectInfo.id
|
||||
? { ...project, ...response.data,
|
||||
? {
|
||||
...project,
|
||||
...response.data,
|
||||
// tenant: project.tenant
|
||||
}
|
||||
: project
|
||||
@ -81,6 +88,7 @@ const ProjectCard = ({ projectData }) => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{showModal && projectDetails && (
|
||||
@ -133,6 +141,9 @@ const ProjectCard = ({ projectData }) => {
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{modifyProjectLoading? <div class="spinner-border spinner-border-sm text-secondary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div> :
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-sm text-muted"
|
||||
data-bs-toggle="tooltip"
|
||||
@ -140,7 +151,7 @@ const ProjectCard = ({ projectData }) => {
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
></i>}
|
||||
</button>
|
||||
<ul className="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
|
||||
@ -21,7 +21,7 @@ const ProjectInfra = ({
|
||||
eachSiteEngineer,
|
||||
}) => {
|
||||
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
||||
const { projects_Details,refetch, loading } = useProjectDetails(data.id);
|
||||
const { projects_Details,refetch, loading } = useProjectDetails(data?.id);
|
||||
const [project, setProject] = useState(projects_Details);
|
||||
const [modalConfig, setModalConfig] = useState({ type: null, data: null });
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
@ -18,23 +18,30 @@ const Teams = ({ project }) => {
|
||||
const [isModalOpen, setIsModelOpen] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [empJobRoles, setEmpJobRoles] = useState(null);
|
||||
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
||||
const [employees, setEmployees] = useState([]);
|
||||
const [filteredEmployees, setFilteredEmployees] = useState([]);
|
||||
const [ removingEmployeeId, setRemovingEmployeeId ] = useState( null );
|
||||
const [ assignedLoading, setAssignedLoading ] = useState( false )
|
||||
const [employeeLodaing,setEmployeeLoading] = useState(false)
|
||||
|
||||
const HasAssignUserPermission = useHasUserPermission(ASSIGN_TO_PROJECT);
|
||||
|
||||
const fetchEmployees = async () => {
|
||||
try {
|
||||
try
|
||||
{
|
||||
setEmployeeLoading(true)
|
||||
|
||||
// if (!empRoles) {
|
||||
ProjectRepository.getProjectAllocation(project.id)
|
||||
.then((response) => {
|
||||
setEmployees(response.data);
|
||||
setFilteredEmployees( response.data.filter( ( emp ) => emp.isActive ) );
|
||||
setEmployeeLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
setError( "Failed to fetch data." );
|
||||
setEmployeeLoading(false)
|
||||
});
|
||||
} catch (err) {
|
||||
setError("Failed to fetch activities.");
|
||||
@ -45,8 +52,9 @@ const Teams = ({ project }) => {
|
||||
ProjectRepository.manageProjectAllocation(items)
|
||||
.then((response) => {
|
||||
showToast("Details updated successfully.", "success");
|
||||
setClearFormTrigger(true);
|
||||
fetchEmployees();
|
||||
setRemovingEmployeeId( null );
|
||||
setAssignedLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
showToast(error.message, "error");
|
||||
@ -54,6 +62,7 @@ const Teams = ({ project }) => {
|
||||
};
|
||||
|
||||
const removeAllocation = (item) => {
|
||||
setRemovingEmployeeId(item.id);
|
||||
submitAllocations([
|
||||
{
|
||||
empID: item.employeeId,
|
||||
@ -134,13 +143,13 @@ const Teams = ({ project }) => {
|
||||
aria-hidden="true"
|
||||
>
|
||||
<MapUsers
|
||||
projectId={project.id}
|
||||
projectId={project?.id}
|
||||
onClose={onModelClose}
|
||||
empJobRoles={empJobRoles}
|
||||
onSubmit={handleEmpAlicationFormSubmit}
|
||||
allocation={employees}
|
||||
clearTrigger={clearFormTrigger}
|
||||
onClearComplete={() => setClearFormTrigger(false)}
|
||||
assignedLoading={assignedLoading}
|
||||
setAssignedLoading={setAssignedLoading}
|
||||
></MapUsers>
|
||||
</div>
|
||||
|
||||
@ -181,7 +190,8 @@ const Teams = ({ project }) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive text-nowrap">
|
||||
{employees && employees.length > 0 ? (
|
||||
{employeeLodaing && (<p>Loading..</p>)}
|
||||
{!employeeLodaing && employees && employees.length > 0 && (
|
||||
<table className="table ">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -205,7 +215,8 @@ const Teams = ({ project }) => {
|
||||
<div className="d-flex flex-column">
|
||||
<a
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
onClick={( e ) =>
|
||||
{
|
||||
e.preventDefault(); // Prevent default link behavior
|
||||
window.location.href =
|
||||
"/employee/" + item.employee.id;
|
||||
@ -247,7 +258,13 @@ const Teams = ({ project }) => {
|
||||
onClick={() => removeAllocation( item )}
|
||||
>
|
||||
{" "}
|
||||
<i className="bx bx-trash me-1 text-danger"></i>{" "}
|
||||
{removingEmployeeId === item.id ? <div
|
||||
class="spinner-border spinner-border-sm text-primary"
|
||||
role="status"
|
||||
>
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div> : <i className="bx bx-trash me-1 text-danger"></i>}
|
||||
|
||||
</button>
|
||||
)}
|
||||
{!item.isActive && <span>Not in project</span>}
|
||||
@ -256,7 +273,8 @@ const Teams = ({ project }) => {
|
||||
) )}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
)}
|
||||
{(!employeeLodaing && employees.length == 0 ) && (
|
||||
<span>No employees assigned to the project</span>
|
||||
)}
|
||||
</div>
|
||||
@ -267,4 +285,3 @@ const Teams = ({ project }) => {
|
||||
};
|
||||
|
||||
export default Teams;
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ export const useProjects = () => {
|
||||
const { profile } = useProfile();
|
||||
const dispatch = useDispatch();
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const projects_cache = getCachedData("projectslist");
|
||||
@ -39,6 +39,7 @@ export const useProjects = () => {
|
||||
if (!projects.length) {
|
||||
const filtered = filterProjects(projects_cache);
|
||||
setProjects( filtered );
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -27,7 +27,12 @@ const ProjectList = () => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemsPerPage] = useState(6);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [selectedStatuses, setSelectedStatuses] = useState(["b74da4c2-d07e-46f2-9919-e75e49b12731","603e994b-a27f-4e5d-a251-f3d69b0498ba","ef1c356e-0fe0-42df-a5d3-8daee355492d","33deaef9-9af1-4f2a-b443-681ea0d04f81",]);
|
||||
const [selectedStatuses, setSelectedStatuses] = useState([
|
||||
"b74da4c2-d07e-46f2-9919-e75e49b12731",
|
||||
"603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
||||
"ef1c356e-0fe0-42df-a5d3-8daee355492d",
|
||||
"33deaef9-9af1-4f2a-b443-681ea0d04f81",
|
||||
]);
|
||||
|
||||
const handleShow = () => setShowModal(true);
|
||||
const handleClose = () => setShowModal(false);
|
||||
@ -41,8 +46,8 @@ const ProjectList = () => {
|
||||
grouped[statusId].push(project);
|
||||
});
|
||||
|
||||
const sortedGrouped = Object.keys(grouped)
|
||||
.sort()
|
||||
const sortedGrouped = selectedStatuses
|
||||
.filter((statusId) => grouped[statusId])
|
||||
.flatMap((statusId) =>
|
||||
grouped[statusId].sort((a, b) =>
|
||||
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
||||
@ -171,7 +176,7 @@ const ProjectList = () => {
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Card View"
|
||||
>
|
||||
<i className="bx bx-grid-alt"></i>
|
||||
<i className="bx bx-grid-alt bx-sm"></i>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -185,9 +190,52 @@ const ProjectList = () => {
|
||||
data-bs-custom-class="tooltip"
|
||||
title="List View"
|
||||
>
|
||||
<i className="bx bx-list-ul"></i>
|
||||
<i className="bx bx-list-ul bx-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
{!listView && (
|
||||
<div className="dropdown ms-3">
|
||||
<a
|
||||
className="dropdown-toggle hide-arrow cursor-pointer"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i className="bx bx-filter bx-lg"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu p-2 text-capitalize">
|
||||
{[
|
||||
{
|
||||
id: "b74da4c2-d07e-46f2-9919-e75e49b12731",
|
||||
label: "Active",
|
||||
},
|
||||
{
|
||||
id: "603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
||||
label: "On Hold",
|
||||
},
|
||||
{
|
||||
id: "ef1c356e-0fe0-42df-a5d3-8daee355492d",
|
||||
label: "Inactive",
|
||||
},
|
||||
{
|
||||
id: "33deaef9-9af1-4f2a-b443-681ea0d04f81",
|
||||
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>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@ -234,10 +282,22 @@ const ProjectList = () => {
|
||||
</a>
|
||||
<ul className="dropdown-menu p-2 text-capitalize">
|
||||
{[
|
||||
{ id: "b74da4c2-d07e-46f2-9919-e75e49b12731", label: "Active" },
|
||||
{ id: "603e994b-a27f-4e5d-a251-f3d69b0498ba", label: "On Hold" },
|
||||
{ id: "ef1c356e-0fe0-42df-a5d3-8daee355492d", label: "Inactive" },
|
||||
{ id: "33deaef9-9af1-4f2a-b443-681ea0d04f81", label: "Completed" },
|
||||
{
|
||||
id: "b74da4c2-d07e-46f2-9919-e75e49b12731",
|
||||
label: "Active",
|
||||
},
|
||||
{
|
||||
id: "603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
||||
label: "On Hold",
|
||||
},
|
||||
{
|
||||
id: "ef1c356e-0fe0-42df-a5d3-8daee355492d",
|
||||
label: "Inactive",
|
||||
},
|
||||
{
|
||||
id: "33deaef9-9af1-4f2a-b443-681ea0d04f81",
|
||||
label: "Completed",
|
||||
},
|
||||
].map(({ id, label }) => (
|
||||
<li key={id}>
|
||||
<div className="form-check">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user