From 3fddb686d3cafe79db4fa66d996c02cb5a6f6238 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Sat, 27 Sep 2025 14:58:39 +0530 Subject: [PATCH] change get employee at assign task to employee --- src/components/Project/AssignTask.jsx | 339 ++++++++++++++----------- src/hooks/useProjects.js | 8 + src/repositories/ProjectRepository.jsx | 13 + 3 files changed, 207 insertions(+), 153 deletions(-) diff --git a/src/components/Project/AssignTask.jsx b/src/components/Project/AssignTask.jsx index 0f755176..8c8aab22 100644 --- a/src/components/Project/AssignTask.jsx +++ b/src/components/Project/AssignTask.jsx @@ -1,24 +1,25 @@ import React, { useState, useEffect, useRef, useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { changeMaster } from "../../slices/localVariablesSlice"; -import useMaster from "../../hooks/masterHook/useMaster"; +import useMaster, { useServices } 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 { useSelectedProject } from "../../slices/apiDataManager"; import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees"; import { TasksRepository } from "../../repositories/ProjectRepository"; import showToast from "../../services/toastService"; -import { useProjectDetails } from "../../hooks/useProjects"; +import { + useEmployeeForTaskAssign, + useProjectAssignedOrganizations, + useProjectDetails, +} from "../../hooks/useProjects"; import eventBus from "../../services/eventBus"; import { useCreateTask } from "../../hooks/useTasks"; import Label from "../common/Label"; -const AssignTask = ({ assignData, onClose, setAssigned }) => { - const maxPlanned = - assignData?.workItem?.plannedWork - assignData?.workItem?.completedWork; - - const schema = z.object({ +const TaskSchema = (maxPlanned) => { + return z.object({ selectedEmployees: z .array(z.string()) .min(1, { message: "At least one employee must be selected" }), @@ -37,20 +38,26 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { }) ), }); +}; + +const AssignTask = ({ assignData, onClose, setAssigned }) => { + const planned = assignData?.workItem?.plannedWork || 0; + const completed = assignData?.workItem?.completedWork || 0; + const maxPlanned = planned - completed; const [isHelpVisibleTarget, setIsHelpVisibleTarget] = useState(false); const helpPopupRefTarget = useRef(null); const [isHelpVisible, setIsHelpVisible] = useState(false); + const [selectedService, setSelectedService] = useState(null); + const [selectedOrganization, setSelectedOrganization] = useState(null); + const { mutate: assignTask, isPending: isSubmitting } = useCreateTask({ - onSuccessCallback: () => { - closedModel(); - }, + onSuccessCallback: closedModel, }); const dropdownRef = useRef(null); const [open, setOpen] = useState(false); - // Close dropdown on outside click useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { @@ -63,48 +70,47 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { const infoRef = useRef(null); const infoRef1 = useRef(null); - - // State for search term const [searchTerm, setSearchTerm] = useState(""); useEffect(() => { if (typeof bootstrap !== "undefined") { - if (infoRef.current) { + infoRef.current && new bootstrap.Popover(infoRef.current, { trigger: "focus", placement: "right", html: true, content: `
Total Pending tasks of the Activity
`, }); - } - if (infoRef1.current) { + 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, - recallEmployeeData, - } = useEmployeesAllOrByProjectId(false, selectedProject, false); - const dispatch = useDispatch(); - const { loading } = useMaster(); - const { data: jobRoleData } = useMaster(); - // Changed to an array to hold multiple selected roles + const selectedProject = useSelectedProject(); + const { data: serviceList, isLoading: isServiceLoading } = useServices(); + const { data: organizationList, isLoading: isOrgLoading } = + useProjectAssignedOrganizations(selectedProject); + const { data: employees, isLoading: isEmployeeLoading } = + useEmployeeForTaskAssign( + selectedProject, + selectedService, + selectedOrganization + ); + + const dispatch = useDispatch(); + const { loading, data: jobRoleData } = useMaster(); + const [selectedRoles, setSelectedRoles] = useState(["all"]); const [displayedSelection, setDisplayedSelection] = useState(""); + const { handleSubmit, control, @@ -114,133 +120,98 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { reset, trigger, } = useForm({ - defaultValues: { - selectedEmployees: [], - description: "", - plannedTask: "", - }, - resolver: zodResolver(schema), + defaultValues: { selectedEmployees: [], description: "", plannedTask: "" }, + resolver: zodResolver(TaskSchema(maxPlanned)), }); const handleCheckboxChange = (event, user) => { - const isChecked = event.target.checked; - let updatedSelectedEmployees = watch("selectedEmployees") || []; + const updatedSelectedEmployees = event.target.checked + ? [...(watch("selectedEmployees") || []), user.id].filter( + (v, i, a) => a.indexOf(v) === i + ) + : (watch("selectedEmployees") || []).filter((id) => id !== user.id); - if (isChecked) { - if (!updatedSelectedEmployees.includes(user.id)) { - updatedSelectedEmployees = [...updatedSelectedEmployees, user.id]; - } - } else { - updatedSelectedEmployees = updatedSelectedEmployees?.filter( - (id) => id !== user.id - ); - } setValue("selectedEmployees", updatedSelectedEmployees); trigger("selectedEmployees"); }; useEffect(() => { dispatch(changeMaster("Job Role")); - // Initial state should reflect "All Roles" selected setSelectedRoles(["all"]); }, [dispatch]); - // Modified handleRoleChange to handle multiple selections const handleRoleChange = (event, roleId) => { - // If 'all' is selected, clear other selections - if (roleId === "all") { - setSelectedRoles(["all"]); - } else { - setSelectedRoles((prevSelectedRoles) => { - // If "all" was previously selected, remove it - const newRoles = prevSelectedRoles.filter((role) => role !== "all"); - if (newRoles.includes(roleId)) { - // If role is already selected, unselect it - return newRoles.filter((id) => id !== roleId); - } else { - // If role is not selected, add it - return [...newRoles, roleId]; - } - }); - } + setSelectedRoles((prev) => { + if (roleId === "all") return ["all"]; + const newRoles = prev.filter((r) => r !== "all"); + return newRoles.includes(roleId) + ? newRoles.filter((r) => r !== roleId) + : [...newRoles, roleId]; + }); }; useEffect(() => { - // Update displayedSelection based on selectedRoles if (selectedRoles.includes("all")) { setDisplayedSelection("All Roles"); } else if (selectedRoles.length > 0) { - const selectedRoleNames = selectedRoles.map(roleId => { - const role = jobRoleData?.find(r => String(r.id) === roleId); - return role ? role.name : ''; - }).filter(Boolean); // Filter out empty strings for roles not found - setDisplayedSelection(selectedRoleNames.join(', ')); - } else { - setDisplayedSelection("Select Roles"); - } + setDisplayedSelection( + selectedRoles + .map((id) => jobRoleData?.find((r) => String(r.id) === id)?.name) + .filter(Boolean) + .join(", ") + ); + } else setDisplayedSelection("Select Roles"); }, [selectedRoles, jobRoleData]); + const handleSearchChange = (e) => setSearchTerm(e.target.value); - const handleSearchChange = (event) => { - setSearchTerm(event.target.value); - }; - - // Filter employees first by role, then by search term AND job role name - const filteredEmployees = employees?.filter((emp) => { + const filteredEmployees = employees?.data?.filter((emp) => { const matchesRole = - selectedRoles.includes("all") || selectedRoles.includes(String(emp.jobRoleId)); - // Convert both first and last names and job role name to lowercase for case-insensitive matching - const fullName = `${emp.firstName} ${emp.lastName}`.toLowerCase(); - - const jobRoleName = jobRoleData?.find((role) => role.id === emp.jobRoleId)?.name?.toLowerCase() || ""; - + selectedRoles.includes("all") || + selectedRoles.includes(String(emp.jobRoleId)); const searchLower = searchTerm.toLowerCase(); - // Check if the full name OR job role name includes the search term - const matchesSearch = fullName.includes(searchLower) || jobRoleName.includes(searchLower); - return matchesRole && matchesSearch; + const fullName = `${emp.firstName} ${emp.lastName}`.toLowerCase(); + const jobRoleName = + jobRoleData + ?.find((role) => role.id === emp.jobRoleId) + ?.name?.toLowerCase() || ""; + return ( + matchesRole && + (fullName.includes(searchLower) || jobRoleName.includes(searchLower)) + ); }); - // Determine unique job role IDs from the filtered employees (for dropdown options) - const uniqueJobRoleIdsInFilteredEmployees = new Set( - employees?.map(emp => emp.jobRoleId).filter(Boolean) + const jobRolesForDropdown = jobRoleData?.filter((role) => + new Set(employees?.data?.map((emp) => emp.jobRoleId).filter(Boolean)).has( + role.id + ) ); - // Filter jobRoleData to only include roles present in the uniqueJobRoleIdsInFilteredEmployees - const jobRolesForDropdown = jobRoleData?.filter(role => - uniqueJobRoleIdsInFilteredEmployees.has(role.id) - ); - - // Calculate the count of selected roles for display const selectedRolesCount = selectedRoles.includes("all") - ? 0 // "All Roles" doesn't contribute to a specific count + ? 0 : selectedRoles.length; const onSubmit = (data) => { - const selectedEmployeeIds = data.selectedEmployees; - - const taskTeamWithDetails = selectedEmployeeIds - ?.map((empId) => empId) - ?.filter(Boolean); - const formattedData = { - taskTeam: taskTeamWithDetails, - plannedTask: data.plannedTask, - description: data.description, - assignmentDate: new Date().toISOString(), - workItemId: assignData?.workItem.id, - }; assignTask({ - payload: formattedData, + payload: { + taskTeam: data.selectedEmployees.filter(Boolean), + plannedTask: data.plannedTask, + description: data.description, + assignmentDate: new Date().toISOString(), + workItemId: assignData?.workItem.id, + }, workAreaId: assignData?.workArea?.id, }); }; - const closedModel = () => { + function closedModel() { reset(); onClose(); - }; + } + return (
-

Assign Task

+

Assign Task

@@ -252,7 +223,7 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { assignData?.workArea?.areaName, assignData?.workItem?.activityMaster?.activityName, ] - .filter(Boolean) // Filter out any undefined/null values + .filter(Boolean) .map((item, index, array) => ( {item} @@ -268,20 +239,64 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {

-
+
+
+
+ +
+
+ +
+
@@ -381,19 +403,19 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { > {selectedRoles?.length > 0 && (
- {employeeLoading ? ( + {isEmployeeLoading ? (

Loading employees...

) : filteredEmployees?.length > 0 ? ( - filteredEmployees.map((emp) => { + filteredEmployees.map((emp,index) => { const jobRole = jobRoleData?.find( (role) => role?.id === emp?.jobRoleId ); return (
@@ -441,7 +463,7 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { ) : (

- No employees found for the selected role. + No employees found for the selected filter.

)} @@ -456,12 +478,14 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { {watch("selectedEmployees")?.length > 0 && (
- {watch("selectedEmployees")?.map((empId) => { - const emp = employees.find((emp) => emp.id === empId); + {watch("selectedEmployees")?.map((empId,ind) => { + const emp = employees?.data?.find( + (emp) => emp.id === empId + ); return ( emp && ( {emp.firstName} {emp.lastName} @@ -506,7 +530,12 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { {assignData?.workItem?.plannedWork - assignData?.workItem?.completedWork} {" "} - {assignData?.workItem?.activityMaster?.unitOfMeasurement} + + { + assignData?.workItem?.activityMaster + ?.unitOfMeasurement + } +
@@ -537,8 +566,15 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => { className="form-control form-control-sm" {...field} /> - - {assignData?.workItem?.activityMaster?.unitOfMeasurement} + + + { + assignData?.workItem?.activityMaster + ?.unitOfMeasurement + } +
)} @@ -546,19 +582,17 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {
{errors.plannedTask && ( -
{errors.plannedTask.message}
+
+ {errors.plannedTask.message} +
)}
- - {/* */} - { {isSubmitting ? "Please Wait" : "Submit"}
-
diff --git a/src/hooks/useProjects.js b/src/hooks/useProjects.js index eeac3c31..bdbd01c6 100644 --- a/src/hooks/useProjects.js +++ b/src/hooks/useProjects.js @@ -308,6 +308,14 @@ export const useProjectAssignedServices = (projectId) => { }); }; + +export const useEmployeeForTaskAssign = (projectId,serviceId,organizationId)=>{ + return useQuery({ + queryKey:["EmployeeForTaskAssign",projectId,serviceId,organizationId], + queryFn:async()=> await ProjectRepository.getEmployeeForTaskAssign(projectId,serviceId,organizationId) + }) +} + // -- -------------Mutation------------------------------- export const useCreateProject = ({ onSuccessCallback }) => { diff --git a/src/repositories/ProjectRepository.jsx b/src/repositories/ProjectRepository.jsx index 42dde36a..b1b0727f 100644 --- a/src/repositories/ProjectRepository.jsx +++ b/src/repositories/ProjectRepository.jsx @@ -82,6 +82,19 @@ const ProjectRepository = { api.get(`/api/Project/get/assigned/services/${projectId}`), getProjectAssignedOrganizations: (projectId) => api.get(`/api/Project/get/assigned/organization/${projectId}`), + + getEmployeeForTaskAssign: (projectId, serviceId, organizationId) => { + let url = `/api/Project/get/task/team/${projectId}`; + + const params = []; + if (serviceId) params.push(`serviceId=${serviceId}`); + if (organizationId) params.push(`organizationId=${organizationId}`); + + if (params.length > 0) { + url += `?${params.join("&")}`; + } + return api.get(url); + }, }; export const TasksRepository = {