diff --git a/src/ModalContext.jsx b/src/ModalContext.jsx new file mode 100644 index 00000000..fa0f30f8 --- /dev/null +++ b/src/ModalContext.jsx @@ -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 ( + + {children} + + {isOpen && ( +
+
+
{modalContent}
+ +
+
+ )} +
+ ); +}; + +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", +}; diff --git a/src/components/Activities/Attendance.jsx b/src/components/Activities/Attendance.jsx index b4d3a378..2ce8217d 100644 --- a/src/components/Activities/Attendance.jsx +++ b/src/components/Activities/Attendance.jsx @@ -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 ) => ( - +
- + {/* {getRole(item.roleID)} - + */} + --- {item.checkInTime ? convertShortTime(item.checkInTime):"--"} {item.checkOutTime ? convertShortTime(item.checkOutTime):"--"} diff --git a/src/components/Activities/InfraPlanning.jsx b/src/components/Activities/InfraPlanning.jsx index 6fee662e..304a7352 100644 --- a/src/components/Activities/InfraPlanning.jsx +++ b/src/components/Activities/InfraPlanning.jsx @@ -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) => ( - - {floor.workAreas.length > 0 ? ( - floor.workAreas.map((workArea) => ( - - - -
-
- {" "} -
- - {" "} - {floor.floorName} - {workArea.areaName}  {" "} - -
-
- -
- - - {workArea.workItems.length > 0 ? ( - - {" "} - - - - - - - - - - - - - {workArea.workItems.map((workItem) => ( - - - - - - - - - {" "} - - ))} - -
ActivityPlannedComplatedProgressActions
- - - {workItem.workItem.activityMaster - ? workItem.workItem.activityMaster - .activityName - : "NA"} - - - {workItem.workItem - ? workItem.workItem.plannedWork - : "NA"} - - {workItem.workItem - ? workItem.workItem.completedWork - : "NA"} - -
-
-
- {/* */} -
-
- - -
-
{" "} - - - ) : ( - - )} -
- )) - ) : ( - - - -
-
- {" "} -
- {floor.floorName}   -
-
- -
- - -
- )} -
- )); - } else { - return ( - <> - - -

No Floors Added, Please add them

- {/*

- -

*/} - - - - ); - } - })()} - - ); - }; - - const getProgress = (planned, completed) => { - return (completed * 100) / planned + "%"; - }; return ( - <> - {isBuildingModalOpen && ( - - )} - - {isFloorModalOpen && ( - - )} - - {isWorkAreaModelOpen && ( - - )} - - {isTaskModelOpen && ( - - )} - - -
-
- {/*
*/} - -
-
-
-
- - - - - - -
+
+
+
+
+
+
+
-
-
- {buildings && buildings.length > 0 && ( - - - {buildings.map((building) => ( - building.floors && building.floors.length > 0 && ( - - - - - - {expandedBuildings.includes(building.id) && getContent(building)} - - - ) - ))} - -
toggleBuilding(building.id)} - > -
-
- - { building.name}   - {expandedBuildings.includes(building.id) ? ( - - ) : ( - - )} -
-
-
- )} -
-
-
+ {/*
+ + + + + +
*/} +
+
+
+
- - +
); }; diff --git a/src/components/Project/AssignRole.jsx b/src/components/Project/AssignRole.jsx index 199b7ffc..6933bdd4 100644 --- a/src/components/Project/AssignRole.jsx +++ b/src/components/Project/AssignRole.jsx @@ -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 (<> - -
+
{[ @@ -143,7 +172,7 @@ useEffect(()=>{
{filteredEmployees.map((emp) => { - const jobRole = jobRoleData?.find((role) => role.id === emp.JobRoleId); + const jobRole = jobRoleData?.find((role) => role.id === emp.jobRoleId); return (
@@ -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 ) }} /> )} />
-
{emp.FirtsName} {emp.LastName}
+
{emp.firstName + } {emp.lastName}
{loading && (

)} {data && !loading && (jobRole ? jobRole.name : 'Unknown Role')} @@ -187,16 +212,15 @@ useEffect(()=>{
)} - - {selectedEmployees.length > 0 && (
{selectedEmployees.map((empId) => { - const emp = employee.find((emp) => emp.id === empId); + const emp = employees.find((emp) => emp.id === empId); return ( - {emp.FirtsName} {emp.LastName} + {emp.firstName + } {emp.lastName}

{

)} - + {errors.selectedEmployees && ( +
+

{errors.selectedEmployees[0]}

+
+ )}
- - setTraget(e.target.value)} id="defaultFormControlInput" aria-describedby="defaultFormControlHelp" /> -
-
- - - - {errors.selectedEmployees && ( -
-

{errors.selectedEmployees[0]}

+ + ( + + )} /> + {errors.pannedTask && ( +
+

{errors.pannedTask.message}

)} - - -
+
+
+ + + ( +