486 lines
15 KiB
JavaScript
486 lines
15 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import "./ProjectInfra.css";
|
|
import BuildingModel from "./Infrastructure/BuildingModel";
|
|
import FloorModel from "./Infrastructure/FloorModel";
|
|
import showToast from "../../services/toastService";
|
|
import WorkAreaModel from "./Infrastructure/WorkAreaModel";
|
|
import TaskModel from "./Infrastructure/TaskModel";
|
|
import ProjectRepository, {
|
|
TasksRepository,
|
|
} from "../../repositories/ProjectRepository";
|
|
import ProjectModal from "./ProjectModal";
|
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
|
import { MANAGE_PROJECT_INFRA } from "../../utils/constants";
|
|
import InfraTable from "./Infrastructure/InfraTable";
|
|
import { cacheData, clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
|
import { useProjectDetails } from "../../hooks/useProjects";
|
|
|
|
const ProjectInfra = ({
|
|
data,
|
|
onDataChange,
|
|
eachSiteEngineer,
|
|
}) => {
|
|
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
|
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);
|
|
const ManageInfra = useHasUserPermission(MANAGE_PROJECT_INFRA);
|
|
|
|
const [isBuildingModalOpen, setIsBuildingModalOpen] = useState(false);
|
|
const [isFloorModalOpen, setIsFloorModalOpen] = useState(false);
|
|
const [isWorkAreaModelOpen, setIsWorkAreaModalOpen] = useState(false);
|
|
const [isTaskModelOpen, setIsTaskModalOpen] = useState(false);
|
|
const [isAssignRoleModal, setIsAssingRoleModal] = useState(false);
|
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
|
const [CurrentBuilding, setCurrentBuilding] = useState("");
|
|
const [showModal, setShowModal] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setProject(projects_Details);
|
|
}, [data, projects_Details]);
|
|
|
|
const openFloorModel = (projectData) => {
|
|
setIsFloorModalOpen(true);
|
|
};
|
|
const closeFloorModel = () => {
|
|
setIsFloorModalOpen(false);
|
|
};
|
|
|
|
const openAssignModel = (assignData) => {
|
|
setCurrentBuilding(assignData);
|
|
setIsAssingRoleModal(true);
|
|
};
|
|
const openBuildingModel = (projectData) => {
|
|
setIsBuildingModalOpen(true);
|
|
};
|
|
|
|
const closeBuildingModel = () => {
|
|
setIsBuildingModalOpen(false);
|
|
};
|
|
|
|
const handleBuildingModelFormSubmit = (buildingmodel) => {
|
|
if (buildingmodel.id == "" || buildingmodel.id == 0)
|
|
delete buildingmodel.id;
|
|
let data = [
|
|
{
|
|
building: buildingmodel,
|
|
floor: null,
|
|
workArea: null,
|
|
},
|
|
];
|
|
submitData(data);
|
|
};
|
|
const handleFloorModelFormSubmit = (updatedFloor) => {
|
|
if (updatedFloor.id == "") delete updatedFloor.id;
|
|
submitData([
|
|
{
|
|
building: null,
|
|
floor: updatedFloor,
|
|
workArea: null,
|
|
},
|
|
]);
|
|
};
|
|
|
|
const openWorkAreaModel = (projectData) => {
|
|
setIsWorkAreaModalOpen(true);
|
|
};
|
|
|
|
const closeWorkAreaModel = () => {
|
|
setIsWorkAreaModalOpen(false);
|
|
};
|
|
const handleWorkAreaModelFormSubmit = (updatedModel) => {
|
|
if (updatedModel.id == "") delete updatedModel.id;
|
|
submitData([
|
|
{
|
|
building: null,
|
|
floor: null,
|
|
workArea: updatedModel,
|
|
},
|
|
]);
|
|
};
|
|
|
|
const openTaskModel = (projectData) => {
|
|
setIsTaskModalOpen(true);
|
|
};
|
|
|
|
const closeTaskModel = () => {
|
|
setIsTaskModalOpen(false);
|
|
};
|
|
|
|
const handleTaskModelFormSubmit = (updatedModel) => {
|
|
if (updatedModel.id == "") updatedModel.id = null;
|
|
const updatedProject = { ...project };
|
|
|
|
ProjectRepository.manageProjectTasks([updatedModel])
|
|
.then((response) => {
|
|
onDataChange("task-change");
|
|
showToast("Details updated successfully.", "success");
|
|
// setClearFormTrigger( true );
|
|
if (response?.data[0]) {
|
|
const { workItemId, workItem } = response.data[0];
|
|
|
|
const updatedBuildings = updatedProject.buildings.map((building) =>
|
|
building.id == updatedModel.buildingID
|
|
? {
|
|
...building,
|
|
floors: building.floors.map((floor) =>
|
|
floor.id == updatedModel.floorId
|
|
? {
|
|
...floor,
|
|
workAreas: floor.workAreas.map((workArea) =>
|
|
workArea.id === workItem?.workAreaId
|
|
? {
|
|
...workArea,
|
|
workItems: workArea.workItems.some(
|
|
(existingItem) =>
|
|
existingItem.workItemId ===
|
|
workItem.workItemId
|
|
)
|
|
? [...workArea.workItems] // Create a new array to trigger re-render
|
|
: [...workArea.workItems, workItem],
|
|
}
|
|
: workArea
|
|
),
|
|
}
|
|
: floor
|
|
),
|
|
}
|
|
: building
|
|
);
|
|
updatedProject.buildings = updatedBuildings;
|
|
// workItem update, but having local state issue there for needed to calling api
|
|
clearCacheKey( "projectInfo" )
|
|
refetch()
|
|
|
|
cacheData("projectInfo", {
|
|
projectId: updatedProject.id,
|
|
data: updatedProject,
|
|
});
|
|
|
|
setProject( updatedProject );
|
|
// closeTaskModel()
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
showToast(error.message, "error");
|
|
});
|
|
};
|
|
|
|
|
|
const submitData = async (infraObject) => {
|
|
try
|
|
{
|
|
|
|
let response = await ProjectRepository.manageProjectInfra(infraObject);
|
|
const entity = response.data;
|
|
|
|
const updatedProject = { ...project };
|
|
// Handle the building data
|
|
if (entity.building) {
|
|
const { id, name, description } = entity.building;
|
|
const updatedBuildings = updatedProject?.buildings?.map((building) =>
|
|
building.id === id ? { ...building, name, description } : building
|
|
);
|
|
|
|
// Add building if it doesn't exist
|
|
if (!updatedProject.buildings.some((building) => building.id === id)) {
|
|
updatedBuildings.push({
|
|
id: id,
|
|
name,
|
|
description,
|
|
floors: [],
|
|
});
|
|
}
|
|
|
|
updatedProject.buildings = updatedBuildings;
|
|
|
|
// Update the cache for buildings
|
|
cacheData("projectInfo", {
|
|
projectId: updatedProject.id,
|
|
data: updatedProject,
|
|
});
|
|
setProject((prevProject) => ({
|
|
...prevProject,
|
|
buildings: updatedBuildings,
|
|
} ) );
|
|
// closeBuildingModel()
|
|
|
|
}
|
|
// Handle the floor data
|
|
else if (entity.floor) {
|
|
const { buildingId, id, floorName } = entity.floor;
|
|
const updatedBuildings = updatedProject?.buildings?.map((building) =>
|
|
building.id == buildingId
|
|
? {
|
|
...building,
|
|
floors: building.floors
|
|
.map((floor) =>
|
|
floor.id === id
|
|
? {
|
|
...floor,
|
|
floorName, // Update the floor name only
|
|
// Keep other properties as they are (including workArea)
|
|
}
|
|
: floor
|
|
)
|
|
// Add the new floor if it doesn't already exist
|
|
.concat(
|
|
!building.floors.some((floor) => floor.id === id)
|
|
? [{ id: id, floorName, workAreas: [] }] // New floor added with workArea set to null
|
|
: []
|
|
),
|
|
}
|
|
: building
|
|
);
|
|
|
|
updatedProject.buildings = updatedBuildings;
|
|
|
|
// Cache the updated project
|
|
cacheData("projectInfo", {
|
|
projectId: updatedProject.id,
|
|
data: updatedProject,
|
|
});
|
|
setProject( updatedProject );
|
|
// closeFloorModel()
|
|
}
|
|
// Handle the work area data
|
|
else if ( entity.workArea )
|
|
{
|
|
let buildingId = infraObject[0].workArea.buildingId;
|
|
|
|
const { floorId, areaName, id } = entity.workArea;
|
|
// Check if the workArea exists, otherwise create a new one
|
|
const updatedBuildings = updatedProject.buildings.map((building) =>
|
|
building.id == buildingId
|
|
? {
|
|
...building,
|
|
floors: building.floors.map((floor) =>
|
|
floor.id == floorId
|
|
? {
|
|
...floor,
|
|
workAreas: floor.workAreas.some(
|
|
(workArea) => workArea.id === id
|
|
)
|
|
? floor.workAreas.map((workArea) =>
|
|
workArea.id === id
|
|
? { ...workArea, areaName }
|
|
: workArea
|
|
)
|
|
: [
|
|
...floor.workAreas,
|
|
{ id, areaName, workItems: [] },
|
|
],
|
|
}
|
|
: floor
|
|
),
|
|
}
|
|
: building
|
|
);
|
|
|
|
updatedProject.buildings = updatedBuildings;
|
|
|
|
// Update the cache for work areas
|
|
cacheData("projectInfo", {
|
|
projectId: updatedProject.id,
|
|
data: updatedProject,
|
|
});
|
|
setProject( updatedProject );
|
|
// closeWorkAreaModel()
|
|
}
|
|
// Handle the task (workItem) data
|
|
else {
|
|
console.error("Unsupported data type for submitData", entity);
|
|
}
|
|
} catch (Err) {
|
|
showToast("Somthing wrong", "error");
|
|
}
|
|
};
|
|
|
|
|
|
const toggleBuilding = (id) => {
|
|
setExpandedBuildings((prev) =>
|
|
prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id]
|
|
);
|
|
};
|
|
|
|
const handleModalData = (type, modaldata) => {
|
|
setModalConfig({ type: type, data: modaldata });
|
|
};
|
|
const openModal = () => {
|
|
const modalElement = document.getElementById("building-model");
|
|
const modal = new Modal(modalElement, {
|
|
backdrop: false,
|
|
keyboard: true,
|
|
focus: true,
|
|
});
|
|
modal.show();
|
|
};
|
|
const closeModal = () => {
|
|
setIsModalOpen(false);
|
|
setModalConfig(null);
|
|
|
|
const modalElement = document.getElementById("building-model");
|
|
if (modalElement) {
|
|
modalElement.classList.remove("show"); // Remove modal visibility class
|
|
modalElement.style.display = "none"; // Hide the modal element
|
|
}
|
|
|
|
document.body.classList.remove("modal-open"); // Remove modal-open class from body
|
|
|
|
// Remove the modal backdrop
|
|
const backdropElement = document.querySelector(".modal-backdrop");
|
|
if (backdropElement) {
|
|
backdropElement.classList.remove("modal-backdrop"); // Remove backdrop class
|
|
backdropElement.style.display = "none"; // Hide the backdrop element
|
|
}
|
|
document.body.style.overflow = "auto";
|
|
};
|
|
|
|
const handleShow = () => setShowModal(true);
|
|
const handleClose = () => setShowModal(false);
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className={`modal fade ${showModal ? "show" : ""}`}
|
|
tabIndex="-1"
|
|
role="dialog"
|
|
style={{ display: showModal ? "block" : "none" }}
|
|
aria-hidden={!showModal}
|
|
>
|
|
<BuildingModel
|
|
project={project}
|
|
onClose={handleClose}
|
|
onSubmit={handleBuildingModelFormSubmit}
|
|
clearTrigger={clearFormTrigger}
|
|
onClearComplete={() => setClearFormTrigger(false)}
|
|
></BuildingModel>
|
|
</div>
|
|
{isFloorModalOpen && (
|
|
<div
|
|
className="modal fade show"
|
|
id="floor-model"
|
|
tabIndex="-1"
|
|
role="dialog"
|
|
style={{ display: "block" }}
|
|
aria-hidden="false"
|
|
>
|
|
<FloorModel
|
|
project={project}
|
|
onClose={closeFloorModel}
|
|
onSubmit={handleFloorModelFormSubmit}
|
|
clearTrigger={clearFormTrigger}
|
|
onClearComplete={() => setClearFormTrigger(false)}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{isWorkAreaModelOpen && (
|
|
<div
|
|
className="modal fade show"
|
|
id="work-area-model"
|
|
tabIndex="-1"
|
|
role="dialog"
|
|
style={{ display: "block" }}
|
|
aria-hidden="false"
|
|
>
|
|
<WorkAreaModel
|
|
project={project}
|
|
onClose={closeWorkAreaModel}
|
|
onSubmit={handleWorkAreaModelFormSubmit}
|
|
clearTrigger={clearFormTrigger}
|
|
onClearComplete={() => setClearFormTrigger(false)}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{isTaskModelOpen && (
|
|
<div
|
|
className="modal fade show"
|
|
id="task-model"
|
|
tabIndex="-1"
|
|
role="dialog"
|
|
style={{ display: "block" }}
|
|
aria-hidden="false"
|
|
>
|
|
<TaskModel
|
|
project={project}
|
|
|
|
onClose={closeTaskModel}
|
|
onSubmit={handleTaskModelFormSubmit}
|
|
clearTrigger={clearFormTrigger}
|
|
onClearComplete={() => setClearFormTrigger(false)}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{isModalOpen && (
|
|
<ProjectModal modalConfig={modalConfig} closeModal={closeModal} />
|
|
)}
|
|
|
|
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
|
<div className="card">
|
|
<div className="card-body" style={{ padding: "0.5rem" }}>
|
|
<div className="align-items-center">
|
|
<div className="row ">
|
|
<div
|
|
className={`col-12 text-end mb-1 ${
|
|
!ManageInfra && "d-none"
|
|
} `}
|
|
>
|
|
<button
|
|
type="button"
|
|
className="link-button link-button-sm m-1 "
|
|
onClick={handleShow}
|
|
>
|
|
<i className="bx bx-plus-circle me-2"></i>
|
|
Manage Building
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="link-button m-1"
|
|
onClick={() => openFloorModel()}
|
|
>
|
|
<i className="bx bx-plus-circle me-2"></i>
|
|
Manage Floors
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="link-button m-1"
|
|
onClick={() => openWorkAreaModel()}
|
|
>
|
|
<i className="bx bx-plus-circle me-2"></i>
|
|
Manage Work Areas
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="link-button m-1"
|
|
onClick={() => openTaskModel()}
|
|
>
|
|
<i className="bx bx-plus-circle me-2"></i>
|
|
Create Tasks
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div className="row ">
|
|
{loading && <p>Loading....</p>}
|
|
{project && project.buildings?.length > 0 && (
|
|
<InfraTable
|
|
buildings={project?.buildings}
|
|
project={project}
|
|
handleFloor={submitData}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ProjectInfra;
|