updated project infra components and added assigntask
This commit is contained in:
parent
1451c1aff7
commit
ddfbed1020
81
src/ModalContext.jsx
Normal file
81
src/ModalContext.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React, { createContext, useContext, useState, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
const ModalContext = createContext();
|
||||||
|
|
||||||
|
export const useModal = () => useContext(ModalContext);
|
||||||
|
|
||||||
|
// ModalProvider to manage modal state and expose functionality to the rest of the app
|
||||||
|
export const ModalProvider = ({ children }) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [modalContent, setModalContent] = useState(null);
|
||||||
|
const [onSubmit, setOnSubmit] = useState(null);
|
||||||
|
const [modalSize, setModalSize] = useState('lg');
|
||||||
|
|
||||||
|
// Ref to track the modal content element
|
||||||
|
const modalRef = useRef(null);
|
||||||
|
|
||||||
|
const openModal = (content, onSubmitCallback, size = 'lg') => {
|
||||||
|
setModalContent(content); // Set modal content dynamically
|
||||||
|
setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically
|
||||||
|
setIsOpen(true); // Open the modal
|
||||||
|
setModalSize(size); // Set the modal size
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to close the modal
|
||||||
|
const closeModal = () => {
|
||||||
|
setIsOpen(false); // Close the modal
|
||||||
|
setModalContent(null); // Clear modal content
|
||||||
|
setOnSubmit(null); // Clear the submit callback
|
||||||
|
setModalSize('lg'); // Reset modal size
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (modalRef.current && !modalRef.current.contains(event.target)) {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalContext.Provider value={{ isOpen, openModal, closeModal, modalContent, modalSize, onSubmit }}>
|
||||||
|
{children}
|
||||||
|
|
||||||
|
{isOpen && (
|
||||||
|
<div style={overlayStyles}>
|
||||||
|
<div ref={modalRef} style={{ ...modalStyles, maxWidth: modalSize === 'sm' ? '400px' : '800px' }}>
|
||||||
|
<div>{modalContent}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ModalContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const overlayStyles = {
|
||||||
|
position: "fixed",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
zIndex: 1050,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modalStyles = {
|
||||||
|
backgroundColor: "white",
|
||||||
|
padding: "20px",
|
||||||
|
borderRadius: "5px",
|
||||||
|
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
||||||
|
width: "90%",
|
||||||
|
maxWidth: "800px",
|
||||||
|
};
|
||||||
@ -9,7 +9,7 @@ import { useNavigate } from "react-router-dom";
|
|||||||
|
|
||||||
const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
||||||
{
|
{
|
||||||
|
console.log(attendance)
|
||||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(attendance, 5);
|
const { currentPage, totalPages, currentItems, paginate } = usePagination(attendance, 5);
|
||||||
const [loading,setLoading] = useState(false);
|
const [loading,setLoading] = useState(false);
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -38,7 +38,7 @@ const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
|||||||
return checkInB - checkInA; // Sort in descending order of checkInTime
|
return checkInB - checkInA; // Sort in descending order of checkInTime
|
||||||
})
|
})
|
||||||
.map( ( item ) => (
|
.map( ( item ) => (
|
||||||
<tr key={item.id}>
|
<tr key={item.employeeId}>
|
||||||
<td colSpan={2}>
|
<td colSpan={2}>
|
||||||
<div className="d-flex justify-content-start align-items-center">
|
<div className="d-flex justify-content-start align-items-center">
|
||||||
<Avatar
|
<Avatar
|
||||||
@ -60,9 +60,10 @@ const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<span className="badge bg-label-primary me-1">
|
{/* <span className="badge bg-label-primary me-1">
|
||||||
{getRole(item.roleID)}
|
{getRole(item.roleID)}
|
||||||
</span>
|
</span> */}
|
||||||
|
---
|
||||||
</td>
|
</td>
|
||||||
<td>{item.checkInTime ? convertShortTime(item.checkInTime):"--"}</td>
|
<td>{item.checkInTime ? convertShortTime(item.checkInTime):"--"}</td>
|
||||||
<td>{item.checkOutTime ? convertShortTime(item.checkOutTime):"--"}</td>
|
<td>{item.checkOutTime ? convertShortTime(item.checkOutTime):"--"}</td>
|
||||||
|
|||||||
@ -1,492 +1,71 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "../../components/Project/ProjectInfra.css";
|
import "../../components/Project/ProjectInfra.css";
|
||||||
import BuildingModel from "../../components/Project/BuildingModel";
|
import BuildingModel from "../Project/Infrastructure/BuildingModel";
|
||||||
import FloorModel from "../../components/Project/FloorModel";
|
import FloorModel from "../Project/Infrastructure/FloorModel";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import WorkAreaModel from "../../components/Project/WorkAreaModel";
|
import WorkAreaModel from "../Project/Infrastructure/WorkAreaModel";
|
||||||
import TaskModel from "../../components/Project/TaskModel";
|
import TaskModel from "../Project/Infrastructure/TaskModel";
|
||||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
import ProjectRepository from "../../repositories/ProjectRepository";
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
|
import {useProjectDetails, useProjects} from "../../hooks/useProjects";
|
||||||
|
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
||||||
|
import {MANAGE_PROJECT_INFRA} from "../../utils/constants";
|
||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {useProfile} from "../../hooks/useProfile";
|
||||||
|
import {setProjectId} from "../../slices/localVariablesSlice";
|
||||||
|
import InfraTable from "../Project/Infrastructure/InfraTable";
|
||||||
|
|
||||||
|
|
||||||
const InfraPlanning = ({ data, activityMaster, onDataChange }) => {
|
const InfraPlanning = () =>
|
||||||
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
|
||||||
const [project, setProject] = useState(data);
|
|
||||||
const [buildings, setBuildings] = useState(data?.buildings);
|
|
||||||
|
|
||||||
const [isBuildingModalOpen, setIsBuildingModalOpen] = useState(false);
|
|
||||||
const [isFloorModalOpen, setIsFloorModalOpen] = useState(false);
|
|
||||||
const [isWorkAreaModelOpen, setIsWorkAreaModalOpen] = useState(false);
|
|
||||||
const [isTaskModelOpen, setIsTaskModalOpen] = useState(false);
|
|
||||||
|
|
||||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
||||||
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setProject(data);
|
|
||||||
setBuildings(data?.buildings);
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const openModal = (projectData) => {
|
|
||||||
setIsCreateModalOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openFloorModel = (projectData) => {
|
|
||||||
setIsFloorModalOpen(true);
|
|
||||||
};
|
|
||||||
const closeFloorModel = () => {
|
|
||||||
setIsFloorModalOpen(false);
|
|
||||||
// const modalBackdrop = document.querySelector(".modal-backdrop");
|
|
||||||
// if (modalBackdrop) modalBackdrop.remove();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFloorModelFormSubmit = (updatedFloor) => {
|
|
||||||
if (updatedFloor.id == "") delete updatedFloor.id;
|
|
||||||
|
|
||||||
submitData([
|
|
||||||
{
|
{
|
||||||
building: null,
|
const {profile: LoggedUser} = useProfile()
|
||||||
floor: updatedFloor,
|
const dispatch = useDispatch()
|
||||||
workArea: null,
|
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
||||||
},
|
const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA )
|
||||||
]);
|
const {projects,loading:project_listLoader,error:projects_error} = useProjects()
|
||||||
};
|
const {projects_Details, loading: project_deatilsLoader, error: project_error} = useProjectDetails(selectedProject)
|
||||||
|
|
||||||
const submitData = (infraObject) => {
|
|
||||||
|
|
||||||
ProjectRepository.manageProjectInfra(infraObject)
|
|
||||||
.then((response) => {
|
|
||||||
fetchData();
|
|
||||||
onDataChange("building-change");
|
|
||||||
showToast("Details updated successfully.", "success");
|
|
||||||
setClearFormTrigger(true); // Set trigger to true
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
showToast(error.message, "error");
|
|
||||||
});
|
|
||||||
|
|
||||||
// api
|
|
||||||
// .post("/api/project/manage-infra", infraObject)
|
|
||||||
// .then((data) => {
|
|
||||||
// fetchData();
|
|
||||||
// onDataChange("building-change");
|
|
||||||
// showToast("Details updated successfully.", "success");
|
|
||||||
// setClearFormTrigger(true); // Set trigger to true
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// showToast(error.message, "error");
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
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 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 modalBackdrop = document.querySelector(".modal-backdrop");
|
|
||||||
// if (modalBackdrop) modalBackdrop.remove();
|
|
||||||
};
|
|
||||||
const handleTaskModelFormSubmit = (updatedModel) => {
|
|
||||||
if (updatedModel.id == "") updatedModel.id = 0;
|
|
||||||
|
|
||||||
//console.log("Form submitted:", updatedModel); // Replace this with an API call or state update
|
|
||||||
ProjectRepository.manageProjectTasks([updatedModel])
|
|
||||||
.then((response) => {
|
|
||||||
onDataChange("task-change");
|
|
||||||
showToast("Details updated successfully.", "success");
|
|
||||||
setClearFormTrigger(true); // Set trigger to true
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
showToast(error.message, "error");
|
|
||||||
});
|
|
||||||
|
|
||||||
// api
|
|
||||||
// .post("/api/project/task", [updatedModel])
|
|
||||||
// .then((data) => {
|
|
||||||
// onDataChange("task-change");
|
|
||||||
// showToast("Details updated successfully.", "success");
|
|
||||||
// setClearFormTrigger(true); // Set trigger to true
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// showToast(error.message, "error");
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleBuilding = (id) => {
|
|
||||||
setExpandedBuildings((prev) =>
|
|
||||||
prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getContent = (building) => {
|
|
||||||
let hasFloors =
|
|
||||||
building.floors && building.floors.length > 0 ? true : false;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{(() => {
|
|
||||||
if (hasFloors) {
|
|
||||||
return building.floors.map((floor) => (
|
|
||||||
<React.Fragment key={floor.id}>
|
|
||||||
{floor.workAreas.length > 0 ? (
|
|
||||||
floor.workAreas.map((workArea) => (
|
|
||||||
<React.Fragment key={workArea.id}>
|
|
||||||
<tr>
|
|
||||||
<td colSpan="4" className="text-start table-cell">
|
|
||||||
<div className="row ps-2">
|
|
||||||
<div className="col-6">
|
|
||||||
{" "}
|
|
||||||
<h6>
|
|
||||||
<span>
|
|
||||||
{" "}
|
|
||||||
{floor.floorName} - {workArea.areaName} {" "}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
<div className="col-6 text-end">
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end me-2"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#floor-model"
|
|
||||||
onClick={() => openFloorModel()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-edit-alt me-2"></i>
|
|
||||||
Edit Floor
|
|
||||||
</a> */}
|
|
||||||
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Activities
|
|
||||||
</a> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{workArea.workItems.length > 0 ? (
|
|
||||||
<tr>
|
|
||||||
{" "}
|
|
||||||
<td colSpan={4}>
|
|
||||||
<table
|
|
||||||
className="table ms-4"
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Activity</th>
|
|
||||||
<th>Planned</th>
|
|
||||||
<th>Complated</th>
|
|
||||||
<th>Progress</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="table-border-bottom-0">
|
|
||||||
{workArea.workItems.map((workItem) => (
|
|
||||||
<React.Fragment key={workItem.workItemId}>
|
|
||||||
<tr>
|
|
||||||
<td className="text-start table-cell-small">
|
|
||||||
<i className="bx bx-right-arrow-alt"></i>
|
|
||||||
<span className="fw-medium">
|
|
||||||
{workItem.workItem.activityMaster
|
|
||||||
? workItem.workItem.activityMaster
|
|
||||||
.activityName
|
|
||||||
: "NA"}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="text-center">
|
|
||||||
{workItem.workItem
|
|
||||||
? workItem.workItem.plannedWork
|
|
||||||
: "NA"}
|
|
||||||
</td>
|
|
||||||
<td className="text-center">
|
|
||||||
{workItem.workItem
|
|
||||||
? workItem.workItem.completedWork
|
|
||||||
: "NA"}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td
|
|
||||||
className="text-center"
|
|
||||||
style={{ width: "15%" }}
|
|
||||||
>
|
|
||||||
<div className="progress p-0">
|
|
||||||
<div
|
|
||||||
className="progress-bar"
|
|
||||||
role="progressbar"
|
|
||||||
style={{
|
|
||||||
width: getProgress(
|
|
||||||
workItem.workItem.plannedWork,
|
|
||||||
workItem.workItem.completedWork
|
|
||||||
),
|
|
||||||
height: "10px",
|
|
||||||
}}
|
|
||||||
aria-valuenow={
|
|
||||||
workItem.workItem
|
|
||||||
? workItem.workItem
|
|
||||||
.completedWork
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
aria-valuemin="0"
|
|
||||||
aria-valuemax={
|
|
||||||
workItem.workItem
|
|
||||||
? workItem.workItem.plannedWork
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
{/* <input type="range" id="customRange1" max="@workItem.PlannedWork" min="0" value="@workItem.CompletedWork"> */}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div className="dropdown">
|
|
||||||
<button
|
|
||||||
aria-label="Modify"
|
|
||||||
type="button"
|
|
||||||
className="btn p-0 dropdown-toggle hide-arrow"
|
|
||||||
>
|
|
||||||
<i class="bx bxs-edit me-2 text-primary"></i>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Delete"
|
|
||||||
type="button"
|
|
||||||
className="btn p-0 dropdown-toggle hide-arrow"
|
|
||||||
>
|
|
||||||
<i className="bx bx-trash me-1 text-danger"></i>{" "}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>{" "}
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>{" "}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
) : (
|
|
||||||
<span></span>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<React.Fragment key={building.id + floor.id}>
|
|
||||||
<tr>
|
|
||||||
<td colSpan="4" className="text-start table-cell">
|
|
||||||
<div className="row ps-2">
|
|
||||||
<div className="col-6">
|
|
||||||
{" "}
|
|
||||||
<h6>
|
|
||||||
<span> {floor.floorName} </span>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
<div className="col-6 text-end">
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end me-2"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#floor-model"
|
|
||||||
onClick={() => openFloorModel()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-edit-alt me-2"></i>
|
|
||||||
Edit Floor
|
|
||||||
</a> */}
|
|
||||||
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Work Area
|
|
||||||
</a> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>No Floors Added, Please add them</p>
|
|
||||||
{/* <p>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
className="btn btn-sm btn-danger m-1"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Floors
|
|
||||||
</button>
|
|
||||||
</p> */}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProgress = (planned, completed) => {
|
|
||||||
return (completed * 100) / planned + "%";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{isBuildingModalOpen && (
|
|
||||||
<div
|
|
||||||
className={`modal fade `}
|
|
||||||
id="building-model"
|
|
||||||
tabIndex="-1"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<BuildingModel
|
|
||||||
project={data}
|
|
||||||
onClose={closeBuildingModel}
|
|
||||||
onSubmit={handleBuildingModelFormSubmit}
|
|
||||||
clearTrigger={clearFormTrigger}
|
|
||||||
onClearComplete={() => setClearFormTrigger(false)}
|
|
||||||
></BuildingModel>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isFloorModalOpen && (
|
|
||||||
<div
|
|
||||||
className={`modal fade `}
|
|
||||||
id="floor-model"
|
|
||||||
tabIndex="-1"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<FloorModel
|
|
||||||
project={data}
|
|
||||||
// building={null}
|
|
||||||
onClose={closeFloorModel}
|
|
||||||
onSubmit={handleFloorModelFormSubmit}
|
|
||||||
clearTrigger={clearFormTrigger}
|
|
||||||
onClearComplete={() => setClearFormTrigger(false)}
|
|
||||||
></FloorModel>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isWorkAreaModelOpen && (
|
|
||||||
<div
|
|
||||||
className={`modal fade `}
|
|
||||||
id="work-area-model"
|
|
||||||
tabIndex="-1"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<WorkAreaModel
|
|
||||||
project={data}
|
|
||||||
// building={null}
|
|
||||||
onClose={closeWorkAreaModel}
|
|
||||||
onSubmit={handleWorkAreaModelFormSubmit}
|
|
||||||
clearTrigger={clearFormTrigger}
|
|
||||||
onClearComplete={() => setClearFormTrigger(false)}
|
|
||||||
></WorkAreaModel>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isTaskModelOpen && (
|
|
||||||
<div
|
|
||||||
className={`modal fade `}
|
|
||||||
id="task-model"
|
|
||||||
tabIndex="-1"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<TaskModel
|
|
||||||
project={data}
|
|
||||||
activities={activityMaster}
|
|
||||||
onClose={closeTaskModel}
|
|
||||||
onSubmit={handleTaskModelFormSubmit}
|
|
||||||
clearTrigger={clearFormTrigger}
|
|
||||||
onClearComplete={() => setClearFormTrigger(false)}
|
|
||||||
></TaskModel>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
|
||||||
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
{/* <div className="card-header pb-4"></div> */}
|
|
||||||
|
|
||||||
<div className="card-body" style={{ padding: "0.5rem" }}>
|
<div className="card-body" style={{ padding: "0.5rem" }}>
|
||||||
<div className="align-items-center">
|
<div className="align-items-center">
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
<div className="col-12 text-end mb-1">
|
<div className="col-sm-3 col-8 text-start mb-1">
|
||||||
|
<select name="DataTables_Table_0_length"
|
||||||
|
aria-controls="DataTables_Table_0"
|
||||||
|
className="form-select form-select-sm"
|
||||||
|
value={selectedProject}
|
||||||
|
onChange={(e)=>dispatch(setProjectId(e.target.value))}
|
||||||
|
aria-label=""
|
||||||
|
>
|
||||||
|
{(project_listLoader || projects.length < 0) && <option value="Loading..." disabled>Loading...</option> }
|
||||||
|
|
||||||
|
{!project_listLoader && projects?.filter(project =>
|
||||||
|
LoggedUser?.projects?.map(Number).includes(project.id)).map((project)=>(
|
||||||
|
<option value={project.id}>{project.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{/* <div className={`col-12 text-end mb-1 ${!ManageInfra && 'd-none'} `} >
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="link-button link-button-sm m-1 "
|
className="link-button link-button-sm m-1 "
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
data-bs-target="#building-model"
|
data-bs-target="#building-model"
|
||||||
onClick={() => openBuildingModel()}
|
// onClick={() => openBuildingModel()}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Manage Building
|
Manage Building
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
className="link-button m-1"
|
className="link-button m-1"
|
||||||
data-bs-target="#floor-model"
|
data-bs-target="#floor-model"
|
||||||
onClick={() => openFloorModel()}
|
// onClick={() => openFloorModel()}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Manage Floors
|
Manage Floors
|
||||||
@ -497,7 +76,7 @@ const InfraPlanning = ({ data, activityMaster, onDataChange }) => {
|
|||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
className="link-button m-1"
|
className="link-button m-1"
|
||||||
data-bs-target="#work-area-model"
|
data-bs-target="#work-area-model"
|
||||||
onClick={() => openWorkAreaModel()}
|
// onClick={() => openWorkAreaModel()}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Manage Work Areas
|
Manage Work Areas
|
||||||
@ -507,61 +86,20 @@ const InfraPlanning = ({ data, activityMaster, onDataChange }) => {
|
|||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
className="link-button m-1"
|
className="link-button m-1"
|
||||||
data-bs-target="#task-model"
|
data-bs-target="#task-model"
|
||||||
onClick={() => openTaskModel()}
|
// onClick={() => openTaskModel()}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Manage Tasks
|
Manage Tasks
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
<div className="col-12">
|
<InfraTable buildings={projects_Details?.buildings}/>
|
||||||
{buildings && buildings.length > 0 && (
|
|
||||||
<table className="table table-bordered">
|
|
||||||
<tbody>
|
|
||||||
{buildings.map((building) => (
|
|
||||||
building.floors && building.floors.length > 0 && (
|
|
||||||
<React.Fragment key={building.id}>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
colSpan="4"
|
|
||||||
className="text-start"
|
|
||||||
style={{
|
|
||||||
background: "#f0f0f0",
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
|
||||||
onClick={() => toggleBuilding(building.id)}
|
|
||||||
>
|
|
||||||
<div className="row">
|
|
||||||
<h5 style={{ marginBottom: "0px" }}>
|
|
||||||
|
|
||||||
{ building.name}
|
|
||||||
{expandedBuildings.includes(building.id) ? (
|
|
||||||
<i className="bx bx-chevron-down"></i>
|
|
||||||
) : (
|
|
||||||
<i className="bx bx-chevron-right"></i>
|
|
||||||
)}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{expandedBuildings.includes(building.id) && getContent(building)}
|
|
||||||
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,32 @@
|
|||||||
import React, { useState,useEffect } from "react";
|
import React, { useState,useEffect } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { changeMaster } from "../../slices/localVariablesSlice";
|
import { changeMaster } from "../../slices/localVariablesSlice";
|
||||||
import useMaster from "../../hooks/masterHook/useMaster";
|
import useMaster from "../../hooks/masterHook/useMaster";
|
||||||
import { employee } from "../../data/masters";
|
import { employee } from "../../data/masters";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { getCachedData } from "../../slices/apiDataManager";
|
import { getCachedData } from "../../slices/apiDataManager";
|
||||||
|
import {useModal} from "../../ModalContext";
|
||||||
|
import {useProjects} from "../../hooks/useProjects";
|
||||||
|
import {useEmployeesAllOrByProjectId} from "../../hooks/useEmployees";
|
||||||
|
import {TasksRepository} from "../../repositories/ProjectRepository";
|
||||||
|
import showToast from "../../services/toastService";
|
||||||
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
selectedEmployees: z.array( z.number() ).min( 1, {message: "At least one employee must be selected"} ),
|
selectedEmployees: z.array( z.number() ).min( 1, {message: "At least one employee must be selected"} ),
|
||||||
|
description: z.string().min( 1, {message: "description required"} ),
|
||||||
|
pannedTask: z.number()
|
||||||
|
.refine(value => value > 0, { message: "pannedTask should be greater than zero" })
|
||||||
|
.refine(value => value !== undefined, { message: "pannedTask is required" }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const AssignRoleModel = ( {assignData,onClose}) => {
|
const AssignRoleModel = ( {assignData,onClose}) => {
|
||||||
const[target,setTraget] = useState("")
|
const { openModal, closeModal } = useModal()
|
||||||
|
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
||||||
|
const {employees} = useEmployeesAllOrByProjectId( selectedProject )
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const {data,loading} = useMaster()
|
const {data,loading} = useMaster()
|
||||||
const jobRoleData = getCachedData("Job Role")
|
const jobRoleData = getCachedData("Job Role")
|
||||||
@ -26,7 +38,8 @@ const [selectedEmployees, setSelectedEmployees] = useState([]);
|
|||||||
|
|
||||||
const { handleSubmit, control, setValue, watch, formState: { errors } } = useForm({
|
const { handleSubmit, control, setValue, watch, formState: { errors } } = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
selectedEmployees: []
|
selectedEmployees: [],
|
||||||
|
description:""
|
||||||
},
|
},
|
||||||
resolver: (data) => {
|
resolver: (data) => {
|
||||||
const validation = schema.safeParse(data);
|
const validation = schema.safeParse(data);
|
||||||
@ -36,13 +49,13 @@ const { handleSubmit, control, setValue, watch, formState: { errors } } = useFor
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleRoleChange = (event) => {
|
const handleRoleChange = (event) => {
|
||||||
setSelectedRole(event.target.value);
|
setSelectedRole(event.plannedTask.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const filteredEmployees = selectedRole === "all"
|
const filteredEmployees = selectedRole === "all"
|
||||||
? employee
|
? employees
|
||||||
: employee.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
: employees.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
||||||
|
|
||||||
|
|
||||||
// not need currently for this fun
|
// not need currently for this fun
|
||||||
@ -56,7 +69,7 @@ const handleEmployeeSelection = (employeeId,field) => {
|
|||||||
} else {
|
} else {
|
||||||
updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||||
}
|
}
|
||||||
field.onChange(updatedSelection); // Update form state with new selection
|
field.onChange(updatedSelection);
|
||||||
return updatedSelection;
|
return updatedSelection;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -65,17 +78,34 @@ const handleEmployeeSelection = (employeeId,field) => {
|
|||||||
const removeEmployee = (employeeId) => {
|
const removeEmployee = (employeeId) => {
|
||||||
setSelectedEmployees((prevSelected) => {
|
setSelectedEmployees((prevSelected) => {
|
||||||
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||||
setValue("selectedEmployees", updatedSelection); // Ensure form state is updated
|
setValue("selectedEmployees", updatedSelection);
|
||||||
return updatedSelection;
|
return updatedSelection;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const onSubmit = async(data) => {
|
||||||
console.log( {...data.selectedEmployees,target});
|
const formattedData = {
|
||||||
onClose()
|
taskTeam: data.selectedEmployees,
|
||||||
|
plannedTask: parseInt( plannedTask, 10 ),
|
||||||
|
description: data.description,
|
||||||
|
assignmentDate: new Date().toISOString(),
|
||||||
|
workItemId:assignData?.workItem?.workItem.id
|
||||||
};
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
let response = await TasksRepository.assignTask( formattedData );
|
||||||
|
console.log( response )
|
||||||
|
showToast( "Task Successfully Assigend", "success" )
|
||||||
|
closeModal()
|
||||||
|
} catch ( error )
|
||||||
|
{
|
||||||
|
showToast("something wrong","error")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
console.log(assignData?.workItem?.workItem)
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
dispatch(changeMaster("Job Role"))
|
dispatch(changeMaster("Job Role"))
|
||||||
return ()=> setSelectedRole("all")
|
return ()=> setSelectedRole("all")
|
||||||
@ -84,8 +114,7 @@ useEffect(()=>{
|
|||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
|
|
||||||
|
<div className="container my-1">
|
||||||
<div className="container-fluid my-1">
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<div className="bs-stepper wizard-numbered d-flex justify-content-center align-items-center flex-wrap">
|
<div className="bs-stepper wizard-numbered d-flex justify-content-center align-items-center flex-wrap">
|
||||||
{[
|
{[
|
||||||
@ -143,7 +172,7 @@ useEffect(()=>{
|
|||||||
<div className="col-sm-12">
|
<div className="col-sm-12">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{filteredEmployees.map((emp) => {
|
{filteredEmployees.map((emp) => {
|
||||||
const jobRole = jobRoleData?.find((role) => role.id === emp.JobRoleId);
|
const jobRole = jobRoleData?.find((role) => role.id === emp.jobRoleId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={emp.id} className="col-6 col-sm-4 col-md-4 col-lg-3 mb-1">
|
<div key={emp.id} className="col-6 col-sm-4 col-md-4 col-lg-3 mb-1">
|
||||||
@ -161,18 +190,14 @@ useEffect(()=>{
|
|||||||
value={emp.id}
|
value={emp.id}
|
||||||
checked={field.value.includes(emp.id)} // Ensure the checkbox reflects the current form state
|
checked={field.value.includes(emp.id)} // Ensure the checkbox reflects the current form state
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
// Directly update the form value
|
|
||||||
handleEmployeeSelection( emp.id, field )
|
handleEmployeeSelection( emp.id, field )
|
||||||
// const updatedSelection = field.value.includes(emp.id)
|
|
||||||
// ? field.value.filter((id) => id !== emp.id)
|
|
||||||
// : [...field.value, emp.id];
|
|
||||||
// field.onChange(updatedSelection); // Directly update form value
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="list-content">
|
<div className="list-content">
|
||||||
<h6 className="mb-0">{emp.FirtsName} {emp.LastName}</h6>
|
<h6 className="mb-0">{emp.firstName
|
||||||
|
} {emp.lastName}</h6>
|
||||||
<small className="text-muted">
|
<small className="text-muted">
|
||||||
{loading && (<p className="skeleton para" style={{height:"7px"}}></p>)}
|
{loading && (<p className="skeleton para" style={{height:"7px"}}></p>)}
|
||||||
{data && !loading && (jobRole ? jobRole.name : 'Unknown Role')}
|
{data && !loading && (jobRole ? jobRole.name : 'Unknown Role')}
|
||||||
@ -187,16 +212,15 @@ useEffect(()=>{
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
{selectedEmployees.length > 0 && (
|
{selectedEmployees.length > 0 && (
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
<div className="text-start px-2">
|
<div className="text-start px-2">
|
||||||
{selectedEmployees.map((empId) => {
|
{selectedEmployees.map((empId) => {
|
||||||
const emp = employee.find((emp) => emp.id === empId);
|
const emp = employees.find((emp) => emp.id === empId);
|
||||||
return (
|
return (
|
||||||
<span key={empId} className="badge bg-label-primary d-inline-flex align-items-center gap-2 me-1 p-2 mb-2">
|
<span key={empId} className="badge bg-label-primary d-inline-flex align-items-center gap-2 me-1 p-2 mb-2">
|
||||||
{emp.FirtsName} {emp.LastName}
|
{emp.firstName
|
||||||
|
} {emp.lastName}
|
||||||
<p
|
<p
|
||||||
type="button"
|
type="button"
|
||||||
className=" btn-close-white p-0 m-0"
|
className=" btn-close-white p-0 m-0"
|
||||||
@ -212,7 +236,11 @@ useEffect(()=>{
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{errors.selectedEmployees && (
|
||||||
|
<div className="danger-text mt-1">
|
||||||
|
<p>{errors.selectedEmployees[0]}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div class="col-md text-start mx-0 px-0">
|
<div class="col-md text-start mx-0 px-0">
|
||||||
<div class="form-check form-check-inline mt-4 px-1">
|
<div class="form-check form-check-inline mt-4 px-1">
|
||||||
<label className="form-text fs-6" for="inlineCheckbox1">Pending Work</label>
|
<label className="form-text fs-6" for="inlineCheckbox1">Pending Work</label>
|
||||||
@ -220,22 +248,35 @@ useEffect(()=>{
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-check form-check-inline col-sm-2 col">
|
<div className="form-check form-check-inline col-sm-2 col">
|
||||||
<label for="defaultFormControlInput" className="form-label">Target</label>
|
<label for="defaultFormControlInput" className="form-label">Target</label>
|
||||||
<input type="text" className="form-control form-control-sm " value={target} onChange={(e)=>setTraget(e.target.value)} id="defaultFormControlInput" aria-describedby="defaultFormControlHelp" />
|
<Controller name="pannedTask" control={control} render={( {field} ) => (
|
||||||
</div>
|
<input type="text" className="form-control form-control-sm " {...field} />
|
||||||
</div>
|
)} />
|
||||||
|
{errors.pannedTask && (
|
||||||
|
<div className="danger-text">
|
||||||
|
<p>{errors.pannedTask.message}</p>
|
||||||
{errors.selectedEmployees && (
|
|
||||||
<div className="danger-text mt-2">
|
|
||||||
<p>{errors.selectedEmployees[0]}</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="exampleFormControlTextarea1" className="form-label">Description</label>
|
||||||
|
<Controller
|
||||||
|
name="description"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<textarea
|
||||||
|
{...field}
|
||||||
|
className="form-control"
|
||||||
|
id="exampleFormControlTextarea1"
|
||||||
|
rows="3"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description && ( <div>{errors.description.message }</div>)}
|
||||||
|
|
||||||
<div className="col-12 d-flex justify-content-center align-items-center gap-sm-6 gap-8 text-center">
|
<div className="col-12 d-flex justify-content-center align-items-center gap-sm-6 gap-8 text-center mt-1">
|
||||||
<button type="submit" className="btn btn-sm btn-primary ">Submit</button>
|
<button type="submit" className="btn btn-sm btn-primary ">Submit</button>
|
||||||
<button type="reset" className="btn btn-sm btn-label-secondary" data-bs-dismiss="modal" aria-label="Close">
|
<button type="reset" className="btn btn-sm btn-label-secondary" data-bs-dismiss="modal" aria-label="Close" onClick={closeModal}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,140 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
const defaultModel = {
|
|
||||||
id: "",
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
projectId: "",
|
|
||||||
};
|
|
||||||
const BuildingModel = ({
|
|
||||||
project,
|
|
||||||
onClose,
|
|
||||||
onSubmit,
|
|
||||||
clearTrigger,
|
|
||||||
onClearComplete,
|
|
||||||
}) => {
|
|
||||||
const [formData, setFormData] = useState(defaultModel);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (clearTrigger) {
|
|
||||||
setFormData(defaultModel); // Clear form
|
|
||||||
onClearComplete(); // Notify parent that clearing is done
|
|
||||||
}
|
|
||||||
}, [clearTrigger, onClearComplete]);
|
|
||||||
|
|
||||||
// Handle input change
|
|
||||||
const handleChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData({ ...formData, [name]: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBuildigChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
const building = project.buildings.find((b) => b.id === Number(value));
|
|
||||||
if (building) {
|
|
||||||
delete building.floors;
|
|
||||||
building.projectId = project.id;
|
|
||||||
setFormData(building);
|
|
||||||
} else
|
|
||||||
setFormData({
|
|
||||||
id: "",
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
projectId: project.id,
|
|
||||||
});
|
|
||||||
//setFormData({ ...formData, [name]: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle form submission
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
formData.projectId = project.id;
|
|
||||||
|
|
||||||
onSubmit(formData); // Pass the updated data to the parent
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-body">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-close"
|
|
||||||
data-bs-dismiss="modal"
|
|
||||||
aria-label="Close"
|
|
||||||
></button>
|
|
||||||
<div className="text-center mb-2">
|
|
||||||
<h5 className="mb-2">Manage Buildings - {project.name}</h5>
|
|
||||||
</div>
|
|
||||||
<form className="row g-2" onSubmit={handleSubmit}>
|
|
||||||
<div className="col-12 col-md-12">
|
|
||||||
<label className="form-label" htmlFor="name">
|
|
||||||
Select Building
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="buildingId"
|
|
||||||
name="buildingId"
|
|
||||||
className="select2 form-select form-select-sm"
|
|
||||||
aria-label="Default select example"
|
|
||||||
onChange={handleBuildigChange}
|
|
||||||
value={formData.buildingId}
|
|
||||||
>
|
|
||||||
<option value="0">Add New Building</option>
|
|
||||||
{project.buildings.map((building) => (
|
|
||||||
<option key={building.id} value={building.id}>
|
|
||||||
{building.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="col-12 col-md-12">
|
|
||||||
<label className="form-label" htmlFor="name">
|
|
||||||
Building Name
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
className="form-control form-control-sm"
|
|
||||||
placeholder="Building Name"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={formData.name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="col-12 col-md-12">
|
|
||||||
<label className="form-label" htmlFor="description">
|
|
||||||
Description
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
type="text"
|
|
||||||
id="description"
|
|
||||||
rows="5"
|
|
||||||
name="description"
|
|
||||||
className="form-control form-control-sm"
|
|
||||||
placeholder="Description"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={formData.description}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-12 text-center">
|
|
||||||
<button type="submit" className="btn btn-primary me-3">
|
|
||||||
{formData.id ? "Edit Building" : "Add Building"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="reset"
|
|
||||||
className="btn btn-label-secondary"
|
|
||||||
data-bs-dismiss="modal"
|
|
||||||
aria-label="Close"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BuildingModel;
|
|
||||||
31
src/components/Project/Infrastructure/Building.jsx
Normal file
31
src/components/Project/Infrastructure/Building.jsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import React from "react";
|
||||||
|
const Building = ( {building, toggleBuilding, expandedBuildings, getContent} ) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={building.id}>
|
||||||
|
<tr className="overflow-auto">
|
||||||
|
<td
|
||||||
|
colSpan="4"
|
||||||
|
className="text-start"
|
||||||
|
style={{ background: "#f0f0f0", cursor: "pointer" }}
|
||||||
|
onClick={() => toggleBuilding(building.id)}
|
||||||
|
>
|
||||||
|
<div className="row table-responsive">
|
||||||
|
<h5 style={{ marginBottom: "0px" }}>
|
||||||
|
{building.name}
|
||||||
|
{expandedBuildings.includes(building.id) ? (
|
||||||
|
<i className="bx bx-chevron-down"></i>
|
||||||
|
) : (
|
||||||
|
<i className="bx bx-chevron-right"></i>
|
||||||
|
)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{expandedBuildings.includes(building.id) && getContent(building)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Building
|
||||||
129
src/components/Project/Infrastructure/BuildingModel.jsx
Normal file
129
src/components/Project/Infrastructure/BuildingModel.jsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import ProjectRepository from "../../../repositories/ProjectRepository";
|
||||||
|
|
||||||
|
// Zod validation schema
|
||||||
|
const buildingSchema = z.object({
|
||||||
|
Id: z.string().optional(),
|
||||||
|
name: z.string().min(1, "Building name is required"),
|
||||||
|
description: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Description is required")
|
||||||
|
.max(160, "Description cannot exceed 160 characters"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const BuildingModel = ({
|
||||||
|
project,
|
||||||
|
onSubmit,
|
||||||
|
clearTrigger,
|
||||||
|
onClearComplete,
|
||||||
|
editingBuilding = null,
|
||||||
|
}) => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
projectId: project.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset form data if clearTrigger is true, or if editing a building
|
||||||
|
useEffect(() => {
|
||||||
|
if (clearTrigger) {
|
||||||
|
setFormData({ id: "", name: "", description: "", projectId: project.id });
|
||||||
|
onClearComplete();
|
||||||
|
} else if (editingBuilding) {
|
||||||
|
setFormData({ ...editingBuilding, projectId: project.id });
|
||||||
|
}
|
||||||
|
}, [clearTrigger, onClearComplete, editingBuilding, project.id]);
|
||||||
|
|
||||||
|
const { register, handleSubmit, formState: { errors }, setValue } = useForm({
|
||||||
|
resolver: zodResolver(buildingSchema),
|
||||||
|
defaultValues: formData, // Set default values from formData state
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleBuildingChange = (e) => {
|
||||||
|
const selectedBuilding = project.buildings.find(b => b.id === +e.target.value);
|
||||||
|
if (selectedBuilding) {
|
||||||
|
setFormData({ ...selectedBuilding, projectId: project.id });
|
||||||
|
setValue("name", selectedBuilding.name); // Update name field
|
||||||
|
setValue("description", selectedBuilding.description); // Update description field
|
||||||
|
} else {
|
||||||
|
setFormData({ id: "", name: "", description: "", projectId: project.id });
|
||||||
|
setValue("name", "");
|
||||||
|
setValue("description", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmitHandler = async( data ) =>
|
||||||
|
{
|
||||||
|
onSubmit({ ...data, projectId: project.id });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-body">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-close"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"
|
||||||
|
></button>
|
||||||
|
<h5 className="text-center mb-2">Manage Buildings - {project.name}</h5>
|
||||||
|
<form onSubmit={handleSubmit(onSubmitHandler)} className="row g-2">
|
||||||
|
<div className="col-12">
|
||||||
|
<label className="form-label">Select Building</label>
|
||||||
|
<select
|
||||||
|
{...register("Id")}
|
||||||
|
className="select2 form-select form-select-sm"
|
||||||
|
onChange={(e) => { handleBuildingChange(e); }}
|
||||||
|
>
|
||||||
|
<option value="0">Add New Building</option>
|
||||||
|
{project.buildings.map((building) => (
|
||||||
|
<option key={building.id} value={building.id}>{building.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{errors.Id && <span className="danger-text">{errors.Id.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12">
|
||||||
|
<label className="form-label">
|
||||||
|
{formData.id ? "Rename Building Name" : "New Building Name"}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
{...register("name")}
|
||||||
|
type="text"
|
||||||
|
className="form-control form-control-sm"
|
||||||
|
/>
|
||||||
|
{errors.name && <span className="danger-text">{errors.name.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12">
|
||||||
|
<label className="form-label">Description</label>
|
||||||
|
<textarea
|
||||||
|
{...register("description")}
|
||||||
|
maxLength="160"
|
||||||
|
rows="5"
|
||||||
|
className="form-control form-control-sm"
|
||||||
|
/>
|
||||||
|
{errors.description && <span className="danger-text">{errors.description.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 text-center">
|
||||||
|
<button type="submit" className="btn btn-primary me-3">
|
||||||
|
{formData.id ? "Edit Building" : "Add Building"}
|
||||||
|
</button>
|
||||||
|
<button type="reset" className="btn btn-label-secondary" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BuildingModel;
|
||||||
29
src/components/Project/Infrastructure/Floor.jsx
Normal file
29
src/components/Project/Infrastructure/Floor.jsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
import WorkArea from "./WorkArea";
|
||||||
|
const Floor = ( {floor, workAreas,forBuilding} ) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={floor.id}>
|
||||||
|
{workAreas && workAreas.length > 0 ? (
|
||||||
|
workAreas.map((workArea) => (
|
||||||
|
<WorkArea forBuilding={forBuilding} key={workArea.id} workArea={workArea} floor={floor} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td colSpan="4" className="text-start">
|
||||||
|
<div className="row ps-2">
|
||||||
|
<div className="col-6">
|
||||||
|
<h6>
|
||||||
|
<span>{floor.floorName} </span>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Floor
|
||||||
@ -1,10 +1,20 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
|
||||||
|
// Zod validation schema
|
||||||
|
const floorSchema = z.object({
|
||||||
|
buildingId: z.string().min(1, "Building is required"),
|
||||||
|
id: z.string().min(1, "Floor is required").optional(),
|
||||||
|
floorName: z.string().min(1, "Floor Name is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Default model
|
||||||
const defaultModel = {
|
const defaultModel = {
|
||||||
id: "0",
|
id: "0",
|
||||||
floorName: "",
|
floorName: "",
|
||||||
buildingId: "0",
|
buildingId: "0",
|
||||||
projectId: "",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const FloorModel = ({
|
const FloorModel = ({
|
||||||
@ -15,67 +25,80 @@ const FloorModel = ({
|
|||||||
onClearComplete,
|
onClearComplete,
|
||||||
}) => {
|
}) => {
|
||||||
const [formData, setFormData] = useState(defaultModel);
|
const [formData, setFormData] = useState(defaultModel);
|
||||||
|
|
||||||
const [selectedBuilding, setSelectedBuilding] = useState({});
|
const [selectedBuilding, setSelectedBuilding] = useState({});
|
||||||
|
|
||||||
//if (floor && floor.id) setFormData(floor);
|
// Initialize the form with React Hook Form
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
reset,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm({
|
||||||
|
resolver: zodResolver(floorSchema),
|
||||||
|
defaultValues: defaultModel,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (clearTrigger) {
|
if (clearTrigger) {
|
||||||
setFormData(defaultModel); // Clear form
|
reset(defaultModel);
|
||||||
onClearComplete(); // Notify parent that clearing is done
|
onClearComplete();
|
||||||
}
|
}
|
||||||
}, [clearTrigger, onClearComplete]);
|
}, [clearTrigger, onClearComplete, reset]);
|
||||||
|
|
||||||
// Handle input change
|
// Handle building selection change
|
||||||
const handleChange = (e) => {
|
const handleBuildigChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const buildingId = e.target.value;
|
||||||
setFormData({ ...formData, [name]: value });
|
const building = project.buildings.find((b) => b.id === Number(buildingId));
|
||||||
|
if (building) {
|
||||||
|
setSelectedBuilding(building);
|
||||||
|
setFormData({
|
||||||
|
id: "",
|
||||||
|
floorName: "",
|
||||||
|
buildingId: building.id,
|
||||||
|
|
||||||
|
});
|
||||||
|
setValue("buildingId", building.id); // Set value for validation
|
||||||
|
setValue("id", "0"); // Reset floorId when changing building
|
||||||
|
} else {
|
||||||
|
setSelectedBuilding({});
|
||||||
|
setFormData({
|
||||||
|
id: "",
|
||||||
|
floorName: "",
|
||||||
|
buildingId: "0",
|
||||||
|
|
||||||
|
});
|
||||||
|
setValue("buildingId", "0");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle floor selection change
|
||||||
const handleFloorChange = (e) => {
|
const handleFloorChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const id = e.target.value;
|
||||||
const floor = selectedBuilding.floors.find((b) => b.id === Number(value));
|
const floor = selectedBuilding.floors.find((b) => b.id === Number(id));
|
||||||
if (floor) {
|
if (floor) {
|
||||||
setFormData({
|
setFormData({
|
||||||
id: floor.id,
|
id: floor.id,
|
||||||
floorName: floor.floorName,
|
floorName: floor.floorName,
|
||||||
buildingId: selectedBuilding.id,
|
buildingId: selectedBuilding.id,
|
||||||
projectId: project.id,
|
|
||||||
});
|
});
|
||||||
} else
|
setValue("floorName", floor.floorName); // Set floor name for form
|
||||||
|
} else {
|
||||||
setFormData({
|
setFormData({
|
||||||
id: "0",
|
id: "0",
|
||||||
floorName: "",
|
floorName: "",
|
||||||
buildingId: selectedBuilding.id,
|
buildingId: selectedBuilding.id,
|
||||||
projectId: project.id,
|
|
||||||
});
|
});
|
||||||
};
|
setValue("floorName", "");
|
||||||
const handleBuildigChange = (e) => {
|
}
|
||||||
const { name, value } = e.target;
|
|
||||||
const building = project.buildings.find((b) => b.id === Number(value));
|
|
||||||
if (building) {
|
|
||||||
setFormData({
|
|
||||||
id: "",
|
|
||||||
floorName: "",
|
|
||||||
buildingId: building.id,
|
|
||||||
projectId: project.id,
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
setFormData({
|
|
||||||
id: "",
|
|
||||||
floorName: "",
|
|
||||||
buildingId: "0",
|
|
||||||
projectId: project.id,
|
|
||||||
});
|
|
||||||
setSelectedBuilding(building);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
const handleSubmit = (e) => {
|
const onFormSubmit = (data) => {
|
||||||
e.preventDefault();
|
|
||||||
formData.projectId = project.id;
|
|
||||||
|
|
||||||
onSubmit(formData); // Pass the updated data to the parent
|
onSubmit(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -92,18 +115,20 @@ const FloorModel = ({
|
|||||||
<div className="text-center mb-1">
|
<div className="text-center mb-1">
|
||||||
<h5 className="mb-1">Manage Floors - {project.name}</h5>
|
<h5 className="mb-1">Manage Floors - {project.name}</h5>
|
||||||
</div>
|
</div>
|
||||||
<form className="row g-2" onSubmit={handleSubmit}>
|
<form
|
||||||
|
className="row g-2"
|
||||||
|
onSubmit={handleSubmit(onFormSubmit)}
|
||||||
|
>
|
||||||
<div className="col-12 col-md-12">
|
<div className="col-12 col-md-12">
|
||||||
<label className="form-label" htmlFor="name">
|
<label className="form-label" htmlFor="buildingId">
|
||||||
Select Building
|
Select Building
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="buildingId"
|
id="buildingId"
|
||||||
name="buildingId"
|
|
||||||
className="select2 form-select form-select-sm"
|
className="select2 form-select form-select-sm"
|
||||||
aria-label="Default select example"
|
aria-label="Select Building"
|
||||||
|
{...register("buildingId")}
|
||||||
onChange={handleBuildigChange}
|
onChange={handleBuildigChange}
|
||||||
value={formData.buildingId}
|
|
||||||
>
|
>
|
||||||
<option value="0">Select Building</option>
|
<option value="0">Select Building</option>
|
||||||
{project.buildings.map((building) => (
|
{project.buildings.map((building) => (
|
||||||
@ -112,20 +137,22 @@ const FloorModel = ({
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
{errors.buildingId && (
|
||||||
|
<p className="text-danger">{errors.buildingId.message}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{formData.buildingId != "0" && (
|
{formData.buildingId !== "0" && (
|
||||||
<div className="col-12 col-md-12">
|
<div className="col-12 col-md-12">
|
||||||
<label className="form-label" htmlFor="floorId">
|
<label className="form-label" >
|
||||||
Select Floor
|
Select Floor
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="floorId"
|
id="id"
|
||||||
name="floorId"
|
|
||||||
className="select2 form-select form-select-sm"
|
className="select2 form-select form-select-sm"
|
||||||
aria-label="Default select example"
|
aria-label="Select Floor"
|
||||||
|
{...register("id")}
|
||||||
onChange={handleFloorChange}
|
onChange={handleFloorChange}
|
||||||
value={formData.floorId}
|
|
||||||
>
|
>
|
||||||
<option value="0">Add New Floor</option>
|
<option value="0">Add New Floor</option>
|
||||||
{selectedBuilding.floors.map((floor) => (
|
{selectedBuilding.floors.map((floor) => (
|
||||||
@ -134,30 +161,33 @@ const FloorModel = ({
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
{errors.id && (
|
||||||
|
<p className="text-danger">{errors.id.message}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{formData.buildingId != "0" && (
|
|
||||||
|
{formData.buildingId !== "0" && (
|
||||||
<div className="col-12 col-md-12">
|
<div className="col-12 col-md-12">
|
||||||
{" "}
|
<label className="form-label" htmlFor="floorName">
|
||||||
<label className="form-label" htmlFor="name">
|
{formData.id !== "0" ? "Modify " : "Enter "} Floor Name
|
||||||
{formData.id != "0" ? "Modify " : "Enter "} Floor Name
|
|
||||||
</label>
|
</label>
|
||||||
<div className="input-group">
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="floorName"
|
id="floorName"
|
||||||
name="floorName"
|
|
||||||
className="form-control form-control-sm me-2"
|
className="form-control form-control-sm me-2"
|
||||||
placeholder="Floor Name"
|
placeholder="Floor Name"
|
||||||
onChange={handleChange}
|
{...register("floorName")}
|
||||||
value={formData.floorName}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
{errors.floorName && (
|
||||||
|
<p className="text-danger">{errors.floorName.message}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="col-12 text-center">
|
<div className="col-12 text-center">
|
||||||
<button type="submit" className="btn btn-primary me-3">
|
<button type="submit" className="btn btn-primary me-3">
|
||||||
{formData.id != "0" && formData.id != ""
|
{formData.id !== "0" && formData.id !== ""
|
||||||
? "Edit Floor"
|
? "Edit Floor"
|
||||||
: "Add Floor"}
|
: "Add Floor"}
|
||||||
</button>
|
</button>
|
||||||
69
src/components/Project/Infrastructure/InfraTable.jsx
Normal file
69
src/components/Project/Infrastructure/InfraTable.jsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import Building from "./Building";
|
||||||
|
import Floor from "./Floor";
|
||||||
|
|
||||||
|
const InfraTable = ( {buildings,assign} ) =>
|
||||||
|
{
|
||||||
|
const [projectBuiling,setProjectBuilding] = useState([])
|
||||||
|
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
||||||
|
|
||||||
|
const toggleBuilding = (buildingId) => {
|
||||||
|
setExpandedBuildings((prevExpanded) =>
|
||||||
|
prevExpanded.includes(buildingId)
|
||||||
|
? prevExpanded.filter((id) => id !== buildingId)
|
||||||
|
: [...prevExpanded, buildingId]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const getContent = (building) => {
|
||||||
|
return building.floors.length > 0 ? (
|
||||||
|
building.floors.map((floor) => <Floor forBuilding={building} key={floor.id} floor={floor} workAreas={floor.workAreas} />)
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td colSpan="4">
|
||||||
|
<div className="alert alert-warning text-center mb-0" role="alert">
|
||||||
|
<p>No floors have been added yet. Please add floors to start managing your building.</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-xs btn-primary"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#addFloorModal"
|
||||||
|
onClick={() => openModal('addFloor')}
|
||||||
|
>
|
||||||
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
|
Add Floors
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
useEffect( () =>
|
||||||
|
{
|
||||||
|
setProjectBuilding(buildings)
|
||||||
|
},[buildings])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="col-12 overflow-auto">
|
||||||
|
{projectBuiling && projectBuiling.length > 0 && (
|
||||||
|
<table className="table table-bordered">
|
||||||
|
<tbody>
|
||||||
|
{projectBuiling.map((building) => (
|
||||||
|
<Building
|
||||||
|
key={building.id}
|
||||||
|
building={building}
|
||||||
|
toggleBuilding={toggleBuilding}
|
||||||
|
expandedBuildings={expandedBuildings}
|
||||||
|
getContent={getContent}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default InfraTable
|
||||||
@ -14,9 +14,10 @@ const TaskModel = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
clearTrigger,
|
clearTrigger,
|
||||||
onClearComplete,
|
onClearComplete,
|
||||||
}) => {
|
} ) =>
|
||||||
const [formData, setFormData] = useState(defaultModel);
|
{
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState(defaultModel);
|
||||||
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
||||||
const [selectedFloor, setSelectedFloor] = useState(null);
|
const [selectedFloor, setSelectedFloor] = useState(null);
|
||||||
const [selectedWorkArea, setSelectedWorkArea] = useState(null);
|
const [selectedWorkArea, setSelectedWorkArea] = useState(null);
|
||||||
@ -47,8 +48,8 @@ const TaskModel = ({
|
|||||||
if (clearTrigger) {
|
if (clearTrigger) {
|
||||||
let model = defaultModel;
|
let model = defaultModel;
|
||||||
model.floorId = selectedFloor.id;
|
model.floorId = selectedFloor.id;
|
||||||
setFormData(defaultModel); // Clear form
|
setFormData(defaultModel);
|
||||||
onClearComplete(); // Notify parent that clearing is done
|
onClearComplete();
|
||||||
}
|
}
|
||||||
}, [clearTrigger, onClearComplete]);
|
}, [clearTrigger, onClearComplete]);
|
||||||
|
|
||||||
@ -110,7 +111,8 @@ const TaskModel = ({
|
|||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
onSubmit(formData); // Pass the updated data to the parent
|
// onSubmit( formData ); // Pass the updated data to the parent
|
||||||
|
console.log(formData)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
46
src/components/Project/Infrastructure/WorkArea.jsx
Normal file
46
src/components/Project/Infrastructure/WorkArea.jsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import React from "react";
|
||||||
|
import WorkItem from "./WorkItem";
|
||||||
|
|
||||||
|
const WorkArea = ({ workArea, floor,forBuilding }) => {
|
||||||
|
return (
|
||||||
|
<React.Fragment key={workArea.id}>
|
||||||
|
<tr>
|
||||||
|
<td colSpan="4" className="text-start table-cell">
|
||||||
|
<div className="row ps-2">
|
||||||
|
<div className="col-6">
|
||||||
|
<h6>
|
||||||
|
<span>
|
||||||
|
{floor.floorName} - {workArea.areaName}
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{workArea?.workItems && workArea.workItems.length > 0 ? (
|
||||||
|
<tr className="overflow-auto">
|
||||||
|
<td colSpan={4}>
|
||||||
|
<table className="table mx-1">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Activity</th>
|
||||||
|
<th>Planned</th>
|
||||||
|
<th>Completed</th>
|
||||||
|
<th>Progress</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="table-border-bottom-0">
|
||||||
|
{workArea.workItems.map((workItem) => (
|
||||||
|
<WorkItem key={workItem.workItemId} workItem={workItem} forBuilding={forBuilding} forFloor={floor} forWorkArea={workArea} />
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : null}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default WorkArea;
|
||||||
218
src/components/Project/Infrastructure/WorkAreaModel.jsx
Normal file
218
src/components/Project/Infrastructure/WorkAreaModel.jsx
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { set, useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
// Zod schema for form validation
|
||||||
|
const workAreaSchema = z.object( {
|
||||||
|
id:z.string().nonempty("Floor is required"),
|
||||||
|
|
||||||
|
buildingId: z.string().nonempty("Building is required"),
|
||||||
|
floorId: z.string().nonempty("Floor is required"),
|
||||||
|
areaName: z.string().nonempty( "Work Area Name is required" ).min( 3, "Name must be at least 3 characters long" ),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Default form data
|
||||||
|
const defaultModel = {
|
||||||
|
id: "0",
|
||||||
|
areaName: "",
|
||||||
|
floorId: "0",
|
||||||
|
};
|
||||||
|
|
||||||
|
const WorkAreaModel = ({ project, onSubmit, clearTrigger, onClearComplete }) => {
|
||||||
|
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
||||||
|
const [ selectedFloor, setSelectedFloor ] = useState( null );
|
||||||
|
const [selectdWorkArea,setWorkArea] = useState()
|
||||||
|
|
||||||
|
const { register, handleSubmit, formState: { errors }, setValue, reset, watch } = useForm({
|
||||||
|
resolver: zodResolver(workAreaSchema), // Use Zod resolver for validation
|
||||||
|
defaultValues: defaultModel,
|
||||||
|
});
|
||||||
|
|
||||||
|
const floorId = watch( "floorId" ); // Watch the floorId for conditional rendering
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (clearTrigger) {
|
||||||
|
reset(defaultModel); // Reset form to initial state
|
||||||
|
setSelectedBuilding(null);
|
||||||
|
setSelectedFloor(null);
|
||||||
|
onClearComplete();
|
||||||
|
}
|
||||||
|
}, [clearTrigger, onClearComplete, reset]);
|
||||||
|
|
||||||
|
const handleWorkAreaChange = ( e ) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
const { value } = e.target;
|
||||||
|
|
||||||
|
if (value === "0") {
|
||||||
|
setValue("id", "0"); // Create New Work Area
|
||||||
|
setValue( "areaName", "" );
|
||||||
|
|
||||||
|
setWorkArea(String(0))
|
||||||
|
} else {
|
||||||
|
const workArea = selectedFloor?.workAreas.find((b) => b.id === Number(value));
|
||||||
|
if ( workArea )
|
||||||
|
{
|
||||||
|
setValue("id", String(workArea.id)); // Set id as a string
|
||||||
|
setValue("areaName", workArea.areaName);
|
||||||
|
setWorkArea(String(workArea.id))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFloorChange = (e) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const floor = selectedBuilding?.floors.find((b) => b.id === Number(value));
|
||||||
|
|
||||||
|
if (floor) {
|
||||||
|
setSelectedFloor(floor);
|
||||||
|
setValue("floorId", floor.id); // Update floorId
|
||||||
|
setValue("id", "0"); // Reset Work Area ID for new area creation
|
||||||
|
setValue("areaName", ""); // Reset Work Area Name when changing floor
|
||||||
|
} else {
|
||||||
|
setSelectedFloor(null);
|
||||||
|
setValue("floorId", "0");
|
||||||
|
setValue("id", "0"); // Reset Work Area ID
|
||||||
|
setValue("areaName", ""); // Reset Work Area Name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBuildingChange = (e) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const building = project.buildings.find((b) => b.id === Number(value));
|
||||||
|
setSelectedBuilding(building);
|
||||||
|
setSelectedFloor(null); // Reset selected floor on building change
|
||||||
|
reset(defaultModel); // Reset the form when a new building is selected
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmitForm = ( data ) =>
|
||||||
|
{
|
||||||
|
console.log(data)
|
||||||
|
let WorkArea = {
|
||||||
|
id: data.id,
|
||||||
|
areaName: data.areaName,
|
||||||
|
floorId: data.floorId,
|
||||||
|
buildingId:data.buildingId
|
||||||
|
}
|
||||||
|
onSubmit(WorkArea); // Send the final data to the parent
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
reset(defaultModel); // Reset the form to initial state
|
||||||
|
setSelectedFloor(null);
|
||||||
|
setSelectedBuilding(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="row">
|
||||||
|
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
<div className="text-center mb-1">
|
||||||
|
<h5 className="mb-1">Manage Work Area</h5>
|
||||||
|
</div>
|
||||||
|
<form className="row g-2" onSubmit={handleSubmit(onSubmitForm)}>
|
||||||
|
{/* Building Selection */}
|
||||||
|
<div className="col-6 col-md-6">
|
||||||
|
<label className="form-label" htmlFor="buildingId">Select Building</label>
|
||||||
|
<select
|
||||||
|
id="buildingId"
|
||||||
|
name="buildingId"
|
||||||
|
className="select2 form-select form-select-sm"
|
||||||
|
{...register("buildingId")}
|
||||||
|
onChange={handleBuildingChange}
|
||||||
|
>
|
||||||
|
<option value="0">Select Building</option>
|
||||||
|
{project.buildings.map((building) => (
|
||||||
|
<option key={building.id} value={building.id}>
|
||||||
|
{building.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{errors.buildingId && <span>{errors.buildingId.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Floor Selection */}
|
||||||
|
{selectedBuilding && selectedBuilding.buildingId !== "0" && (
|
||||||
|
<div className="col-6 col-md-6">
|
||||||
|
<label className="form-label" htmlFor="floorId">Select Floor</label>
|
||||||
|
<select
|
||||||
|
id="floorId"
|
||||||
|
name="floorId"
|
||||||
|
className="select2 form-select form-select-sm"
|
||||||
|
{...register("floorId")}
|
||||||
|
onChange={handleFloorChange}
|
||||||
|
>
|
||||||
|
<option value="0">Select Floor</option>
|
||||||
|
{selectedBuilding.floors.map((floor) => (
|
||||||
|
<option key={floor.id} value={floor.id}>
|
||||||
|
{floor.floorName}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{errors.floorId && <span>{errors.floorId.message}</span>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Work Area Selection or Creation */}
|
||||||
|
{floorId !== "0" && (
|
||||||
|
<>
|
||||||
|
<div className="col-12 col-md-12">
|
||||||
|
<label className="form-label" >Select Work Area</label>
|
||||||
|
<select
|
||||||
|
id="workAreaId"
|
||||||
|
name="workAreaId"
|
||||||
|
className="select2 form-select form-select-sm"
|
||||||
|
{...register("id")}
|
||||||
|
onChange={handleWorkAreaChange}
|
||||||
|
>
|
||||||
|
<option value="0">Create New Work Area</option>
|
||||||
|
{selectedFloor?.workAreas.map((workArea) => (
|
||||||
|
<option key={workArea.id} value={workArea.id}>
|
||||||
|
{workArea.areaName}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{errors.id && <span>{errors.id.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Work Area Name Input */}
|
||||||
|
<div className="col-12 col-md-12">
|
||||||
|
<label className="form-label" htmlFor="areaName">
|
||||||
|
{watch("id") === "0" ? "Enter Work Area Name" : "Modify Work Area Name"}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="areaName"
|
||||||
|
name="areaName"
|
||||||
|
className="form-control form-control-sm"
|
||||||
|
placeholder="Work Area"
|
||||||
|
{...register("areaName")}
|
||||||
|
/>
|
||||||
|
{errors.areaName && <span className="danger-text">{errors.areaName.message}</span>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Submit and Cancel Buttons */}
|
||||||
|
<div className="col-12 text-center">
|
||||||
|
<button type="submit" className="btn btn-primary me-3">
|
||||||
|
{watch("id") === "0" ? "Add Work Area" : "Edit Work Area"}
|
||||||
|
</button>
|
||||||
|
<button type="button" className="btn btn-label-secondary" onClick={handleCancel} data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkAreaModel;
|
||||||
98
src/components/Project/Infrastructure/WorkItem.jsx
Normal file
98
src/components/Project/Infrastructure/WorkItem.jsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useModal } from "../../../ModalContext";
|
||||||
|
import AssignRoleModel from "../AssignRole";
|
||||||
|
import {useParams} from "react-router-dom";
|
||||||
|
|
||||||
|
const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||||
|
const {projectId} = useParams()
|
||||||
|
const { openModal ,closedModal} = useModal();
|
||||||
|
const [itemName, setItemName] = useState('');
|
||||||
|
const getProgress = (planned, completed) => {
|
||||||
|
return (completed * 100) / planned + "%";
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAssignTask = () => {
|
||||||
|
console.log("Item Created:", itemName);
|
||||||
|
setItemName('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCreateItemModal = (modalData) => {
|
||||||
|
openModal(
|
||||||
|
<AssignRoleModel assignData={modalData} onClose={closedModal} />,
|
||||||
|
handleAssignTask ,"lg"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let assigndata = {
|
||||||
|
building: forBuilding,
|
||||||
|
floor: forFloor,
|
||||||
|
workArea: forWorkArea,
|
||||||
|
workItem
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td className="text-start table-cell-small">
|
||||||
|
<i className="bx bx-right-arrow-alt"></i>
|
||||||
|
<span className="fw-medium">
|
||||||
|
{workItem.workItem.activityMaster
|
||||||
|
? workItem.workItem.activityMaster.activityName
|
||||||
|
: "NA"}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="text-center">
|
||||||
|
{workItem.workItem ? workItem.workItem.plannedWork : "NA"}
|
||||||
|
</td>
|
||||||
|
<td className="text-center">
|
||||||
|
{workItem.workItem ? workItem.workItem.completedWork : "NA"}
|
||||||
|
</td>
|
||||||
|
<td className="text-center" style={{ width: "15%" }}>
|
||||||
|
<div className="progress p-0">
|
||||||
|
<div
|
||||||
|
className="progress-bar"
|
||||||
|
role="progressbar"
|
||||||
|
style={{
|
||||||
|
width: getProgress(workItem.workItem.plannedWork, workItem.workItem.completedWork),
|
||||||
|
height: "10px",
|
||||||
|
}}
|
||||||
|
aria-valuenow={workItem.workItem ? workItem.workItem.completedWork : 0}
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax={workItem.workItem ? workItem.workItem.plannedWork : 0}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div className="dropdown">
|
||||||
|
{!projectId && ( <button
|
||||||
|
aria-label="Modify"
|
||||||
|
type="button"
|
||||||
|
className="btn p-0"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#project-modal"
|
||||||
|
onClick={() =>
|
||||||
|
{
|
||||||
|
showCreateItemModal(assigndata)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="badge bg-label-primary me-1">Assign</span>
|
||||||
|
</button>)}
|
||||||
|
<button
|
||||||
|
aria-label="Modify"
|
||||||
|
type="button"
|
||||||
|
className="btn p-0 dropdown-toggle hide-arrow"
|
||||||
|
>
|
||||||
|
<i className="bx bxs-edit me-2 text-primary"></i>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="Delete"
|
||||||
|
type="button"
|
||||||
|
className="btn p-0 dropdown-toggle hide-arrow"
|
||||||
|
>
|
||||||
|
<i className="bx bx-trash me-1 text-danger"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkItem;
|
||||||
@ -1,18 +1,20 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "./ProjectInfra.css";
|
import "./ProjectInfra.css";
|
||||||
import BuildingModel from "./BuildingModel";
|
import BuildingModel from "./Infrastructure/BuildingModel";
|
||||||
import FloorModel from "./FloorModel";
|
import FloorModel from "./Infrastructure/FloorModel";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import WorkAreaModel from "./WorkAreaModel";
|
import WorkAreaModel from "./Infrastructure/WorkAreaModel";
|
||||||
import TaskModel from "./TaskModel";
|
import TaskModel from "./Infrastructure/TaskModel";
|
||||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
import ProjectRepository, {TasksRepository} from "../../repositories/ProjectRepository";
|
||||||
import ProjectModal from "./ProjectModal";
|
import ProjectModal from "./ProjectModal";
|
||||||
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
||||||
import {MANAGE_PROJECT_INFRA} from "../../utils/constants";
|
import {MANAGE_PROJECT_INFRA} from "../../utils/constants";
|
||||||
// import AssignRoleModel from "./AssignRoleModel";
|
import InfraTable from "./Infrastructure/InfraTable";
|
||||||
|
import {cacheData} from "../../slices/apiDataManager";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) => {
|
const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) => {
|
||||||
|
|
||||||
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
||||||
const [project, setProject] = useState(data);
|
const [project, setProject] = useState(data);
|
||||||
const[modalConfig,setModalConfig] = useState({type:null,data:null});
|
const[modalConfig,setModalConfig] = useState({type:null,data:null});
|
||||||
@ -28,6 +30,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||||
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
||||||
const [ CurrentBuilding, setCurrentBuilding ] = useState( "" )
|
const [ CurrentBuilding, setCurrentBuilding ] = useState( "" )
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProject(data);
|
setProject(data);
|
||||||
@ -50,6 +53,188 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
setIsAssingRoleModal(true)
|
setIsAssingRoleModal(true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const openBuildingModel = (projectData) => {
|
||||||
|
setIsBuildingModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const submitData = async (infraObject) => {
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
console.log(infraObject)
|
||||||
|
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,
|
||||||
|
floor: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedProject.buildings = updatedBuildings;
|
||||||
|
|
||||||
|
// Update the cache for buildings
|
||||||
|
cacheData( "projectInfo", {projectId: updatedProject.id, data: updatedProject} );
|
||||||
|
setProject(updatedProject)
|
||||||
|
}
|
||||||
|
// 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, workArea: null }] // 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)
|
||||||
|
}
|
||||||
|
// Handle the work area data
|
||||||
|
else if ( entity.workArea )
|
||||||
|
{
|
||||||
|
debugger
|
||||||
|
|
||||||
|
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: null },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
: floor
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: building
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedProject.buildings = updatedBuildings;
|
||||||
|
|
||||||
|
// Update the cache for work areas
|
||||||
|
cacheData( "projectInfo", {projectId: updatedProject.id, data: updatedProject} );
|
||||||
|
setProject(updatedProject)
|
||||||
|
}
|
||||||
|
// Handle the task (workItem) data
|
||||||
|
else if (entity.workItem) {
|
||||||
|
const { buildingId, floorId, workAreaId, name, description } = entity.workItem;
|
||||||
|
const updatedBuildings = updatedProject.buildings.map((building) =>
|
||||||
|
building.id === buildingId
|
||||||
|
? {
|
||||||
|
...building,
|
||||||
|
floors: building.floors.map((floor) =>
|
||||||
|
floor.id === floorId
|
||||||
|
? {
|
||||||
|
...floor,
|
||||||
|
workAreas: floor.workAreas.map((workArea) =>
|
||||||
|
workArea.id === workAreaId
|
||||||
|
? {
|
||||||
|
...workArea,
|
||||||
|
tasks: workArea.tasks.map((task) =>
|
||||||
|
task.id === entity.workItem.id ? { ...task, name, description } : task
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: workArea
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: floor
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: building
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedProject.buildings = updatedBuildings;
|
||||||
|
|
||||||
|
|
||||||
|
cacheData("projectInfo", { projectId: updatedProject.id, data: updatedProject });
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
console.error("Unsupported data type for submitData", entity);
|
||||||
|
}
|
||||||
|
} catch ( Err )
|
||||||
|
{
|
||||||
|
showToast("Somthing wrong","error")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
handleClose()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) => {
|
const handleFloorModelFormSubmit = (updatedFloor) => {
|
||||||
if (updatedFloor.id == "") delete updatedFloor.id;
|
if (updatedFloor.id == "") delete updatedFloor.id;
|
||||||
|
|
||||||
@ -62,49 +247,13 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitData = (infraObject) => {
|
|
||||||
ProjectRepository.manageProjectInfra(infraObject)
|
|
||||||
.then((response) => {
|
|
||||||
fetchData();
|
|
||||||
onDataChange("building-change");
|
|
||||||
showToast("Details updated successfully.", "success");
|
|
||||||
setClearFormTrigger(true); // Set trigger to true
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
showToast(error.message, "error");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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 openWorkAreaModel = (projectData) => {
|
const openWorkAreaModel = (projectData) => {
|
||||||
setIsWorkAreaModalOpen(true);
|
setIsWorkAreaModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeWorkAreaModel = () => {
|
const closeWorkAreaModel = () => {
|
||||||
setIsWorkAreaModalOpen(false);
|
setIsWorkAreaModalOpen(false);
|
||||||
// const modalBackdrop = document.querySelector(".modal-backdrop");
|
|
||||||
// if (modalBackdrop) modalBackdrop.remove();
|
|
||||||
};
|
};
|
||||||
const handleWorkAreaModelFormSubmit = (updatedModel) => {
|
const handleWorkAreaModelFormSubmit = (updatedModel) => {
|
||||||
if (updatedModel.id == "") delete updatedModel.id;
|
if (updatedModel.id == "") delete updatedModel.id;
|
||||||
@ -124,19 +273,18 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
|
|
||||||
const closeTaskModel = () => {
|
const closeTaskModel = () => {
|
||||||
setIsTaskModalOpen(false);
|
setIsTaskModalOpen(false);
|
||||||
// const modalBackdrop = document.querySelector(".modal-backdrop");
|
|
||||||
// if (modalBackdrop) modalBackdrop.remove();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTaskModelFormSubmit = (updatedModel) => {
|
const handleTaskModelFormSubmit = (updatedModel) => {
|
||||||
if (updatedModel.id == "") updatedModel.id = 0;
|
if (updatedModel.id == "") updatedModel.id = 0;
|
||||||
|
|
||||||
//console.log("Form submitted:", updatedModel); // Replace this with an API call or state update
|
|
||||||
ProjectRepository.manageProjectTasks([updatedModel])
|
ProjectRepository.manageProjectTasks([updatedModel])
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
onDataChange("task-change");
|
onDataChange("task-change");
|
||||||
showToast("Details updated successfully.", "success");
|
showToast("Details updated successfully.", "success");
|
||||||
setClearFormTrigger(true); // Set trigger to true
|
setClearFormTrigger(true);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
showToast(error.message, "error");
|
showToast(error.message, "error");
|
||||||
@ -149,296 +297,53 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getContent = (building) => {
|
|
||||||
let hasFloors =
|
|
||||||
building.floors && building.floors.length > 0 ? true : false;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{(() => {
|
|
||||||
if (hasFloors) {
|
|
||||||
return building.floors.map((floor) => (
|
|
||||||
<React.Fragment key={floor.id}>
|
|
||||||
|
|
||||||
{floor.workAreas.length > 0 ? (
|
|
||||||
floor.workAreas.map((workArea) => (
|
|
||||||
<React.Fragment key={workArea.id}>
|
|
||||||
<tr>
|
|
||||||
<td colSpan="4" className="text-start table-cell">
|
|
||||||
<div className="row ps-2">
|
|
||||||
<div className="col-6">
|
|
||||||
{" "}
|
|
||||||
<h6>
|
|
||||||
<span>
|
|
||||||
{" "}
|
|
||||||
{floor.floorName} - {workArea.areaName} {" "}
|
|
||||||
</span>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
<div className="col-6 text-end">
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end me-2"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#floor-model"
|
|
||||||
onClick={() => openFloorModel()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-edit-alt me-2"></i>
|
|
||||||
Edit Floor
|
|
||||||
</a> */}
|
|
||||||
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Activities
|
|
||||||
</a> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{workArea.workItems.length > 0 ? (
|
|
||||||
<tr className="overflow-auto" >
|
|
||||||
{" "}
|
|
||||||
<td colSpan={4} >
|
|
||||||
<table
|
|
||||||
className="table mx-1"
|
|
||||||
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Activity</th>
|
|
||||||
<th>Planned</th>
|
|
||||||
<th>Complated</th>
|
|
||||||
<th>Progress</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="table-border-bottom-0">
|
|
||||||
{workArea.workItems.map((workItem) => (
|
|
||||||
<React.Fragment key={workItem.workItemId}>
|
|
||||||
<tr>
|
|
||||||
<td className="text-start table-cell-small">
|
|
||||||
<i className="bx bx-right-arrow-alt"></i>
|
|
||||||
<span className="fw-medium">
|
|
||||||
{workItem.workItem.activityMaster
|
|
||||||
? workItem.workItem.activityMaster
|
|
||||||
.activityName
|
|
||||||
: "NA"}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="text-center">
|
|
||||||
{workItem.workItem
|
|
||||||
? workItem.workItem.plannedWork
|
|
||||||
: "NA"}
|
|
||||||
</td>
|
|
||||||
<td className="text-center">
|
|
||||||
{workItem.workItem
|
|
||||||
? workItem.workItem.completedWork
|
|
||||||
: "NA"}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td
|
|
||||||
className="text-center"
|
|
||||||
style={{ width: "15%" }}
|
|
||||||
>
|
|
||||||
<div className="progress p-0">
|
|
||||||
<div
|
|
||||||
className="progress-bar"
|
|
||||||
role="progressbar"
|
|
||||||
style={{
|
|
||||||
width: getProgress(
|
|
||||||
workItem.workItem.plannedWork,
|
|
||||||
workItem.workItem.completedWork
|
|
||||||
),
|
|
||||||
height: "10px",
|
|
||||||
}}
|
|
||||||
aria-valuenow={
|
|
||||||
workItem.workItem
|
|
||||||
? workItem.workItem
|
|
||||||
.completedWork
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
aria-valuemin="0"
|
|
||||||
aria-valuemax={
|
|
||||||
workItem.workItem
|
|
||||||
? workItem.workItem.plannedWork
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div className="dropdown">
|
|
||||||
<button
|
|
||||||
aria-label="Modify"
|
|
||||||
type="button"
|
|
||||||
className="btn p-0 "
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#project-modal"
|
|
||||||
onClick={()=>{
|
|
||||||
// setModalConfig({type:"assignRole",data:{building,floor,workArea,workItem}})
|
|
||||||
handleModalData("assignRole",{building,floor,workArea,workItem})
|
|
||||||
// openAssignModel({building,floor,workArea,workItem})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="badge bg-label-primary me-1">Assign</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Modify"
|
|
||||||
type="button"
|
|
||||||
className="btn p-0 dropdown-toggle hide-arrow"
|
|
||||||
>
|
|
||||||
<i class="bx bxs-edit me-2 text-primary"></i>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Delete"
|
|
||||||
type="button"
|
|
||||||
className="btn p-0 dropdown-toggle hide-arrow"
|
|
||||||
>
|
|
||||||
<i className="bx bx-trash me-1 text-danger"></i>{" "}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>{" "}
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>{" "}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
) : (
|
|
||||||
<span></span>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<React.Fragment key={building.id + floor.id}>
|
|
||||||
<tr>
|
|
||||||
<td colSpan="4" className="text-start table-cell">
|
|
||||||
<div className="row ps-2">
|
|
||||||
<div className="col-6">
|
|
||||||
{" "}
|
|
||||||
<h6>
|
|
||||||
<span> {floor.floorName} </span>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
<div className="col-6 text-end">
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end me-2"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#floor-model"
|
|
||||||
onClick={() => openFloorModel()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-edit-alt me-2"></i>
|
|
||||||
Edit Floor
|
|
||||||
</a> */}
|
|
||||||
|
|
||||||
{/* <a
|
|
||||||
type="button"
|
|
||||||
className="text-end"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Work Area
|
|
||||||
</a> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>No Floors Added, Please add them</p>
|
|
||||||
{/* <p>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
className="btn btn-sm btn-danger m-1"
|
|
||||||
data-bs-target="#editproject"
|
|
||||||
onClick={() => openModal()}
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Add Floors
|
|
||||||
</button>
|
|
||||||
</p> */}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProgress = (planned, completed) => {
|
|
||||||
return (completed * 100) / planned + "%";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// common modal
|
|
||||||
|
|
||||||
const handleModalData = (type,modaldata)=>{
|
const handleModalData = (type,modaldata)=>{
|
||||||
setModalConfig({type:type,data:modaldata})
|
setModalConfig({type:type,data:modaldata})
|
||||||
}
|
}
|
||||||
const openModal = () => {
|
const openModal = () => {
|
||||||
setIsModalOpen(true);
|
const modalElement = document.getElementById('building-model');
|
||||||
|
const modal = new Modal(modalElement, {
|
||||||
|
backdrop: false,
|
||||||
|
keyboard: true,
|
||||||
|
focus: true
|
||||||
|
});
|
||||||
|
modal.show()
|
||||||
};
|
};
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
setModalConfig(null)
|
setModalConfig(null)
|
||||||
|
|
||||||
|
|
||||||
const modalElement = document.getElementById('project-modal');
|
const modalElement = document.getElementById('building-model');
|
||||||
if (modalElement) {
|
if (modalElement) {
|
||||||
modalElement.classList.remove('show');
|
modalElement.classList.remove('show'); // Remove modal visibility class
|
||||||
modalElement.style.display = 'none'; // Hide modal visually
|
modalElement.style.display = 'none'; // Hide the modal element
|
||||||
document.body.classList.remove('modal-open'); // Unlock body scroll
|
}
|
||||||
|
|
||||||
|
document.body.classList.remove('modal-open'); // Remove modal-open class from body
|
||||||
|
|
||||||
|
// Remove the modal backdrop
|
||||||
const backdropElement = document.querySelector('.modal-backdrop');
|
const backdropElement = document.querySelector('.modal-backdrop');
|
||||||
if (backdropElement) {
|
if (backdropElement) {
|
||||||
backdropElement.classList.remove('modal-backdrop'); // Remove backdrop class
|
backdropElement.classList.remove('modal-backdrop'); // Remove backdrop class
|
||||||
backdropElement.style.display = 'none'; // Hide the backdrop element
|
backdropElement.style.display = 'none'; // Hide the backdrop element
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const modalBackdropElement = document.querySelector('.modal-backdrop');
|
|
||||||
if (modalBackdropElement) {
|
|
||||||
modalBackdropElement.remove();
|
|
||||||
}
|
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.overflow = 'auto';
|
||||||
|
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
|
||||||
if (modalConfig !== null) {
|
|
||||||
openModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [modalConfig,isModalOpen]);
|
|
||||||
|
|
||||||
|
const handleShow = () => setShowModal(true);
|
||||||
|
const handleClose = () => setShowModal( false );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isBuildingModalOpen && (
|
|
||||||
<div
|
<div
|
||||||
className={`modal fade `}
|
className={`modal fade ${showModal ? 'show' : ''}`}
|
||||||
id="building-model"
|
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
aria-hidden="true"
|
role="dialog"
|
||||||
|
style={{ display: showModal ? 'block' : 'none' }}
|
||||||
|
aria-hidden={!showModal}
|
||||||
>
|
>
|
||||||
<BuildingModel
|
<BuildingModel
|
||||||
project={data}
|
project={data}
|
||||||
@ -448,7 +353,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
onClearComplete={() => setClearFormTrigger(false)}
|
onClearComplete={() => setClearFormTrigger(false)}
|
||||||
></BuildingModel>
|
></BuildingModel>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{isFloorModalOpen && (
|
{isFloorModalOpen && (
|
||||||
<div
|
<div
|
||||||
@ -459,7 +364,6 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
>
|
>
|
||||||
<FloorModel
|
<FloorModel
|
||||||
project={data}
|
project={data}
|
||||||
// building={null}
|
|
||||||
onClose={closeFloorModel}
|
onClose={closeFloorModel}
|
||||||
onSubmit={handleFloorModelFormSubmit}
|
onSubmit={handleFloorModelFormSubmit}
|
||||||
clearTrigger={clearFormTrigger}
|
clearTrigger={clearFormTrigger}
|
||||||
@ -505,15 +409,12 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* common Modal */}
|
|
||||||
{isModalOpen && (
|
{isModalOpen && (
|
||||||
<ProjectModal modalConfig={modalConfig} closeModal={closeModal} />
|
<ProjectModal modalConfig={modalConfig} closeModal={closeModal} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
{/* <div className="card-header pb-4"></div> */}
|
|
||||||
|
|
||||||
<div className="card-body" style={{ padding: "0.5rem" }}>
|
<div className="card-body" style={{ padding: "0.5rem" }}>
|
||||||
<div className="align-items-center">
|
<div className="align-items-center">
|
||||||
@ -522,14 +423,12 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="link-button link-button-sm m-1 "
|
className="link-button link-button-sm m-1 "
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#building-model"
|
onClick={handleShow}
|
||||||
onClick={() => openBuildingModel()}
|
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Manage Building
|
Manage Building
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
@ -564,48 +463,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
<div className="col-12 overflow-auto">
|
<InfraTable buildings={project.buildings}/>
|
||||||
{buildings && buildings.length > 0 && (
|
|
||||||
<table className="table table-bordered ">
|
|
||||||
<tbody>
|
|
||||||
{buildings.map((building) => (
|
|
||||||
|
|
||||||
building.floors && building.floors.length > 0 && (
|
|
||||||
<React.Fragment key={building.id}>
|
|
||||||
<tr className="overflow-auto">
|
|
||||||
<td
|
|
||||||
colSpan="4"
|
|
||||||
className="text-start "
|
|
||||||
style={{
|
|
||||||
background: "#f0f0f0",
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
|
||||||
onClick={() => toggleBuilding(building.id)}
|
|
||||||
>
|
|
||||||
<div className="row table-responsive">
|
|
||||||
<h5 style={{ marginBottom: "0px" }}>
|
|
||||||
|
|
||||||
{ building.name}
|
|
||||||
{expandedBuildings.includes(building.id) ? (
|
|
||||||
<i className="bx bx-chevron-down"></i>
|
|
||||||
) : (
|
|
||||||
<i className="bx bx-chevron-right"></i>
|
|
||||||
)}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{expandedBuildings.includes(building.id) && getContent(building)}
|
|
||||||
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const ProjectModal = ({modalConfig,closeModal}) => {
|
|||||||
{/* Modal Component */}
|
{/* Modal Component */}
|
||||||
|
|
||||||
{modalConfig?.type === "assignRole" && <AssignRole assignData={modalConfig?.data} onClose={closeModal} />}
|
{modalConfig?.type === "assignRole" && <AssignRole assignData={modalConfig?.data} onClose={closeModal} />}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import {useEmployeesByProjectAllocated} from "../../hooks/useProjects";
|
|||||||
|
|
||||||
const ProjectOverview = ({project}) =>
|
const ProjectOverview = ({project}) =>
|
||||||
{
|
{
|
||||||
const {projectEmployees} = useEmployeesByProjectAllocated( project.id );
|
const {projectEmployees} = useEmployeesByProjectAllocated( project?.id );
|
||||||
let teamSize = projectEmployees.filter( ( emp ) => emp.isActive )
|
let teamSize = projectEmployees.filter( ( emp ) => emp.isActive )
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,230 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
const defaultModel = {
|
|
||||||
id: "0",
|
|
||||||
areaName: "",
|
|
||||||
floorId: "0",
|
|
||||||
};
|
|
||||||
|
|
||||||
const WorkAreaModel = ({
|
|
||||||
project,
|
|
||||||
onSubmit,
|
|
||||||
clearTrigger,
|
|
||||||
onClearComplete,
|
|
||||||
}) => {
|
|
||||||
const [formData, setFormData] = useState(defaultModel);
|
|
||||||
|
|
||||||
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
|
||||||
const [selectedFloor, setSelectedFloor] = useState(null);
|
|
||||||
|
|
||||||
//if (floor && floor.id) setFormData(floor);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selectedBuilding) {
|
|
||||||
let building = project.buildings.find(
|
|
||||||
(b) => b.id === selectedBuilding.id
|
|
||||||
);
|
|
||||||
setSelectedBuilding(building);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedFloor) {
|
|
||||||
let floor = selectedBuilding.floors.find(
|
|
||||||
(b) => b.id === Number(selectedFloor.id)
|
|
||||||
);
|
|
||||||
setSelectedFloor(floor);
|
|
||||||
}
|
|
||||||
}, [project]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (clearTrigger) {
|
|
||||||
let model = defaultModel;
|
|
||||||
model.floorId = selectedFloor.id;
|
|
||||||
setFormData(defaultModel); // Clear form
|
|
||||||
onClearComplete(); // Notify parent that clearing is done
|
|
||||||
}
|
|
||||||
}, [clearTrigger, onClearComplete]);
|
|
||||||
|
|
||||||
// Handle input change
|
|
||||||
const handleChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData({ ...formData, [name]: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleWorkAreaChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
const workArea = selectedFloor.workAreas.find(
|
|
||||||
(b) => b.id === Number(value)
|
|
||||||
);
|
|
||||||
if (workArea) {
|
|
||||||
setFormData({
|
|
||||||
id: workArea.id,
|
|
||||||
floorId: workArea.floorId,
|
|
||||||
areaName: workArea.areaName,
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
setFormData({
|
|
||||||
id: "0",
|
|
||||||
floorId: selectedFloor.id,
|
|
||||||
areaName: "",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFloorChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
const floor = selectedBuilding.floors.find((b) => b.id === Number(value));
|
|
||||||
setSelectedFloor(floor);
|
|
||||||
if (floor) {
|
|
||||||
setFormData({
|
|
||||||
id: "0",
|
|
||||||
floorId: floor.id,
|
|
||||||
areaName: "",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setSelectedFloor(null);
|
|
||||||
setFormData({
|
|
||||||
id: "0",
|
|
||||||
floorId: "0",
|
|
||||||
areaName: "",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleBuildigChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
const building = project.buildings.find((b) => b.id === Number(value));
|
|
||||||
setSelectedBuilding(building);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle form submission
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
formData.projectId = project.id;
|
|
||||||
|
|
||||||
onSubmit(formData); // Pass the updated data to the parent
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-body">
|
|
||||||
<div className="row">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-close"
|
|
||||||
data-bs-dismiss="modal"
|
|
||||||
aria-label="Close"
|
|
||||||
></button>
|
|
||||||
<div className="text-center mb-1">
|
|
||||||
<h5 className="mb-1">Manage Work Area</h5>
|
|
||||||
</div>
|
|
||||||
<form className="row g-2" onSubmit={handleSubmit}>
|
|
||||||
<div className="col-6 col-md-6">
|
|
||||||
<label className="form-label" htmlFor="name">
|
|
||||||
Select Building
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="buildingId"
|
|
||||||
name="buildingId"
|
|
||||||
className="select2 form-select form-select-sm"
|
|
||||||
aria-label="Default select example"
|
|
||||||
onChange={handleBuildigChange}
|
|
||||||
value={formData.buildingId}
|
|
||||||
>
|
|
||||||
<option value="0">Select Building</option>
|
|
||||||
{project.buildings.map((building) => (
|
|
||||||
<option key={building.id} value={building.id}>
|
|
||||||
{building.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{selectedBuilding && selectedBuilding.buildingId != "0" && (
|
|
||||||
<div className="col-6 col-md-6">
|
|
||||||
<label className="form-label" htmlFor="floorId">
|
|
||||||
Select Floor
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="floorId"
|
|
||||||
name="floorId"
|
|
||||||
className="select2 form-select form-select-sm"
|
|
||||||
aria-label="Default select example"
|
|
||||||
onChange={handleFloorChange}
|
|
||||||
value={formData.floorId}
|
|
||||||
>
|
|
||||||
<option value="0">Select Floor</option>
|
|
||||||
{selectedBuilding.floors.map((floor) => (
|
|
||||||
<option key={floor.id} value={floor.id}>
|
|
||||||
{floor.floorName}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{formData.floorId != "0" && (
|
|
||||||
<div className="col-12 col-md-12">
|
|
||||||
<label className="form-label" htmlFor="floorId">
|
|
||||||
Select Work Area
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="floorId"
|
|
||||||
name="floorId"
|
|
||||||
className="select2 form-select form-select-sm"
|
|
||||||
aria-label="Default select example"
|
|
||||||
onChange={handleWorkAreaChange}
|
|
||||||
value={formData.floorId}
|
|
||||||
>
|
|
||||||
<option value="0">Create New Work Area</option>
|
|
||||||
{selectedFloor.workAreas.map((workArea) => (
|
|
||||||
<option key={workArea.id} value={workArea.id}>
|
|
||||||
{workArea.areaName}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{formData.floorId != "0" && (
|
|
||||||
<div className="col-12 col-md-12">
|
|
||||||
{" "}
|
|
||||||
<label className="form-label" htmlFor="areaName">
|
|
||||||
{formData.id != "0" ? "Modify " : "Enter "} Work Area Name
|
|
||||||
</label>
|
|
||||||
<div className="input-group">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="areaName"
|
|
||||||
name="areaName"
|
|
||||||
className="form-control form-control-sm me-2"
|
|
||||||
placeholder="Work Area"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={formData.areaName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="col-12 text-center">
|
|
||||||
{formData.floorId != "0" && (
|
|
||||||
<button type="submit" className="btn btn-primary me-3">
|
|
||||||
{formData.id != "0" && formData.id != ""
|
|
||||||
? "Edit Work Area"
|
|
||||||
: "Add Work Area"}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
type="reset"
|
|
||||||
className="btn btn-label-secondary"
|
|
||||||
data-bs-dismiss="modal"
|
|
||||||
aria-label="Close"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WorkAreaModel;
|
|
||||||
@ -6,6 +6,7 @@ import {
|
|||||||
import ProjectRepository from "../repositories/ProjectRepository";
|
import ProjectRepository from "../repositories/ProjectRepository";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const useProjects =()=>{
|
export const useProjects =()=>{
|
||||||
|
|
||||||
const [projects, setProjects] = useState([]);
|
const [projects, setProjects] = useState([]);
|
||||||
@ -37,6 +38,7 @@ export const useProjects =()=>{
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
fetchData()
|
fetchData()
|
||||||
|
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
return { projects,loading,error,refetch:fetchData}
|
return { projects,loading,error,refetch:fetchData}
|
||||||
@ -84,18 +86,18 @@ export const useEmployeesByProjectAllocated = ( selectedProject ) =>
|
|||||||
export const useProjectDetails =(projectId)=>{
|
export const useProjectDetails =(projectId)=>{
|
||||||
|
|
||||||
const [projects_Details, setProject_Details] = useState(null);
|
const [projects_Details, setProject_Details] = useState(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const project_cache = getCachedData(`projectinfo-${projectId}`);
|
const project_cache = getCachedData("projectInfo");
|
||||||
if (!project_cache) {
|
if (!project_cache || project_cache?.projectId !== projectId) {
|
||||||
ProjectRepository.getProjectByprojectId(projectId)
|
ProjectRepository.getProjectByprojectId(projectId)
|
||||||
.then( ( response ) =>
|
.then( ( response ) =>
|
||||||
{
|
{
|
||||||
setProject_Details( response.data );
|
setProject_Details( response.data );
|
||||||
cacheData( `projectinfo-${ projectId }`, response.data );
|
cacheData("projectInfo", {projectId,data: response.data} );
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -104,15 +106,17 @@ export const useProjectDetails =(projectId)=>{
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setProject_Details( project_cache );
|
setProject_Details( project_cache.data );
|
||||||
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
};;
|
};
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
if ( projectId )
|
||||||
|
{
|
||||||
fetchData()
|
fetchData()
|
||||||
|
}
|
||||||
},[projectId])
|
},[projectId])
|
||||||
|
|
||||||
return { projects_Details,loading,error,refetch:fetchData}
|
return { projects_Details,loading,error,refetch:fetchData}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import App from './App.tsx'
|
|||||||
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { store } from './store/store';
|
import { store } from './store/store';
|
||||||
|
import { ModalProvider } from './ModalContext.jsx';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +14,9 @@ createRoot(document.getElementById('root')!).render(
|
|||||||
// <StrictMode>
|
// <StrictMode>
|
||||||
// <MasterDataProvider>
|
// <MasterDataProvider>
|
||||||
<Provider store={ store }>
|
<Provider store={ store }>
|
||||||
|
<ModalProvider>
|
||||||
<App />
|
<App />
|
||||||
|
</ModalProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
// </MasterDataProvider>
|
// </MasterDataProvider>
|
||||||
|
|
||||||
|
|||||||
@ -91,7 +91,10 @@ const AttendancePage = () =>
|
|||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
setAttendances(attendance)
|
setAttendances(attendance)
|
||||||
},[attendance])
|
},[attendance])
|
||||||
|
useEffect( () =>
|
||||||
|
{
|
||||||
|
dispatch(setProjectId(projects[0]?.id))
|
||||||
|
},[projects])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -14,18 +14,6 @@ const DailyTask =()=>{
|
|||||||
<div className="card card-action mb-6">
|
<div className="card card-action mb-6">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{/* <div className="col-12 text-end mb-1">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="link-button link-button-sm m-1"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#user-model"
|
|
||||||
|
|
||||||
>
|
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
|
||||||
Assign Employee
|
|
||||||
</button>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="table-responsive text-nowrap">
|
<div className="table-responsive text-nowrap">
|
||||||
{/* {employees && employees.length > 0 ? ( */}
|
{/* {employees && employees.length > 0 ? ( */}
|
||||||
|
|||||||
@ -58,21 +58,6 @@ const TaskPlannng = () => {
|
|||||||
} else {
|
} else {
|
||||||
setProjectDetails(project_cache);
|
setProjectDetails(project_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
// api
|
|
||||||
// .get(`/api/project/details/${projectId}`)
|
|
||||||
// .then((data) => {
|
|
||||||
// setProjectDetails(data);
|
|
||||||
// setProject(data);
|
|
||||||
// dispatch(
|
|
||||||
// cacheApiResponse({ key: `projectinfo-${projectId}`, data: data })
|
|
||||||
// );
|
|
||||||
// setLoading(false);
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// console.error(error);
|
|
||||||
// setError("Failed to fetch data.");
|
|
||||||
// });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
setError("Failed to fetch data.");
|
setError("Failed to fetch data.");
|
||||||
|
|||||||
@ -32,14 +32,17 @@ const ForgotPasswordPage = () => {
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
setLoading(true)
|
||||||
const response = await AuthRepository.forgotPassword(data)
|
const response = await AuthRepository.forgotPassword(data)
|
||||||
if ( response.data && response.success )
|
if ( response.data && response.success )
|
||||||
showToast( response.message, "success" )
|
showToast( response.message, "success" )
|
||||||
setLoading( false )
|
setLoading( false )
|
||||||
setEmail( "" )
|
setEmail( "" )
|
||||||
|
console.log(response)
|
||||||
} catch ( err )
|
} catch ( err )
|
||||||
{
|
{
|
||||||
showToast( err.response.data, "error" )
|
|
||||||
|
showToast( err.message, "error" )
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,12 @@ import ProjectRepository from "../../repositories/ProjectRepository";
|
|||||||
import { ActivityeRepository } from "../../repositories/MastersRepository";
|
import { ActivityeRepository } from "../../repositories/MastersRepository";
|
||||||
|
|
||||||
import "./ProjectDetails.css";
|
import "./ProjectDetails.css";
|
||||||
import {useEmployeesByProjectAllocated} from "../../hooks/useProjects";
|
import {useEmployeesByProjectAllocated, useProjectDetails} from "../../hooks/useProjects";
|
||||||
|
|
||||||
|
|
||||||
const ProjectDetails = () => {
|
const ProjectDetails = () => {
|
||||||
let {projectId} = useParams();
|
let {projectId} = useParams();
|
||||||
|
const {projects_Details,loading:projectLoading,error:ProjectError} = useProjectDetails(projectId)
|
||||||
|
|
||||||
const [project, setProject] = useState(null);
|
const [project, setProject] = useState(null);
|
||||||
const [ projectDetails, setProjectDetails ] = useState( null );
|
const [ projectDetails, setProjectDetails ] = useState( null );
|
||||||
@ -50,14 +51,14 @@ const ProjectDetails = () => {
|
|||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
|
|
||||||
const project_cache = getCachedData(`projectinfo-${projectId}`);
|
const project_cache = getCachedData("projectInfo");
|
||||||
if (!project_cache) {
|
if (!project_cache || project_cache?.projectId !== projectId) {
|
||||||
ProjectRepository.getProjectByprojectId(projectId)
|
ProjectRepository.getProjectByprojectId(projectId)
|
||||||
.then( ( response ) =>
|
.then( ( response ) =>
|
||||||
{
|
{
|
||||||
setProjectDetails( response.data );
|
setProjectDetails( response.data );
|
||||||
setProject( response.data );
|
setProject( response.data );
|
||||||
cacheData( `projectinfo-${ projectId }`, response.data );
|
cacheData("projectInfo", {projectId,data: response.data} );
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -66,13 +67,14 @@ const ProjectDetails = () => {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setProjectDetails( project_cache );
|
setProjectDetails( project_cache.data );
|
||||||
setProject( project_cache );
|
setProject( project_cache.data );
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const [activePill, setActivePill] = useState("profile");
|
const [activePill, setActivePill] = useState("profile");
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +88,7 @@ const ProjectDetails = () => {
|
|||||||
|
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (loading) return <Loader></Loader>;
|
if (projectLoading) return <Loader></Loader>;
|
||||||
switch (activePill) {
|
switch (activePill) {
|
||||||
case "profile": {
|
case "profile": {
|
||||||
return (
|
return (
|
||||||
@ -152,13 +154,16 @@ const ProjectDetails = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
// fetchData();
|
||||||
|
setProject( projects_Details )
|
||||||
|
setProjectDetails(projects_Details)
|
||||||
fetchActivities();
|
fetchActivities();
|
||||||
}, []);
|
}, [projects_Details]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<>
|
<>
|
||||||
|
{}
|
||||||
<div className="container-xxl flex-grow-1 container-p-y">
|
<div className="container-xxl flex-grow-1 container-p-y">
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
data={[
|
data={[
|
||||||
@ -169,8 +174,8 @@ const ProjectDetails = () => {
|
|||||||
></Breadcrumb>
|
></Breadcrumb>
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{loading && <p>Loading....</p>}
|
{projectLoading && <p>Loading....</p>}
|
||||||
{!loading && <ProjectBanner project_data={project} ></ProjectBanner>}
|
{(!projectLoading && project) && <ProjectBanner project_data={project} ></ProjectBanner>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
|||||||
@ -14,6 +14,7 @@ const ProjectRepository = {
|
|||||||
// updateProject: (data) => api.post("/api/project/update", data),
|
// updateProject: (data) => api.post("/api/project/update", data),
|
||||||
|
|
||||||
manageProjectAllocation: ( data ) => api.post( "/api/project/allocation", data ),
|
manageProjectAllocation: ( data ) => api.post( "/api/project/allocation", data ),
|
||||||
|
|
||||||
manageProjectInfra: (data) => api.post("/api/project/manage-infra", data),
|
manageProjectInfra: (data) => api.post("/api/project/manage-infra", data),
|
||||||
manageProjectTasks: (data) => api.post("/api/project/manage-infra", data),
|
manageProjectTasks: (data) => api.post("/api/project/manage-infra", data),
|
||||||
|
|
||||||
@ -21,4 +22,8 @@ const ProjectRepository = {
|
|||||||
deleteProject: (id) => api.delete(`/projects/${id}`),
|
deleteProject: (id) => api.delete(`/projects/${id}`),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TasksRepository = {
|
||||||
|
assignTask: ( data ) => api.post( "/api/task/assign", data ),
|
||||||
|
reportTak:(data)=>api.post("/api/task/report",data)
|
||||||
|
}
|
||||||
export default ProjectRepository;
|
export default ProjectRepository;
|
||||||
|
|||||||
@ -54,7 +54,7 @@ axiosClient.interceptors.response.use(
|
|||||||
console.error("Request timed out.");
|
console.error("Request timed out.");
|
||||||
showToast("The request took too long. Please try again later.", "error");
|
showToast("The request took too long. Please try again later.", "error");
|
||||||
} else if (error.response) {
|
} else if (error.response) {
|
||||||
console.error("Error response:", error.response.status, error.response.data);
|
showToast(error.response.data.message,"error")
|
||||||
|
|
||||||
if (error.response.status === 401 && !originalRequest._retry) {
|
if (error.response.status === 401 && !originalRequest._retry) {
|
||||||
originalRequest._retry = true;
|
originalRequest._retry = true;
|
||||||
@ -89,7 +89,9 @@ axiosClient.interceptors.response.use(
|
|||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
|
|
||||||
showToast(error.response.data?.message || "An error occurred. Please try again.", "error");
|
showToast(error.response.data?.message || "An error occurred. Please try again.", "error");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user