diff --git a/src/components/common/FilterIcon.jsx b/src/components/common/FilterIcon.jsx index 7f448f4e..1ac8d892 100644 --- a/src/components/common/FilterIcon.jsx +++ b/src/components/common/FilterIcon.jsx @@ -1,90 +1,98 @@ import React, { useState, useEffect } from "react"; -const FilterIcon = ({ taskListData, onApplyFilters, currentSelectedBuilding, currentSelectedFloors, currentSelectedActivities }) => { - // State for filters, now managed within FilterIcon - const [selectedBuilding, setSelectedBuilding] = useState(currentSelectedBuilding); - const [selectedFloors, setSelectedFloors] = useState(currentSelectedFloors); - const [selectedActivities, setSelectedActivities] = useState(currentSelectedActivities); +const FilterIcon = ({ + taskListData, + onApplyFilters, + currentSelectedBuilding, + currentSelectedFloors, + currentSelectedActivities, +}) => { + const [selectedBuilding, setSelectedBuilding] = useState(currentSelectedBuilding || ""); + const [selectedFloors, setSelectedFloors] = useState(currentSelectedFloors || []); + const [selectedActivities, setSelectedActivities] = useState(currentSelectedActivities || []); - // Update internal state when props change (e.g., project selection in DailyTask clears filters) useEffect(() => { - setSelectedBuilding(currentSelectedBuilding); - setSelectedFloors(currentSelectedFloors); - setSelectedActivities(currentSelectedActivities); + setSelectedBuilding(currentSelectedBuilding || ""); + setSelectedFloors(currentSelectedFloors || []); + setSelectedActivities(currentSelectedActivities || []); }, [currentSelectedBuilding, currentSelectedFloors, currentSelectedActivities]); - // Helper to get unique values for filters based on current selections - const getUniqueFilterValues = (key) => { + const getUniqueFilterValues = (key, overrideBuilding, overrideFloors) => { if (!taskListData) return []; - let relevantTasks = taskListData; - // Filter tasks based on selected building for floors and activities - if (selectedBuilding) { - relevantTasks = relevantTasks.filter(task => - task?.workItem?.workArea?.floor?.building?.name === selectedBuilding + let filteredTasks = [...taskListData]; + + if (overrideBuilding) { + filteredTasks = filteredTasks.filter( + (task) => + task?.workItem?.workArea?.floor?.building?.name === overrideBuilding ); } - // Filter tasks based on selected floors for activities - if (selectedFloors.length > 0) { - relevantTasks = relevantTasks.filter(task => - selectedFloors.includes(task?.workItem?.workArea?.floor?.floorName) + if (overrideFloors?.length > 0) { + filteredTasks = filteredTasks.filter((task) => + overrideFloors.includes(task?.workItem?.workArea?.floor?.floorName) ); } - const values = relevantTasks.map(task => { - if (key === 'building') return task?.workItem?.workArea?.floor?.building?.name; - if (key === 'floor') return task?.workItem?.workArea?.floor?.floorName; - if (key === 'activity') return task?.workItem?.activityMaster?.activityName; + const values = filteredTasks.map((task) => { + if (key === "building") return task?.workItem?.workArea?.floor?.building?.name; + if (key === "floor") return task?.workItem?.workArea?.floor?.floorName; + if (key === "activity") return task?.workItem?.activityMaster?.activityName; return null; - }).filter(Boolean); // Remove null or undefined values - return [...new Set(values)].sort(); // Sort for consistent order + }); + + return [...new Set(values.filter(Boolean))].sort(); }; - const uniqueBuildings = getUniqueFilterValues('building'); - const uniqueFloors = getUniqueFilterValues('floor'); - const uniqueActivities = getUniqueFilterValues('activity'); + const uniqueBuildings = getUniqueFilterValues("building"); + const uniqueFloors = getUniqueFilterValues("floor", selectedBuilding); + const uniqueActivities = getUniqueFilterValues("activity", selectedBuilding, selectedFloors); - // Handle filter selection with dependency logic const handleFilterChange = (filterType, value) => { - let newSelectedBuilding = selectedBuilding; - let newSelectedFloors = [...selectedFloors]; - let newSelectedActivities = [...selectedActivities]; + let updatedBuilding = selectedBuilding; + let updatedFloors = [...selectedFloors]; + let updatedActivities = [...selectedActivities]; - if (filterType === 'building') { - if (selectedBuilding !== value) { - newSelectedFloors = []; - newSelectedActivities = []; + if (filterType === "building") { + updatedBuilding = value; + updatedFloors = []; + updatedActivities = []; + } else if (filterType === "floor") { + if (updatedFloors.includes(value)) { + updatedFloors = updatedFloors.filter((floor) => floor !== value); + } else { + updatedFloors.push(value); } - newSelectedBuilding = value; - } else if (filterType === 'floor') { - newSelectedFloors = selectedFloors.includes(value) ? selectedFloors.filter(item => item !== value) : [...selectedFloors, value]; - if (!newSelectedFloors.includes(value) && selectedFloors.includes(value)) { - newSelectedActivities = []; + + const validActivities = getUniqueFilterValues("activity", updatedBuilding, updatedFloors); + updatedActivities = updatedActivities.filter((act) => validActivities.includes(act)); + } else if (filterType === "activity") { + if (updatedActivities.includes(value)) { + updatedActivities = updatedActivities.filter((act) => act !== value); + } else { + updatedActivities.push(value); } - } else if (filterType === 'activity') { - newSelectedActivities = selectedActivities.includes(value) ? selectedActivities.filter(item => item !== value) : [...selectedActivities, value]; } - setSelectedBuilding(newSelectedBuilding); - setSelectedFloors(newSelectedFloors); - setSelectedActivities(newSelectedActivities); + setSelectedBuilding(updatedBuilding); + setSelectedFloors(updatedFloors); + setSelectedActivities(updatedActivities); - // Communicate the updated filter states back to the parent onApplyFilters({ - selectedBuilding: newSelectedBuilding, - selectedFloors: newSelectedFloors, - selectedActivities: newSelectedActivities, + selectedBuilding: updatedBuilding, + selectedFloors: updatedFloors, + selectedActivities: updatedActivities, }); }; const clearAllFilters = () => { - setSelectedBuilding(''); + setSelectedBuilding(""); setSelectedFloors([]); setSelectedActivities([]); - // Communicate cleared filters back to the parent + onApplyFilters({ - selectedBuilding: '', + selectedBuilding: "", selectedFloors: [], selectedActivities: [], }); @@ -98,20 +106,19 @@ const FilterIcon = ({ taskListData, onApplyFilters, currentSelectedBuilding, cur data-bs-toggle="dropdown" aria-expanded="false" > - - + 0 || selectedActivities.length > 0 ? "#7161EF" : "gray" }} + > + ); diff --git a/src/pages/Activities/DailyTask.jsx b/src/pages/Activities/DailyTask.jsx index 41e7ff9e..a194a41b 100644 --- a/src/pages/Activities/DailyTask.jsx +++ b/src/pages/Activities/DailyTask.jsx @@ -26,20 +26,17 @@ const DailyTask = () => { const [initialized, setInitialized] = useState(false); const dispatch = useDispatch(); - // State for filters (moved to FilterIcon, but we need to receive them here) const [filters, setFilters] = useState({ selectedBuilding: "", selectedFloors: [], selectedActivities: [], }); - // Sync projectId (either from URL or pick first accessible one) useEffect(() => { if (!project_loading && projects.length > 0 && !initialized) { if (projectIdFromUrl) { dispatch(setProjectId(projectIdFromUrl)); } else if (selectedProject === 1 || selectedProject === undefined) { - // If no project from URL or default/undefined, pick the first project dispatch(setProjectId(projects[0].id)); } setInitialized(true); @@ -57,7 +54,7 @@ const DailyTask = () => { const { TaskList, - loading: task_loading, // This `loading` state indicates if task data is being fetched + loading: task_loading, error: task_error, refetch, } = useTaskList( @@ -66,13 +63,11 @@ const DailyTask = () => { initialized ? dateRange.endDate : null ); - const [TaskLists, setTaskLists] = useState([]); // This state holds the *filtered* tasks for display + const [TaskLists, setTaskLists] = useState([]); const [dates, setDates] = useState([]); const popoverRefs = useRef([]); - // Effect to apply filters to TaskList (from useTaskList) and update TaskLists (filtered display) useEffect(() => { - // Only filter if TaskList is available (not null or undefined) if (TaskList) { let filteredTasks = TaskList; @@ -101,8 +96,6 @@ const DailyTask = () => { } setTaskLists(filteredTasks); } else { - // If TaskList is null (e.g., during initial load or project change before data arrives), - // ensure TaskLists is also empty to avoid displaying stale data. setTaskLists([]); } }, [ @@ -137,52 +130,22 @@ const DailyTask = () => { }; useEffect(() => { - // Ensure Bootstrap's Popover is initialized correctly popoverRefs.current.forEach((el) => { - if ( - el && - window.bootstrap && - typeof window.bootstrap.Popover === "function" - ) { - // Dispose existing popovers to prevent duplicates if component re-renders - const existingPopover = window.bootstrap.Popover.getInstance(el); - if (existingPopover) { - existingPopover.dispose(); - } - new window.bootstrap.Popover(el, { + if (el) { + new bootstrap.Popover(el, { trigger: "focus", placement: "left", html: true, - content: el.getAttribute("data-bs-content"), + content: el.getAttribute("data-bs-content"), }); } }); - - // Cleanup function for popovers when component unmounts or dependencies change - return () => { - popoverRefs.current.forEach((el) => { - if ( - el && - window.bootstrap && - typeof window.bootstrap.Popover === "function" - ) { - const existingPopover = window.bootstrap.Popover.getInstance(el); - if (existingPopover) { - existingPopover.dispose(); - } - } - }); - popoverRefs.current = []; // Clear the refs array - }; - }, [dates, TaskLists]); // Re-initialize popovers when tasks or dates change - - // Handler for project selection + },[dates, TaskLists]); + const handleProjectChange = (e) => { const newProjectId = e.target.value; dispatch(setProjectId(newProjectId)); - // --- IMPORTANT: Clear old data immediately to show loading state --- - setTaskLists([]); // This makes the table empty, allowing the spinner to show - // Reset filters when project changes (communicate to FilterIcon to clear) + setTaskLists([]); setFilters({ selectedBuilding: "", selectedFloors: [], @@ -192,7 +155,6 @@ const DailyTask = () => { return ( <> - {/* Report Task Modal */}
{ refetch={refetch} /> {isModalOpen &&
}{" "} - {/* Add backdrop */}
- {/* Report Task Comments Modal */}
{ closeModal={closeCommentModal} /> {isModalOpenComment &&
}{" "} - {/* Add backdrop */}
@@ -242,15 +201,12 @@ const DailyTask = () => { DateDifference="6" dateFormat="DD-MM-YYYY" /> - {/* FilterIcon component now manages its own filter states and logic */}
@@ -261,7 +217,7 @@ const DailyTask = () => { value={selectedProject || ""} onChange={handleProjectChange} aria-label="Select Project" - disabled={project_loading} // Disable dropdown while projects are loading + disabled={project_loading} > {project_loading && (