From eccbb8c609ec60ded517810a626090c3c3e278b2 Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Tue, 17 Jun 2025 20:44:43 +0530 Subject: [PATCH] changed name AssignRole to AssignTask --- src/components/Project/AssignTask.jsx | 574 ++++++++++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 src/components/Project/AssignTask.jsx diff --git a/src/components/Project/AssignTask.jsx b/src/components/Project/AssignTask.jsx new file mode 100644 index 00000000..797560cc --- /dev/null +++ b/src/components/Project/AssignTask.jsx @@ -0,0 +1,574 @@ +import React, { useState, useEffect, useRef } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { changeMaster } from "../../slices/localVariablesSlice"; +import useMaster from "../../hooks/masterHook/useMaster"; +import { useForm, Controller } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { clearCacheKey, getCachedData } from "../../slices/apiDataManager"; +import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees"; +import { TasksRepository } from "../../repositories/ProjectRepository"; +import showToast from "../../services/toastService"; +import { useProjectDetails } from "../../hooks/useProjects"; + +const AssignTask = ({ assignData, onClose, setAssigned }) => { + const maxPlanned = + assignData?.workItem?.workItem?.plannedWork - + assignData?.workItem?.workItem?.completedWork; + + // Zod schema for form validation + const schema = z.object({ + selectedEmployees: z + .array(z.string()) + .min(1, { message: "At least one employee must be selected" }), + description: z.string().min(1, { message: "Description is required" }), + plannedTask: z.preprocess( + (val) => parseInt(val, 10), + z + .number({ + required_error: "Planned task is required", + invalid_type_error: "Target for Today must be a number", + }) + .int() + .positive({ message: "Planned task must be a positive number" }) + .max(maxPlanned, { + + message: `Planned task cannot exceed ${maxPlanned}`, + }) + ), + }); + + const [isHelpVisibleTarget, setIsHelpVisibleTarget] = useState(false); + const helpPopupRefTarget = useRef(null); + const [isHelpVisible, setIsHelpVisible] = useState(false); + + // Refs for Bootstrap Popovers + const infoRef = useRef(null); + const infoRef1 = useRef(null); + + // Initialize Bootstrap Popovers on component mount + useEffect(() => { + // Check if Bootstrap is available globally + if (typeof bootstrap !== "undefined") { + if (infoRef.current) { + new bootstrap.Popover(infoRef.current, { + trigger: "focus", + placement: "right", + html: true, + content: `
Total Pending tasks of the Activity
`, + }); + } + + if (infoRef1.current) { + new bootstrap.Popover(infoRef1.current, { + trigger: "focus", + placement: "right", + html: true, + content: `
Target task for today
`, + }); + } + } else { + console.warn("Bootstrap is not available. Popovers might not function."); + } + }, []); // Empty dependency array ensures this runs once on mount + // Redux state and hooks + const selectedProject = useSelector( + (store) => store.localVariables.projectId + ); + const { employees, loading: employeeLoading } = useEmployeesAllOrByProjectId( + selectedProject, + false + ); + const dispatch = useDispatch(); + const { loading } = useMaster(); // Assuming this is for jobRoleData loading + const jobRoleData = getCachedData("Job Role"); + + // Local component states + const [selectedRole, setSelectedRole] = useState("all"); + const [displayedSelection, setDisplayedSelection] = useState(""); // This state is not updated in the provided code, consider if it's still needed or how it should be updated + + // React Hook Form setup + const { + handleSubmit, + control, + setValue, + watch, + formState: { errors }, + reset, + trigger, // <--- IMPORTANT: Destructure 'trigger' here + } = useForm({ + defaultValues: { + selectedEmployees: [], + description: "", + plannedTask: "", + }, + resolver: zodResolver(schema), // Integrate Zod schema with react-hook-form + }); + + // Handler for employee checkbox changes + const handleCheckboxChange = (event, user) => { + const isChecked = event.target.checked; + let updatedSelectedEmployees = watch("selectedEmployees") || []; // Get current selected employees from form state + + if (isChecked) { + // Add employee if checked and not already in the list + if (!updatedSelectedEmployees.includes(user.id)) { + updatedSelectedEmployees = [...updatedSelectedEmployees, user.id]; + } + } else { + // Remove employee if unchecked + updatedSelectedEmployees = updatedSelectedEmployees.filter( + (id) => id !== user.id + ); + } + // Update the form state with the new list of selected employees + setValue("selectedEmployees", updatedSelectedEmployees); + trigger("selectedEmployees"); // <--- IMPORTANT: Trigger validation here + }; + + // Effect to dispatch action for Job Role master data + useEffect(() => { + dispatch(changeMaster("Job Role")); + // Cleanup function to reset selected role when component unmounts or dispatch changes + return () => setSelectedRole("all"); + }, [dispatch]); + + // Handler for role filter change + const handleRoleChange = (event) => { + setSelectedRole(event.target.value); + }; + + // Filter employees based on selected role + const filteredEmployees = + selectedRole === "all" + ? employees + : employees?.filter( + (emp) => String(emp.jobRoleId || "") === selectedRole + ); + + // Form submission handler + const onSubmit = async (data) => { + const selectedEmployeeIds = data.selectedEmployees; + + // Prepare taskTeam data (only IDs are needed for the backend based on previous context) + const taskTeamWithDetails = selectedEmployeeIds + .map((empId) => { + return empId; // Return just the ID as per previous discussions + }) + .filter(Boolean); // Ensure no nulls if employee not found (though unlikely with current logic) + + // Format data for API call + const formattedData = { + taskTeam: taskTeamWithDetails, + plannedTask: data.plannedTask, + description: data.description, + assignmentDate: new Date().toISOString(), // Current date/time + workItemId: assignData?.workItem?.workItem.id, + }; + + try { + // Call API to assign task + // Close the modal + } catch (error) { + console.error("Error assigning task:", error); + showToast("Something went wrong. Please try again.", "error"); + } + }; + + // Handler to close the modal and reset form + const closedModel = () => { + reset(); + onClose(); + }; + return ( + +
+

Assign Task

+
+
+

+ + Work Location : + {[ + assignData?.building?.name, + assignData?.floor?.floorName, + assignData?.workArea?.areaName, + assignData?.workItem?.workItem?.activityMaster + ?.activityName, + ] + .filter(Boolean) // Filter out any undefined/null values + .map((item, index, array) => ( + + {item} + {index < array.length - 1 && ( + + )} + + ))} + +

+ +
+
+
+
+
+
+ Select Team +
{displayedSelection}
+ + +
    +
  • + +
  • + {jobRoleData?.map((user) => ( +
  • + +
  • + ))} +
+
+
+
+
+ +
+
+ {selectedRole !== "" && ( +
+ {loading ? ( // Assuming 'loading' here refers to master data loading +
+

Loading roles...

+
+ ) : filteredEmployees?.length > 0 ? ( + filteredEmployees?.map((emp) => { + const jobRole = jobRoleData?.find( + (role) => role?.id === emp?.jobRoleId + ); + + return ( +
+
+ ( + { + handleCheckboxChange(e, emp); + }} + /> + )} + /> +
+

+ {emp.firstName} {emp.lastName} +

+ + {loading ? ( + + + + ) : ( + jobRole?.name || "Unknown Role" + )} + +
+
+
+ ); + }) + ) : ( +
+

+ No employees found for the selected role. +

+
+ )} +
+ )} +
+
+ +
+ {watch("selectedEmployees")?.length > 0 && ( +
+
+ {watch("selectedEmployees")?.map((empId) => { + const emp = employees.find( + (emp) => emp.id === empId + ); + return ( + emp && ( + + {emp.firstName} {emp.lastName} +

{ + const updatedSelected = watch( + "selectedEmployees" + ).filter((id) => id !== empId); + setValue( + "selectedEmployees", + updatedSelected + ); + trigger("selectedEmployees"); // <--- IMPORTANT: Trigger validation on removing badge + }} + > + +

+
+ ) + ); + })} +
+
+ )} +
+ + {!loading && errors.selectedEmployees && ( +
+

{errors.selectedEmployees.message}

{" "} + {/* Use message from Zod schema */} +
+ )} + + {/* Pending Task of Activity section */} +
+
+ +
+
+ + {/* Target for Today input and validation */} +
+
+ +
+
+ ( +
+ + + { + assignData?.workItem?.workItem?.activityMaster + ?.unitOfMeasurement + } + +
+
+   + + + + +
+
+
+ )} + /> +
+ + {errors.plannedTask && ( +
+ {errors.plannedTask.message} +
+ )} + + {isHelpVisible && ( +
+ {/* Add your help content here */} +

+ Enter the target value for today's task. +

+
+ )} +
+ + + ( +