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} ) =>
|
||||
{
|
||||
|
||||
console.log(attendance)
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(attendance, 5);
|
||||
const [loading,setLoading] = useState(false);
|
||||
const navigate = useNavigate()
|
||||
@ -38,7 +38,7 @@ const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
||||
return checkInB - checkInA; // Sort in descending order of checkInTime
|
||||
})
|
||||
.map( ( item ) => (
|
||||
<tr key={item.id}>
|
||||
<tr key={item.employeeId}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
<Avatar
|
||||
@ -60,9 +60,10 @@ const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span className="badge bg-label-primary me-1">
|
||||
{/* <span className="badge bg-label-primary me-1">
|
||||
{getRole(item.roleID)}
|
||||
</span>
|
||||
</span> */}
|
||||
---
|
||||
</td>
|
||||
<td>{item.checkInTime ? convertShortTime(item.checkInTime):"--"}</td>
|
||||
<td>{item.checkOutTime ? convertShortTime(item.checkOutTime):"--"}</td>
|
||||
|
@ -1,567 +1,105 @@
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "../../components/Project/ProjectInfra.css";
|
||||
import BuildingModel from "../../components/Project/BuildingModel";
|
||||
import FloorModel from "../../components/Project/FloorModel";
|
||||
import BuildingModel from "../Project/Infrastructure/BuildingModel";
|
||||
import FloorModel from "../Project/Infrastructure/FloorModel";
|
||||
import showToast from "../../services/toastService";
|
||||
import WorkAreaModel from "../../components/Project/WorkAreaModel";
|
||||
import TaskModel from "../../components/Project/TaskModel";
|
||||
import WorkAreaModel from "../Project/Infrastructure/WorkAreaModel";
|
||||
import TaskModel from "../Project/Infrastructure/TaskModel";
|
||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
||||
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 [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,
|
||||
floor: updatedFloor,
|
||||
workArea: null,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
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 InfraPlanning = () =>
|
||||
{
|
||||
const {profile: LoggedUser} = useProfile()
|
||||
const dispatch = useDispatch()
|
||||
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 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 (
|
||||
<>
|
||||
{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="card">
|
||||
{/* <div className="card-header pb-4"></div> */}
|
||||
|
||||
<div className="card-body" style={{ padding: "0.5rem" }}>
|
||||
<div className="align-items-center">
|
||||
<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="#building-model"
|
||||
onClick={() => openBuildingModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Building
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#floor-model"
|
||||
onClick={() => openFloorModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Floors
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#work-area-model"
|
||||
onClick={() => openWorkAreaModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Work Areas
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#task-model"
|
||||
onClick={() => openTaskModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Tasks
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
||||
<div className="card">
|
||||
<div className="card-body" style={{ padding: "0.5rem" }}>
|
||||
<div className="align-items-center">
|
||||
<div className="row ">
|
||||
<div className="col-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="row">
|
||||
<div className="col-12">
|
||||
{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 className={`col-12 text-end mb-1 ${!ManageInfra && 'd-none'} `} >
|
||||
<button
|
||||
type="button"
|
||||
className="link-button link-button-sm m-1 "
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#building-model"
|
||||
// onClick={() => openBuildingModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Building
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#floor-model"
|
||||
// onClick={() => openFloorModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Floors
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#work-area-model"
|
||||
// onClick={() => openWorkAreaModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Work Areas
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
className="link-button m-1"
|
||||
data-bs-target="#task-model"
|
||||
// onClick={() => openTaskModel()}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Tasks
|
||||
</button>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="row ">
|
||||
<InfraTable buildings={projects_Details?.buildings}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,20 +1,32 @@
|
||||
import React, { useState,useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { changeMaster } from "../../slices/localVariablesSlice";
|
||||
import useMaster from "../../hooks/masterHook/useMaster";
|
||||
import { employee } from "../../data/masters";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
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({
|
||||
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[target,setTraget] = useState("")
|
||||
const { openModal, closeModal } = useModal()
|
||||
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
||||
const {employees} = useEmployeesAllOrByProjectId( selectedProject )
|
||||
|
||||
const dispatch = useDispatch()
|
||||
const {data,loading} = useMaster()
|
||||
const jobRoleData = getCachedData("Job Role")
|
||||
@ -26,7 +38,8 @@ const [selectedEmployees, setSelectedEmployees] = useState([]);
|
||||
|
||||
const { handleSubmit, control, setValue, watch, formState: { errors } } = useForm({
|
||||
defaultValues: {
|
||||
selectedEmployees: []
|
||||
selectedEmployees: [],
|
||||
description:""
|
||||
},
|
||||
resolver: (data) => {
|
||||
const validation = schema.safeParse(data);
|
||||
@ -36,13 +49,13 @@ const { handleSubmit, control, setValue, watch, formState: { errors } } = useFor
|
||||
});
|
||||
|
||||
const handleRoleChange = (event) => {
|
||||
setSelectedRole(event.target.value);
|
||||
setSelectedRole(event.plannedTask.value);
|
||||
};
|
||||
|
||||
|
||||
const filteredEmployees = selectedRole === "all"
|
||||
? employee
|
||||
: employee.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
||||
? employees
|
||||
: employees.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
||||
|
||||
|
||||
// not need currently for this fun
|
||||
@ -56,7 +69,7 @@ const handleEmployeeSelection = (employeeId,field) => {
|
||||
} else {
|
||||
updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||
}
|
||||
field.onChange(updatedSelection); // Update form state with new selection
|
||||
field.onChange(updatedSelection);
|
||||
return updatedSelection;
|
||||
});
|
||||
};
|
||||
@ -65,17 +78,34 @@ const handleEmployeeSelection = (employeeId,field) => {
|
||||
const removeEmployee = (employeeId) => {
|
||||
setSelectedEmployees((prevSelected) => {
|
||||
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||
setValue("selectedEmployees", updatedSelection); // Ensure form state is updated
|
||||
setValue("selectedEmployees", updatedSelection);
|
||||
return updatedSelection;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const onSubmit = (data) => {
|
||||
console.log( {...data.selectedEmployees,target});
|
||||
onClose()
|
||||
};
|
||||
const onSubmit = async(data) => {
|
||||
const formattedData = {
|
||||
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(()=>{
|
||||
dispatch(changeMaster("Job Role"))
|
||||
return ()=> setSelectedRole("all")
|
||||
@ -84,8 +114,7 @@ useEffect(()=>{
|
||||
|
||||
return (<>
|
||||
|
||||
|
||||
<div className="container-fluid my-1">
|
||||
<div className="container my-1">
|
||||
<div className="mb-2">
|
||||
<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="row">
|
||||
{filteredEmployees.map((emp) => {
|
||||
const jobRole = jobRoleData?.find((role) => role.id === emp.JobRoleId);
|
||||
const jobRole = jobRoleData?.find((role) => role.id === emp.jobRoleId);
|
||||
|
||||
return (
|
||||
<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}
|
||||
checked={field.value.includes(emp.id)} // Ensure the checkbox reflects the current form state
|
||||
onChange={() => {
|
||||
// Directly update the form value
|
||||
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
|
||||
handleEmployeeSelection( emp.id, field )
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<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">
|
||||
{loading && (<p className="skeleton para" style={{height:"7px"}}></p>)}
|
||||
{data && !loading && (jobRole ? jobRole.name : 'Unknown Role')}
|
||||
@ -187,16 +212,15 @@ useEffect(()=>{
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{selectedEmployees.length > 0 && (
|
||||
<div className="mt-1">
|
||||
<div className="text-start px-2">
|
||||
{selectedEmployees.map((empId) => {
|
||||
const emp = employee.find((emp) => emp.id === empId);
|
||||
const emp = employees.find((emp) => emp.id === empId);
|
||||
return (
|
||||
<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
|
||||
type="button"
|
||||
className=" btn-close-white p-0 m-0"
|
||||
@ -212,30 +236,47 @@ useEffect(()=>{
|
||||
</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="form-check form-check-inline mt-4 px-1">
|
||||
<label className="form-text fs-6" for="inlineCheckbox1">Pending Work</label>
|
||||
<label className="form-check-label ms-2" for="inlineCheckbox1">{ assignData?.workItem?.workItem?.plannedWork - assignData?.workItem?.workItem?.completedWork}</label>
|
||||
</div>
|
||||
<div className="form-check form-check-inline col-sm-2 col">
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{errors.selectedEmployees && (
|
||||
<div className="danger-text mt-2">
|
||||
<p>{errors.selectedEmployees[0]}</p>
|
||||
<label for="defaultFormControlInput" className="form-label">Target</label>
|
||||
<Controller name="pannedTask" control={control} render={( {field} ) => (
|
||||
<input type="text" className="form-control form-control-sm " {...field} />
|
||||
)} />
|
||||
{errors.pannedTask && (
|
||||
<div className="danger-text">
|
||||
<p>{errors.pannedTask.message}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
<div className="col-12 d-flex justify-content-center align-items-center gap-sm-6 gap-8 text-center">
|
||||
</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 mt-1">
|
||||
<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
|
||||
</button>
|
||||
</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 { 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 = {
|
||||
id: "0",
|
||||
floorName: "",
|
||||
buildingId: "0",
|
||||
projectId: "",
|
||||
};
|
||||
|
||||
const FloorModel = ({
|
||||
@ -15,67 +25,80 @@ const FloorModel = ({
|
||||
onClearComplete,
|
||||
}) => {
|
||||
const [formData, setFormData] = useState(defaultModel);
|
||||
|
||||
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(() => {
|
||||
if (clearTrigger) {
|
||||
setFormData(defaultModel); // Clear form
|
||||
onClearComplete(); // Notify parent that clearing is done
|
||||
reset(defaultModel);
|
||||
onClearComplete();
|
||||
}
|
||||
}, [clearTrigger, onClearComplete]);
|
||||
}, [clearTrigger, onClearComplete, reset]);
|
||||
|
||||
// Handle input change
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
// Handle building selection change
|
||||
const handleBuildigChange = (e) => {
|
||||
const buildingId = e.target.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 { name, value } = e.target;
|
||||
const floor = selectedBuilding.floors.find((b) => b.id === Number(value));
|
||||
const id = e.target.value;
|
||||
const floor = selectedBuilding.floors.find((b) => b.id === Number(id));
|
||||
if (floor) {
|
||||
setFormData({
|
||||
id: floor.id,
|
||||
floorName: floor.floorName,
|
||||
buildingId: selectedBuilding.id,
|
||||
projectId: project.id,
|
||||
|
||||
});
|
||||
} else
|
||||
setValue("floorName", floor.floorName); // Set floor name for form
|
||||
} else {
|
||||
setFormData({
|
||||
id: "0",
|
||||
floorName: "",
|
||||
buildingId: selectedBuilding.id,
|
||||
projectId: project.id,
|
||||
|
||||
});
|
||||
};
|
||||
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);
|
||||
setValue("floorName", "");
|
||||
}
|
||||
};
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
formData.projectId = project.id;
|
||||
const onFormSubmit = (data) => {
|
||||
|
||||
onSubmit(formData); // Pass the updated data to the parent
|
||||
onSubmit(data);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -92,18 +115,20 @@ const FloorModel = ({
|
||||
<div className="text-center mb-1">
|
||||
<h5 className="mb-1">Manage Floors - {project.name}</h5>
|
||||
</div>
|
||||
<form className="row g-2" onSubmit={handleSubmit}>
|
||||
<form
|
||||
className="row g-2"
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<div className="col-12 col-md-12">
|
||||
<label className="form-label" htmlFor="name">
|
||||
<label className="form-label" htmlFor="buildingId">
|
||||
Select Building
|
||||
</label>
|
||||
<select
|
||||
id="buildingId"
|
||||
name="buildingId"
|
||||
className="select2 form-select form-select-sm"
|
||||
aria-label="Default select example"
|
||||
aria-label="Select Building"
|
||||
{...register("buildingId")}
|
||||
onChange={handleBuildigChange}
|
||||
value={formData.buildingId}
|
||||
>
|
||||
<option value="0">Select Building</option>
|
||||
{project.buildings.map((building) => (
|
||||
@ -112,20 +137,22 @@ const FloorModel = ({
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.buildingId && (
|
||||
<p className="text-danger">{errors.buildingId.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{formData.buildingId != "0" && (
|
||||
{formData.buildingId !== "0" && (
|
||||
<div className="col-12 col-md-12">
|
||||
<label className="form-label" htmlFor="floorId">
|
||||
<label className="form-label" >
|
||||
Select Floor
|
||||
</label>
|
||||
<select
|
||||
id="floorId"
|
||||
name="floorId"
|
||||
id="id"
|
||||
className="select2 form-select form-select-sm"
|
||||
aria-label="Default select example"
|
||||
aria-label="Select Floor"
|
||||
{...register("id")}
|
||||
onChange={handleFloorChange}
|
||||
value={formData.floorId}
|
||||
>
|
||||
<option value="0">Add New Floor</option>
|
||||
{selectedBuilding.floors.map((floor) => (
|
||||
@ -134,30 +161,33 @@ const FloorModel = ({
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.id && (
|
||||
<p className="text-danger">{errors.id.message}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{formData.buildingId != "0" && (
|
||||
|
||||
{formData.buildingId !== "0" && (
|
||||
<div className="col-12 col-md-12">
|
||||
{" "}
|
||||
<label className="form-label" htmlFor="name">
|
||||
{formData.id != "0" ? "Modify " : "Enter "} Floor Name
|
||||
<label className="form-label" htmlFor="floorName">
|
||||
{formData.id !== "0" ? "Modify " : "Enter "} Floor Name
|
||||
</label>
|
||||
<div className="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="floorName"
|
||||
name="floorName"
|
||||
className="form-control form-control-sm me-2"
|
||||
placeholder="Floor Name"
|
||||
onChange={handleChange}
|
||||
value={formData.floorName}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
id="floorName"
|
||||
className="form-control form-control-sm me-2"
|
||||
placeholder="Floor Name"
|
||||
{...register("floorName")}
|
||||
/>
|
||||
{errors.floorName && (
|
||||
<p className="text-danger">{errors.floorName.message}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="col-12 text-center">
|
||||
<button type="submit" className="btn btn-primary me-3">
|
||||
{formData.id != "0" && formData.id != ""
|
||||
{formData.id !== "0" && formData.id !== ""
|
||||
? "Edit Floor"
|
||||
: "Add Floor"}
|
||||
</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,
|
||||
clearTrigger,
|
||||
onClearComplete,
|
||||
}) => {
|
||||
} ) =>
|
||||
{
|
||||
|
||||
const [formData, setFormData] = useState(defaultModel);
|
||||
|
||||
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
||||
const [selectedFloor, setSelectedFloor] = useState(null);
|
||||
const [selectedWorkArea, setSelectedWorkArea] = useState(null);
|
||||
@ -47,8 +48,8 @@ const TaskModel = ({
|
||||
if (clearTrigger) {
|
||||
let model = defaultModel;
|
||||
model.floorId = selectedFloor.id;
|
||||
setFormData(defaultModel); // Clear form
|
||||
onClearComplete(); // Notify parent that clearing is done
|
||||
setFormData(defaultModel);
|
||||
onClearComplete();
|
||||
}
|
||||
}, [clearTrigger, onClearComplete]);
|
||||
|
||||
@ -110,7 +111,8 @@ const TaskModel = ({
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
onSubmit(formData); // Pass the updated data to the parent
|
||||
// onSubmit( formData ); // Pass the updated data to the parent
|
||||
console.log(formData)
|
||||
};
|
||||
|
||||
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 "./ProjectInfra.css";
|
||||
import BuildingModel from "./BuildingModel";
|
||||
import FloorModel from "./FloorModel";
|
||||
import BuildingModel from "./Infrastructure/BuildingModel";
|
||||
import FloorModel from "./Infrastructure/FloorModel";
|
||||
import showToast from "../../services/toastService";
|
||||
import WorkAreaModel from "./WorkAreaModel";
|
||||
import TaskModel from "./TaskModel";
|
||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
||||
import WorkAreaModel from "./Infrastructure/WorkAreaModel";
|
||||
import TaskModel from "./Infrastructure/TaskModel";
|
||||
import ProjectRepository, {TasksRepository} from "../../repositories/ProjectRepository";
|
||||
import ProjectModal from "./ProjectModal";
|
||||
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
||||
import {MANAGE_PROJECT_INFRA} from "../../utils/constants";
|
||||
// import AssignRoleModel from "./AssignRoleModel";
|
||||
import InfraTable from "./Infrastructure/InfraTable";
|
||||
import {cacheData} from "../../slices/apiDataManager";
|
||||
|
||||
|
||||
|
||||
const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) => {
|
||||
|
||||
const [expandedBuildings, setExpandedBuildings] = useState([]);
|
||||
const [project, setProject] = useState(data);
|
||||
const[modalConfig,setModalConfig] = useState({type:null,data:null});
|
||||
@ -27,7 +29,8 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
const [isAssignRoleModal,setIsAssingRoleModal] = useState(false)
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||
const [clearFormTrigger, setClearFormTrigger] = useState(false);
|
||||
const [CurrentBuilding,setCurrentBuilding] = useState("")
|
||||
const [ CurrentBuilding, setCurrentBuilding ] = useState( "" )
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setProject(data);
|
||||
@ -50,6 +53,188 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
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) => {
|
||||
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) => {
|
||||
setIsWorkAreaModalOpen(true);
|
||||
};
|
||||
|
||||
const closeWorkAreaModel = () => {
|
||||
setIsWorkAreaModalOpen(false);
|
||||
// const modalBackdrop = document.querySelector(".modal-backdrop");
|
||||
// if (modalBackdrop) modalBackdrop.remove();
|
||||
|
||||
};
|
||||
const handleWorkAreaModelFormSubmit = (updatedModel) => {
|
||||
if (updatedModel.id == "") delete updatedModel.id;
|
||||
@ -124,19 +273,18 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
|
||||
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
|
||||
setClearFormTrigger(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
showToast(error.message, "error");
|
||||
@ -149,297 +297,54 @@ 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)=>{
|
||||
setModalConfig({type:type,data:modaldata})
|
||||
}
|
||||
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 = () => {
|
||||
setIsModalOpen(false);
|
||||
setModalConfig(null)
|
||||
|
||||
|
||||
const modalElement = document.getElementById('project-modal');
|
||||
const modalElement = document.getElementById('building-model');
|
||||
if (modalElement) {
|
||||
modalElement.classList.remove('show');
|
||||
modalElement.style.display = 'none'; // Hide modal visually
|
||||
document.body.classList.remove('modal-open'); // Unlock body scroll
|
||||
|
||||
|
||||
const backdropElement = document.querySelector('.modal-backdrop');
|
||||
if (backdropElement) {
|
||||
backdropElement.classList.remove('modal-backdrop'); // Remove backdrop class
|
||||
backdropElement.style.display = 'none'; // Hide the backdrop element
|
||||
}
|
||||
modalElement.classList.remove('show'); // Remove modal visibility class
|
||||
modalElement.style.display = 'none'; // Hide the modal element
|
||||
}
|
||||
const modalBackdropElement = document.querySelector('.modal-backdrop');
|
||||
if (modalBackdropElement) {
|
||||
modalBackdropElement.remove();
|
||||
|
||||
document.body.classList.remove('modal-open'); // Remove modal-open class from body
|
||||
|
||||
// Remove the modal backdrop
|
||||
const backdropElement = document.querySelector('.modal-backdrop');
|
||||
if (backdropElement) {
|
||||
backdropElement.classList.remove('modal-backdrop'); // Remove backdrop class
|
||||
backdropElement.style.display = 'none'; // Hide the backdrop element
|
||||
}
|
||||
document.body.style.overflow = 'auto';
|
||||
|
||||
};
|
||||
useEffect(() => {
|
||||
if (modalConfig !== null) {
|
||||
openModal();
|
||||
}
|
||||
|
||||
}, [modalConfig,isModalOpen]);
|
||||
|
||||
const handleShow = () => setShowModal(true);
|
||||
const handleClose = () => setShowModal( false );
|
||||
|
||||
return (
|
||||
<>
|
||||
{isBuildingModalOpen && (
|
||||
|
||||
<div
|
||||
className={`modal fade `}
|
||||
id="building-model"
|
||||
tabIndex="-1"
|
||||
aria-hidden="true"
|
||||
>
|
||||
className={`modal fade ${showModal ? 'show' : ''}`}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: showModal ? 'block' : 'none' }}
|
||||
aria-hidden={!showModal}
|
||||
>
|
||||
<BuildingModel
|
||||
project={data}
|
||||
onClose={closeBuildingModel}
|
||||
@ -448,7 +353,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
onClearComplete={() => setClearFormTrigger(false)}
|
||||
></BuildingModel>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{isFloorModalOpen && (
|
||||
<div
|
||||
@ -459,7 +364,6 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
>
|
||||
<FloorModel
|
||||
project={data}
|
||||
// building={null}
|
||||
onClose={closeFloorModel}
|
||||
onSubmit={handleFloorModelFormSubmit}
|
||||
clearTrigger={clearFormTrigger}
|
||||
@ -504,16 +408,13 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
{/* common Modal */}
|
||||
|
||||
{isModalOpen && (
|
||||
<ProjectModal modalConfig={modalConfig} closeModal={closeModal} />
|
||||
)}
|
||||
|
||||
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
||||
<div className="card">
|
||||
{/* <div className="card-header pb-4"></div> */}
|
||||
|
||||
<div className="card-body" style={{ padding: "0.5rem" }}>
|
||||
<div className="align-items-center">
|
||||
@ -522,14 +423,12 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
<button
|
||||
type="button"
|
||||
className="link-button link-button-sm m-1 "
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#building-model"
|
||||
onClick={() => openBuildingModel()}
|
||||
|
||||
onClick={handleShow}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Manage Building
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
@ -564,48 +463,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
</div>
|
||||
</div>
|
||||
<div className="row ">
|
||||
<div className="col-12 overflow-auto">
|
||||
{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>
|
||||
<InfraTable buildings={project.buildings}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -25,7 +25,8 @@ const ProjectModal = ({modalConfig,closeModal}) => {
|
||||
|
||||
{/* Modal Component */}
|
||||
|
||||
{modalConfig?.type === "assignRole" && <AssignRole assignData={modalConfig?.data} onClose={closeModal} />}
|
||||
{modalConfig?.type === "assignRole" && <AssignRole assignData={modalConfig?.data} onClose={closeModal} />}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@ import {useEmployeesByProjectAllocated} from "../../hooks/useProjects";
|
||||
|
||||
const ProjectOverview = ({project}) =>
|
||||
{
|
||||
const {projectEmployees} = useEmployeesByProjectAllocated( project.id );
|
||||
const {projectEmployees} = useEmployeesByProjectAllocated( project?.id );
|
||||
let teamSize = projectEmployees.filter( ( emp ) => emp.isActive )
|
||||
|
||||
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;
|
@ -5,9 +5,10 @@ import {
|
||||
} from "../slices/apiDataManager"
|
||||
import ProjectRepository from "../repositories/ProjectRepository";
|
||||
|
||||
|
||||
|
||||
export const useProjects =()=>{
|
||||
|
||||
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
@ -36,7 +37,8 @@ export const useProjects =()=>{
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
fetchData()
|
||||
fetchData()
|
||||
|
||||
},[])
|
||||
|
||||
return { projects,loading,error,refetch:fetchData}
|
||||
@ -84,18 +86,18 @@ export const useEmployeesByProjectAllocated = ( selectedProject ) =>
|
||||
export const useProjectDetails =(projectId)=>{
|
||||
|
||||
const [projects_Details, setProject_Details] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true)
|
||||
const project_cache = getCachedData(`projectinfo-${projectId}`);
|
||||
if (!project_cache) {
|
||||
setLoading(true)
|
||||
const project_cache = getCachedData("projectInfo");
|
||||
if (!project_cache || project_cache?.projectId !== projectId) {
|
||||
ProjectRepository.getProjectByprojectId(projectId)
|
||||
.then( ( response ) =>
|
||||
{
|
||||
setProject_Details(response.data);
|
||||
cacheData( `projectinfo-${ projectId }`, response.data );
|
||||
setProject_Details( response.data );
|
||||
cacheData("projectInfo", {projectId,data: response.data} );
|
||||
setLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -104,15 +106,17 @@ export const useProjectDetails =(projectId)=>{
|
||||
setLoading(false)
|
||||
});
|
||||
} else {
|
||||
setProject_Details( project_cache );
|
||||
|
||||
setProject_Details( project_cache.data );
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
};;
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
fetchData()
|
||||
if ( projectId )
|
||||
{
|
||||
fetchData()
|
||||
}
|
||||
},[projectId])
|
||||
|
||||
return { projects_Details,loading,error,refetch:fetchData}
|
||||
|
@ -6,14 +6,17 @@ import App from './App.tsx'
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './store/store';
|
||||
import { ModalProvider } from './ModalContext.jsx';
|
||||
|
||||
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
// <StrictMode>
|
||||
// <MasterDataProvider>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
<Provider store={ store }>
|
||||
<ModalProvider>
|
||||
<App />
|
||||
</ModalProvider>
|
||||
</Provider>
|
||||
// </MasterDataProvider>
|
||||
|
||||
|
@ -91,8 +91,11 @@ const AttendancePage = () =>
|
||||
useEffect(()=>{
|
||||
setAttendances(attendance)
|
||||
},[attendance])
|
||||
|
||||
|
||||
useEffect( () =>
|
||||
{
|
||||
dispatch(setProjectId(projects[0]?.id))
|
||||
},[projects])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isCreateModalOpen && modelConfig && (
|
||||
|
@ -14,18 +14,6 @@ const DailyTask =()=>{
|
||||
<div className="card card-action mb-6">
|
||||
<div className="card-body">
|
||||
<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 className="table-responsive text-nowrap">
|
||||
{/* {employees && employees.length > 0 ? ( */}
|
||||
|
@ -58,21 +58,6 @@ const TaskPlannng = () => {
|
||||
} else {
|
||||
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) {
|
||||
console.log(err)
|
||||
setError("Failed to fetch data.");
|
||||
@ -111,7 +96,7 @@ const TaskPlannng = () => {
|
||||
<InfraPlanning
|
||||
data={projectDetails}
|
||||
activityMaster={activities}
|
||||
onDataChange={handleDataChange}
|
||||
onDataChange={handleDataChange}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
@ -32,14 +32,17 @@ const ForgotPasswordPage = () => {
|
||||
{
|
||||
try
|
||||
{
|
||||
setLoading(true)
|
||||
const response = await AuthRepository.forgotPassword(data)
|
||||
if ( response.data && response.success )
|
||||
showToast( response.message, "success" )
|
||||
setLoading( false )
|
||||
setEmail("")
|
||||
setEmail( "" )
|
||||
console.log(response)
|
||||
} catch ( err )
|
||||
{
|
||||
showToast( err.response.data, "error" )
|
||||
|
||||
showToast( err.message, "error" )
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
@ -16,18 +16,19 @@ import ProjectRepository from "../../repositories/ProjectRepository";
|
||||
import { ActivityeRepository } from "../../repositories/MastersRepository";
|
||||
|
||||
import "./ProjectDetails.css";
|
||||
import {useEmployeesByProjectAllocated} from "../../hooks/useProjects";
|
||||
import {useEmployeesByProjectAllocated, useProjectDetails} from "../../hooks/useProjects";
|
||||
|
||||
|
||||
const ProjectDetails = () => {
|
||||
let { projectId } = useParams();
|
||||
let {projectId} = useParams();
|
||||
const {projects_Details,loading:projectLoading,error:ProjectError} = useProjectDetails(projectId)
|
||||
|
||||
const [project, setProject] = useState(null);
|
||||
const [ projectDetails, setProjectDetails ] = useState( null );
|
||||
const [activities, setActivities] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const [ error, setError ] = useState( "" );
|
||||
|
||||
const fetchActivities = async () => {
|
||||
|
||||
const activities_cache = getCachedData("activitiesMaster");
|
||||
@ -50,14 +51,14 @@ const ProjectDetails = () => {
|
||||
|
||||
const fetchData = async () => {
|
||||
|
||||
const project_cache = getCachedData(`projectinfo-${projectId}`);
|
||||
if (!project_cache) {
|
||||
const project_cache = getCachedData("projectInfo");
|
||||
if (!project_cache || project_cache?.projectId !== projectId) {
|
||||
ProjectRepository.getProjectByprojectId(projectId)
|
||||
.then( ( response ) =>
|
||||
{
|
||||
setProjectDetails(response.data);
|
||||
setProject(response.data);
|
||||
cacheData( `projectinfo-${ projectId }`, response.data );
|
||||
setProjectDetails( response.data );
|
||||
setProject( response.data );
|
||||
cacheData("projectInfo", {projectId,data: response.data} );
|
||||
setLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -66,13 +67,14 @@ const ProjectDetails = () => {
|
||||
setLoading(false)
|
||||
});
|
||||
} else {
|
||||
setProjectDetails( project_cache );
|
||||
setProject( project_cache );
|
||||
setProjectDetails( project_cache.data );
|
||||
setProject( project_cache.data );
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
const [activePill, setActivePill] = useState("profile");
|
||||
|
||||
|
||||
@ -86,7 +88,7 @@ const ProjectDetails = () => {
|
||||
|
||||
|
||||
const renderContent = () => {
|
||||
if (loading) return <Loader></Loader>;
|
||||
if (projectLoading) return <Loader></Loader>;
|
||||
switch (activePill) {
|
||||
case "profile": {
|
||||
return (
|
||||
@ -152,13 +154,16 @@ const ProjectDetails = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
// fetchData();
|
||||
setProject( projects_Details )
|
||||
setProjectDetails(projects_Details)
|
||||
fetchActivities();
|
||||
}, []);
|
||||
}, [projects_Details]);
|
||||
|
||||
return (
|
||||
|
||||
<>
|
||||
{}
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
<Breadcrumb
|
||||
data={[
|
||||
@ -169,8 +174,8 @@ const ProjectDetails = () => {
|
||||
></Breadcrumb>
|
||||
|
||||
<div className="row">
|
||||
{loading && <p>Loading....</p>}
|
||||
{!loading && <ProjectBanner project_data={project} ></ProjectBanner>}
|
||||
{projectLoading && <p>Loading....</p>}
|
||||
{(!projectLoading && project) && <ProjectBanner project_data={project} ></ProjectBanner>}
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
|
@ -13,7 +13,8 @@ const ProjectRepository = {
|
||||
manageProject: (data) => api.post("/api/project", 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),
|
||||
manageProjectTasks: (data) => api.post("/api/project/manage-infra", data),
|
||||
|
||||
@ -21,4 +22,8 @@ const ProjectRepository = {
|
||||
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;
|
||||
|
@ -54,8 +54,8 @@ axiosClient.interceptors.response.use(
|
||||
console.error("Request timed out.");
|
||||
showToast("The request took too long. Please try again later.", "error");
|
||||
} 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) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
@ -89,7 +89,9 @@ axiosClient.interceptors.response.use(
|
||||
redirectToLogin();
|
||||
return Promise.reject(err);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
|
||||
showToast(error.response.data?.message || "An error occurred. Please try again.", "error");
|
||||
}
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user