updated project infra components and added assigntask

This commit is contained in:
Pramod Mahajan 2025-04-05 13:10:24 +05:30
parent 1451c1aff7
commit ddfbed1020
27 changed files with 1275 additions and 1475 deletions

81
src/ModalContext.jsx Normal file
View 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",
};

View File

@ -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>

View File

@ -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} &nbsp;{" "}
</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} &nbsp; </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} &nbsp;
{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>
);
};

View File

@ -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>

View File

@ -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;

View 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} &nbsp;
{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

View 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;

View 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} &nbsp;</span>
</h6>
</div>
</div>
</td>
</tr>
)}
</React.Fragment>
);
};
export default Floor

View File

@ -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>

View 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

View File

@ -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 (

View 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} &nbsp;
</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;

View 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;

View 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;

View File

@ -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} &nbsp;{" "}
</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} &nbsp; </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} &nbsp;
{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>

View File

@ -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>

View File

@ -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 (

View File

@ -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;

View File

@ -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}

View File

@ -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>

View File

@ -91,8 +91,11 @@ const AttendancePage = () =>
useEffect(()=>{
setAttendances(attendance)
},[attendance])
useEffect( () =>
{
dispatch(setProjectId(projects[0]?.id))
},[projects])
return (
<>
{isCreateModalOpen && modelConfig && (

View File

@ -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 ? ( */}

View File

@ -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>
</>

View File

@ -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)
}
}

View File

@ -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">

View File

@ -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;

View File

@ -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 {