diff --git a/src/components/Activities/SubTask.jsx b/src/components/Activities/SubTask.jsx new file mode 100644 index 00000000..996509e5 --- /dev/null +++ b/src/components/Activities/SubTask.jsx @@ -0,0 +1,552 @@ +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 SubTask = ({ assignData, onClose }) => { + 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); + + const infoRef = useRef(null); + const infoRef1 = useRef(null); + + useEffect(() => { + 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."); + } + }, []); + + const selectedProject = useSelector( + (store) => store.localVariables.projectId + ); + const { employees, loading: employeeLoading } = useEmployeesAllOrByProjectId( + selectedProject, + false + ); + const dispatch = useDispatch(); + const { loading } = useMaster(); + const jobRoleData = getCachedData("Job Role"); + + const [selectedRole, setSelectedRole] = useState("all"); + const [displayedSelection, setDisplayedSelection] = useState(""); + + const { + handleSubmit, + control, + setValue, + watch, + formState: { errors }, + reset, + trigger, + } = useForm({ + defaultValues: { + selectedEmployees: [], + description: "", + plannedTask: "", + }, + resolver: zodResolver(schema), + }); + + const handleCheckboxChange = (event, user) => { + const isChecked = event.target.checked; + let updatedSelectedEmployees = watch("selectedEmployees") || []; // Get current selected employees from form state + + if (isChecked) { + if (!updatedSelectedEmployees.includes(user.id)) { + updatedSelectedEmployees = [...updatedSelectedEmployees, user.id]; + } + } else { + updatedSelectedEmployees = updatedSelectedEmployees.filter( + (id) => id !== user.id + ); + } + setValue("selectedEmployees", updatedSelectedEmployees); + trigger("selectedEmployees"); // <--- IMPORTANT: Trigger validation here + }; + + useEffect(() => { + dispatch(changeMaster("Job Role")); + return () => setSelectedRole("all"); + }, [dispatch]); + + // Handler for role filter change + const handleRoleChange = (event) => { + setSelectedRole(event.target.value); + }; + + const filteredEmployees = + selectedRole === "all" + ? employees + : employees?.filter( + (emp) => String(emp.jobRoleId || "") === selectedRole + ); + + const onSubmit = async (data) => { + const selectedEmployeeIds = data.selectedEmployees; + + const taskTeamWithDetails = selectedEmployeeIds + .map((empId) => { + return empId; + }) + .filter(Boolean); + + + + + let payload = { + + assignmentDate: new Date().toISOString(), + parentTaskId: assignData?.id, + plannedTask: data.plannedTask, + description: data.description, + taskTeam: taskTeamWithDetails, + workItemId: assignData.workItem.workItemId + } + + try { + console.log(payload) + showToast("Task Successfully Assigned", "success"); + reset(); + clearCacheKey("projectInfo"); + + onClose(); + } catch (error) { + console.error("Error assigning task:", error); + showToast("Something went wrong. Please try again.", "error"); + } + }; + + const closedModel = () => { + reset(); + onClose(); + }; + console.log(assignData); + return ( +
+

Create Sub 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 ? ( +
+

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 */} +
+ )} + +
+
+ +
+
+ + {/* Target for Today input and validation */} +
+
+ +
+
+ ( +
+ + + { + assignData?.workItem?.workItem?.activityMaster + ?.unitOfMeasurement + } + +
+
+   + + + + +
+
+
+ )} + /> +
+ + {errors.plannedTask && ( +
+ {errors.plannedTask.message} +
+ )} + + {isHelpVisible && ( +
+

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

+
+ )} +
+ + + ( +