From 94962ef7a6e02ac81ed3e28b292a29f8743262f2 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 30 Jul 2025 12:30:50 +0530 Subject: [PATCH 1/2] When a project is selected, the last selected project will be displayed. --- src/components/Layout/Header.jsx | 88 +++++++++++++-------------- src/components/Project/ProjectNav.jsx | 30 ++++----- src/pages/project/ProjectDetails.jsx | 4 +- src/slices/apiDataManager.jsx | 16 ++++- src/slices/localVariablesSlice.jsx | 2 + 5 files changed, 78 insertions(+), 62 deletions(-) diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx index b5b62579..f3c4dda3 100644 --- a/src/components/Layout/Header.jsx +++ b/src/components/Layout/Header.jsx @@ -3,6 +3,7 @@ import { cacheData, clearAllCache, getCachedData, + useSelectedproject, } from "../../slices/apiDataManager"; import AuthRepository from "../../repositories/AuthRepository"; import { useDispatch, useSelector } from "react-redux"; @@ -12,18 +13,18 @@ import { useProfile } from "../../hooks/useProfile"; import { useLocation, useNavigate, useParams } from "react-router-dom"; import Avatar from "../../components/common/Avatar"; import { useChangePassword } from "../Context/ChangePasswordContext"; -import { useProjects } from "../../hooks/useProjects"; +import { useProjects, useProjectName } from "../../hooks/useProjects"; // Make sure useProjects is imported if needed elsewhere import { useCallback, useEffect, useState } from "react"; -import { useProjectName } from "../../hooks/useProjects"; import eventBus from "../../services/eventBus"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { MANAGE_PROJECT } from "../../utils/constants"; +import { useMemo } from "react"; const Header = () => { const { profile } = useProfile(); const location = useLocation(); const dispatch = useDispatch(); - const { data, loading } = useMaster(); + const { data, loading: masterLoading } = useMaster(); // Renamed loading to masterLoading for clarity const navigate = useNavigate(); const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT); @@ -33,11 +34,9 @@ const Header = () => { /^\/dashboard$/.test(location.pathname) || /^\/$/.test(location.pathname); // Define the specific project status IDs you want to filter by - // Changed to explicitly include only 'Active', 'On Hold', 'In Progress' const allowedProjectStatusIds = [ "603e994b-a27f-4e5d-a251-f3d69b0498ba", // On Hold "cdad86aa-8a56-4ff4-b633-9c629057dfef", // In Progress - // "ef1c356e-0fe0-42df-a5d3-8daee355492d", // Inactive - Removed as per requirement "b74da4c2-d07e-46f2-9919-e75e49b12731", // Active ]; @@ -68,7 +67,6 @@ const Header = () => { window.location.href = "/auth/login"; }) .catch((error) => { - // Even if logout API fails, clear local storage and redirect localStorage.removeItem("jwtToken"); localStorage.removeItem("refreshToken"); localStorage.removeItem("user"); @@ -87,53 +85,52 @@ const Header = () => { navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`); }; - const { projectNames, loading: projectLoading, fetchData } = useProjectName(); + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); // Renamed loading to projectLoading - const selectedProject = useSelector( - (store) => store.localVariables.projectId - ); + const selectedProject = useSelectedproject(); + + // Filter projects for the dropdown based on the current path and allowed statuses + const projectsForDropdown = useMemo(() => { + if (!projectNames) return []; // Return empty array if projectNames is not yet fetched + + return isDashboard + ? projectNames + : projectNames?.filter(project => allowedProjectStatusIds.includes(project.projectStatusId)); + }, [projectNames, isDashboard, allowedProjectStatusIds]); - // Conditional filtering for projectsForDropdown - // If on Dashboard, show all projects. Otherwise, filter by allowedProjectStatusIds. - const projectsForDropdown = isDashboard - ? projectNames // On dashboard, show all projects - : projectNames?.filter(project => - allowedProjectStatusIds.includes(project.projectStatusId) - ); // Determine the display text for the project dropdown - let displayText = "All Projects"; - if (selectedProject === null) { - displayText = "All Projects"; - } else if (selectedProject) { - // Find the selected project from the full projectNames list - const selectedProjectObj = projectNames?.find( - (p) => p?.id === selectedProject - ); - // Fallback to selectedProject ID if name not found during loading or mismatch - displayText = selectedProjectObj ? selectedProjectObj.name : selectedProject; - } else if (projectLoading) { - displayText = "Loading..."; + let displayText = "Loading..."; // Default to loading + if (!projectLoading && projectNames) { // Only update if not loading and projectNames is available + if (selectedProject === null) { + displayText = "All Projects"; + } else { + // Find the selected project from the full projectNames list + const selectedProjectObj = projectNames.find( // Use projectNames directly here + (p) => p?.id === selectedProject + ); + displayText = selectedProjectObj ? selectedProjectObj.name : "All Projects"; // Fallback to "All Projects" if selected project is not found + } } + const { openChangePassword } = useChangePassword(); useEffect(() => { if ( projectNames && projectNames.length > 0 && - selectedProject === undefined && - !getCachedData("hasReceived") + selectedProject === undefined && // Only set default if no project is currently selected + !getCachedData("hasReceived") // Check if this flag is still relevant for your caching strategy ) { if (isDashboard) { dispatch(setProjectId(null)); // Always set to null for "All Projects" on Dashboard initial load } else { - // If not dashboard, set to the first project that matches the allowed statuses if available const firstAllowedProject = projectNames.find(project => allowedProjectStatusIds.includes(project.projectStatusId)); dispatch(setProjectId(firstAllowedProject?.id || null)); // Fallback to null if no allowed projects } } - }, [projectNames, selectedProject, dispatch, isDashboard]); + }, [projectNames, selectedProject, dispatch, isDashboard, allowedProjectStatusIds]); const handler = useCallback( @@ -154,7 +151,7 @@ const Header = () => { const newProjectHandler = useCallback( async (msg) => { if (HasManageProjectPermission && msg.keyword === "Create_Project") { - await fetchData(); + await fetchData(); } else if (projectNames?.some((item) => item.id === msg.response.id)) { await fetchData(); } @@ -177,16 +174,17 @@ const Header = () => { }; }, [handler, newProjectHandler]); - const handleProjectChange = (project) => { - dispatch(setProjectId(project)); // Always set the projectId - if (isProjectPath && project !== null) { - navigate("/projects/details"); // Navigate only if on /projects and a specific project is selected + const handleProjectChange = (projectId) => { + dispatch(setProjectId(projectId)); + if (isProjectPath && projectId !== null) { + navigate(`/projects/details?resetDates=true`); + } else if (isProjectPath && projectId === null) { + navigate("/projects"); + } else if (isDashboard) { } - // No navigation if on dashboard or if "All Projects" is selected }; - // Determine if the dropdown should be shown const shouldShowDropdown = isDashboard || (projectsForDropdown && projectsForDropdown.length > 1); @@ -223,15 +221,17 @@ const Header = () => { {displayText} ) : ( - // If only one project, just display its name without a dropdown + // If only one project or no projects (and not dashboard), just display its name/message without a dropdown - {projectsForDropdown && projectsForDropdown.length === 1 + {projectLoading ? "Loading..." : + (projectsForDropdown && projectsForDropdown.length === 1 ? projectsForDropdown[0].name - : displayText} + : (isDashboard ? "All Projects" : "No Projects")) // Handle "No Projects" for non-dashboard views + } )} - {/* Only render the dropdown menu if shouldShowDropdown is true */} + {/* Only render the dropdown menu if shouldShowDropdown is true AND there are projects to show */} {shouldShowDropdown && projectsForDropdown && projectsForDropdown.length > 0 && ( diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index 7df9107e..e4d81f5e 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -13,6 +13,7 @@ import { cacheData, clearCacheKey, getCachedData, + useSelectedproject, } from "../../slices/apiDataManager"; import "./ProjectDetails.css"; import { @@ -28,8 +29,7 @@ import { setProjectId } from "../../slices/localVariablesSlice"; const ProjectDetails = () => { - - const projectId = useSelector((store) => store.localVariables.projectId); + const projectId = useSelectedproject() const { projectNames, fetchData } = useProjectName(); const dispatch = useDispatch() diff --git a/src/slices/apiDataManager.jsx b/src/slices/apiDataManager.jsx index 84cc1d8d..d0f8bc67 100644 --- a/src/slices/apiDataManager.jsx +++ b/src/slices/apiDataManager.jsx @@ -5,6 +5,7 @@ import { flushApiCache, } from "../slices/apiCacheSlice"; import {setLoginUserPermmisions} from "./globalVariablesSlice"; +import { useSelector } from "react-redux"; // Cache data @@ -36,4 +37,17 @@ export const cacheProfileData = ( data) => { // Get cached data export const getCachedProfileData = () => { return store.getState().globalVariables.loginUser; -}; \ No newline at end of file +}; + +export const useSelectedproject = () => { + const selectedProject = useSelector((store)=> store.localVariables.projectId); + var project = localStorage.getItem("project"); + if(project){ + return project + } else{ + return selectedProject + } + // return project ? selectedProject + + +}; \ No newline at end of file diff --git a/src/slices/localVariablesSlice.jsx b/src/slices/localVariablesSlice.jsx index 7e7ada9d..7c996608 100644 --- a/src/slices/localVariablesSlice.jsx +++ b/src/slices/localVariablesSlice.jsx @@ -21,7 +21,9 @@ const localVariablesSlice = createSlice({ state.regularizationCount = action.payload; }, setProjectId: (state, action) => { + localStorage.setItem("project",null) state.projectId = action.payload; + localStorage.setItem("project",state.projectId) }, refreshData: ( state, action ) => { From 6c571e62da74a56078b63440c43fc484578396f5 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 30 Jul 2025 13:18:20 +0530 Subject: [PATCH 2/2] In ProjectNav bar last selected tab will be shown when we refresh the page. --- src/pages/project/ProjectDetails.jsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index e4d81f5e..1c1492b6 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -47,9 +47,10 @@ const ProjectDetails = () => { refetch, } = useProjectDetails(projectId); - const [activePill, setActivePill] = useState("profile"); - - + // const [activePill, setActivePill] = useState("profile"); + const [activePill, setActivePill] = useState(() => { + return localStorage.getItem("lastActiveProjectTab") || "profile"; +}); const handler = useCallback( (msg) => { @@ -65,9 +66,11 @@ const ProjectDetails = () => { return () => eventBus.off("project", handler); }, [handler]); - const handlePillClick = (pillKey) => { - setActivePill(pillKey); - }; + const handlePillClick = (pillKey) => { + setActivePill(pillKey); + localStorage.setItem("lastActiveProjectTab", pillKey); // ✅ Save to localStorage +}; + const renderContent = () => { if (projectLoading || !projects_Details) return ;