diff --git a/src/components/Charts/LineChart.jsx b/src/components/Charts/LineChart.jsx index 1dc1b1ac..6eb4840c 100644 --- a/src/components/Charts/LineChart.jsx +++ b/src/components/Charts/LineChart.jsx @@ -117,7 +117,7 @@ const LineChart = ({ return ( -
+
{ - const { projectsCardData } = useDashboardProjectsCardData(); - const { teamsCardData } = useDashboardTeamsCardData(); - const { tasksCardData } = useDashboardTasksCardData(); +const { projectsCardData } = useDashboardProjectsCardData(); +const { teamsCardData } = useDashboardTeamsCardData(); +const { tasksCardData } = useDashboardTasksCardData(); - return ( -
-
- {/* Projects Card */} -
- -
+// Get the selected project ID from Redux store +const selectedProjectId = useSelector( +(store) => store.localVariables.projectId +); - {/* Teams Card */} -
- -
+// Determine if "All Projects" is selected +// selectedProjectId will be null when "All Projects" is chosen +const isAllProjectsSelected = selectedProjectId === null; - {/* Tasks Card */} -
- -
+return ( +
+
- {/* Bar Chart (Project Completion) */} -
- -
+{isAllProjectsSelected && ( +
+ +
+)} - {/* Line Chart (Project Progress) */} -
- -
- {/*
- -
*/} -
-
- ); +
+ +
+ +
+ +
+ + +{isAllProjectsSelected && ( +
+ +
+)} + +{! isAllProjectsSelected && ( +
+ +
+)} +
+ +
+ + +
+
+); }; export default Dashboard; \ No newline at end of file diff --git a/src/components/Dashboard/ProjectProgressChart.jsx b/src/components/Dashboard/ProjectProgressChart.jsx index 20e0191a..f80bb0d5 100644 --- a/src/components/Dashboard/ProjectProgressChart.jsx +++ b/src/components/Dashboard/ProjectProgressChart.jsx @@ -93,33 +93,6 @@ const ProjectProgressChart = ({
Project Progress

Progress Overview by Project

- - {/* Right: Checkbox and Project Name */} -
- {ShowAllProject == true && ( -
- setShowAllEmployees(e.target.checked)} - /> - -
- )} - {!showAllEmployees && selectedProjectName && ( -

- {selectedProjectName} -

- )} -
{/* Row 2: Time Range Buttons */} diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx index 9c1b4b17..476c73d0 100644 --- a/src/components/Layout/Header.jsx +++ b/src/components/Layout/Header.jsx @@ -1,3 +1,4 @@ + import getGreetingMessage from "../../utils/greetingHandler"; import { cacheData, @@ -20,26 +21,28 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { MANAGE_PROJECT } from "../../utils/constants"; const Header = () => { - const {profile} = useProfile(); + const { profile } = useProfile(); const location = useLocation(); const dispatch = useDispatch(); const { data, loading } = useMaster(); const navigate = useNavigate(); const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT); + const isDirectoryPath = /^\/directory$/.test(location.pathname); + const isDashboard = /^\/dashboard$/.test(location.pathname); const getRole = (roles, joRoleId) => { if (!Array.isArray(roles)) return "User"; let role = roles.find((role) => role.id === joRoleId); return role ? role.name : "User"; }; + const handleLogout = (e) => { - e.preventDefault(); // Prevent default anchor behavior (e.g., page reload) + e.preventDefault(); logout(); }; const logout = async () => { try { - // Notify server about the logout (optional) let data = { refreshToken: localStorage.getItem("refreshToken"), }; @@ -54,6 +57,7 @@ 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"); @@ -71,98 +75,93 @@ const Header = () => { const handleProfilePage = () => { navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`); }; - // const { projects, loading: projectLoading } = useProjects(); + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); const selectedProject = useSelector( (store) => store.localVariables.projectId ); - const selectedProjectName = projectNames?.find( - (p) => p?.id === selectedProject - )?.name; - - let displayText = ""; - if (selectedProjectName) { - displayText = selectedProjectName; - } else if (projectLoading && selectedProject) { - displayText = selectedProject; + // Determine the display text for the project dropdown + let displayText = "All Projects"; + if (selectedProject === null) { + displayText = "All Projects"; + } else if (selectedProject) { + 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..."; } const { openChangePassword } = useChangePassword(); + useEffect(() => { if ( projectNames && - selectedProject !== " " && + projectNames.length > 0 && + selectedProject === undefined && !getCachedData("hasReceived") ) { - dispatch(setProjectId(projectNames[0]?.id)); + if(isDashboard){ + dispatch(setProjectId(null)); + }else{ + dispatch(setProjectId(projectNames[0]?.id)); + } } - }, [projectNames]); + }, [projectNames, selectedProject, dispatch]); + + + /** Check if current page is project details page or directory page */ + // const isProjectPath = /^\/projects\/[a-f0-9-]{36}$/.test(location.pathname); - /** Check if current page id project details page */ - const isProjectPath = /^\/projects\/[a-f0-9-]{36}$/.test(location.pathname) - const isDirectoryPath = /^\/directory$/.test(location.pathname); const handler = useCallback( async (data) => { if (!HasManageProjectPermission) { await fetchData(); const projectExist = data.projectIds.some( - (item) => item == selectedProject + (item) => item === selectedProject ); if (projectExist) { cacheData("hasReceived", false); } } }, - [fetchData,projectNames,selectedProject] + [fetchData, selectedProject, HasManageProjectPermission] ); - // useEffect(() => { - // eventBus.on("assign_project_one", handler); - // return () => eventBus.off("assign_project_one", handler); - // }, [handler]); - const newProjectHandler = useCallback( async (msg) => { - if (HasManageProjectPermission && msg.keyword === "Create_Project") { await fetchData(); - } else if (projectNames.some((item) => item.id == msg.response.id)) { - console.log((projectNames.some((item) => item.id == msg.response.id))) + } else if (projectNames?.some((item) => item.id === msg.response.id)) { await fetchData(); } cacheData("hasReceived", false); }, - [HasManageProjectPermission,projectNames] + [HasManageProjectPermission, projectNames, fetchData] ); - // useEffect(() => { - // eventBus.on("project", newProjectHandler); - // return () => eventBus.off("project", newProjectHandler); - // }, [handler]); - - useDispatch( () => - { - dispatch(changeMaster("Job Role")) -},[]) useEffect(() => { - eventBus.on("assign_project_one", handler); - eventBus.on("project", newProjectHandler); + dispatch(changeMaster("Job Role")); + }, [dispatch]); - return () => { - eventBus.off("assign_project_one", handler); - eventBus.off("project", newProjectHandler); - }; -}, [handler, newProjectHandler]); + useEffect(() => { + eventBus.on("assign_project_one", handler); + eventBus.on("project", newProjectHandler); + return () => { + eventBus.off("assign_project_one", handler); + eventBus.off("project", newProjectHandler); + }; + }, [handler, newProjectHandler]); return ( ); }; -export default Header; +export default Header; \ No newline at end of file diff --git a/src/components/Project/AboutProject.jsx b/src/components/Project/AboutProject.jsx index 30c42e03..e5196eac 100644 --- a/src/components/Project/AboutProject.jsx +++ b/src/components/Project/AboutProject.jsx @@ -2,48 +2,53 @@ import React, { useEffect, useState } from "react"; import moment from "moment"; import { getProjectStatusName } from "../../utils/projectStatus"; import {useProjectDetails, useUpdateProject} from "../../hooks/useProjects"; -import {useParams} from "react-router-dom"; +import { useSelector } from "react-redux"; // Import useSelector import {useHasUserPermission} from "../../hooks/useHasUserPermission"; import {MANAGE_PROJECT} from "../../utils/constants"; import GlobalModel from "../common/GlobalModel"; import ManageProjectInfo from "./ManageProjectInfo"; import {useQueryClient} from "@tanstack/react-query"; -const AboutProject = () => -{ - const [ IsOpenModal, setIsOpenModal ] = useState( false ) - const {mutate: UpdateProjectDetails, isPending} = useUpdateProject( { - onSuccessCallback: () => - { - setIsOpenModal(false) + +const AboutProject = () => { + const [IsOpenModal, setIsOpenModal] = useState(false); + const {mutate: UpdateProjectDetails, isPending} = useUpdateProject({ + onSuccessCallback: () => { + setIsOpenModal(false); } - } ) - const ClientQuery = useQueryClient() - const {projectId} = useParams(); + }); + const ClientQuery = useQueryClient(); + + // *** MODIFIED LINE: Get projectId from Redux store using useSelector *** + const projectId = useSelector((store) => store.localVariables.projectId); + const manageProject = useHasUserPermission(MANAGE_PROJECT); - const {projects_Details, isLoading, error,refetch} = useProjectDetails( projectId ) - const handleFormSubmit = ( updatedProject ) => - { - if ( projects_Details?.id ) - { - UpdateProjectDetails({ projectId: projects_Details?.id,updatedData: updatedProject, - } ); - refetch() - } -}; + const {projects_Details, isLoading, error,refetch} = useProjectDetails( projectId ); // Pass projectId from useSelector + + const handleFormSubmit = ( updatedProject ) => { + if ( projects_Details?.id ) { + UpdateProjectDetails({ projectId: projects_Details?.id,updatedData: updatedProject }); + // The refetch here might be redundant or could be handled by react-query's invalidateQueries + // if UpdateProjectDetails properly invalidates the 'projectDetails' query key. + // If refetch is still needed, consider adding a delay or using onSuccess of UpdateProjectDetails. + // For now, keeping it as is based on your original code. + refetch(); + } + }; + return ( <> {IsOpenModal && ( - setIsOpenModal(false)}> + setIsOpenModal(false)}> setIsOpenModal( false )} isPending={isPending} /> - - )} + + )} {projects_Details && ( - <> + <>
@@ -126,10 +131,9 @@ const AboutProject = () => )} - {isLoading && loading...} ); }; -export default AboutProject; +export default AboutProject; \ No newline at end of file diff --git a/src/components/Project/Infrastructure/WorkItem.jsx b/src/components/Project/Infrastructure/WorkItem.jsx index df1f2bc1..629f9e39 100644 --- a/src/components/Project/Infrastructure/WorkItem.jsx +++ b/src/components/Project/Infrastructure/WorkItem.jsx @@ -31,7 +31,9 @@ const WorkItem = ({ forWorkArea, deleteHandleTask, }) => { - const { projectId } = useParams(); + // const { projectId } = useParams(); +const isTaskPlanning = /^\/activities\/task$/.test(location.pathname); + const [itemName, setItemName] = useState(""); const [NewWorkItem, setNewWorkItem] = useState(); const [isModalOpen, setIsModalOpen] = useState(false); @@ -244,7 +246,7 @@ const WorkItem = ({ {/* Desktop (md and up): inline icons */}
- {!projectId && + {isTaskPlanning && ManageAndAssignTak && PlannedWork !== CompletedWork && (
-
- +
+
    +
  • +
    + {/* Centered Chart */} +
    +
    + +
    +
    + + {/* Info Section */} +
    +
    + {/* Tasks Planned */} +
    +
    + + + +
    +
    + Tasks Planned +
    + {FormattedNumber(current_project?.plannedWork)} +
    +
    +
    + + {/* Tasks Completed */} +
    +
    + + + +
    +
    + Tasks Completed +
    + {FormattedNumber(current_project?.completedWork)} +
    +
    +
    + + {/* Team Size */} +
    +
    + + + +
    +
    + Current Team Size +
    + {FormattedNumber(current_project?.teamSize)} +
    +
    +
    +
    +
    +
  • +
+
+
); }; -export default ProjectOverview; +export default ProjectOverview; \ No newline at end of file diff --git a/src/components/Project/Teams.jsx b/src/components/Project/Teams.jsx index 263f3f41..25e3eda8 100644 --- a/src/components/Project/Teams.jsx +++ b/src/components/Project/Teams.jsx @@ -7,7 +7,7 @@ import Avatar from "../common/Avatar"; import moment from "moment"; import ProjectRepository from "../../repositories/ProjectRepository"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { changeMaster } from "../../slices/localVariablesSlice"; import useMaster from "../../hooks/masterHook/useMaster"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; @@ -18,7 +18,8 @@ import {useEmployeesByProjectAllocated, useManageProjectAllocation} from "../../ const Teams = () => { - const {projectId} = useParams() + // const {projectId} = useParams() + const projectId = useSelector((store)=>store.localVariables.projectId) const dispatch = useDispatch(); const { data, loading } = useMaster(); diff --git a/src/pages/Activities/AttendancePage.jsx b/src/pages/Activities/AttendancePage.jsx index 9f309197..f4e6c58c 100644 --- a/src/pages/Activities/AttendancePage.jsx +++ b/src/pages/Activities/AttendancePage.jsx @@ -21,13 +21,14 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { REGULARIZE_ATTENDANCE } from "../../utils/constants"; import eventBus from "../../services/eventBus"; import AttendanceRepository from "../../repositories/AttendanceRepository"; +import { useProjectName } from "../../hooks/useProjects"; const AttendancePage = () => { const [activeTab, setActiveTab] = useState("all"); const [ShowPending, setShowPending] = useState(false); const loginUser = getCachedProfileData(); var selectedProject = useSelector((store) => store.localVariables.projectId); - // const { projects, loading: projectLoading } = useProjects(); + const dispatch = useDispatch() const { attendance, loading: attLoading, @@ -38,7 +39,8 @@ const AttendancePage = () => { const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [modelConfig, setModelConfig] = useState(); const DoRegularized = useHasUserPermission(REGULARIZE_ATTENDANCE); - const dispatch = useDispatch(); + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); + const [formData, setFormData] = useState({ markTime: "", @@ -130,7 +132,13 @@ const AttendancePage = () => { const handleToggle = (event) => { setShowOnlyCheckout(event.target.checked); }; + useEffect(() => { + if(selectedProject == null){ + dispatch(setProjectId(projectNames[0]?.id)); + } + },[]) + useEffect(() => { if (modelConfig !== null) { openModel(); @@ -140,18 +148,7 @@ const AttendancePage = () => { setAttendances(attendance); }, [attendance]); - // useEffect(() => { - // if (selectedProject === 1 || selectedProject === undefined) { - // dispatch(setProjectId(loginUser?.projects[0])); - // } - // }, [selectedProject, loginUser?.projects]); - // Filter attendance data based on the toggle - // const filteredAttendance = showOnlyCheckout - // ? attendances?.filter( - // (att) => att?.checkOutTime !== null && att?.checkInTime !== null - // ) - // : attendances; const filteredAttendance = ShowPending ? attendances?.filter( (att) => att?.checkInTime !== null && att?.checkOutTime === null @@ -269,7 +266,8 @@ const AttendancePage = () => {
{activeTab === "all" && ( <> -
+ {!attLoading && ( +
{ showOnlyCheckout={ShowPending} />
+ )} {!attLoading && filteredAttendance?.length === 0 && (

{" "} diff --git a/src/pages/Activities/DailyTask.jsx b/src/pages/Activities/DailyTask.jsx index fb121a89..a545736f 100644 --- a/src/pages/Activities/DailyTask.jsx +++ b/src/pages/Activities/DailyTask.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import Breadcrumb from "../../components/common/Breadcrumb"; import { useTaskList } from "../../hooks/useTasks"; -import { useProjects } from "../../hooks/useProjects"; +import { useProjectName, useProjects } from "../../hooks/useProjects"; import { setProjectId } from "../../slices/localVariablesSlice"; import { ReportTask } from "../../components/Activities/ReportTask"; import ReportTaskComments from "../../components/Activities/ReportTaskComments"; @@ -18,11 +18,11 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { APPROVE_TASK, ASSIGN_REPORT_TASK } from "../../utils/constants"; const DailyTask = () => { - const [searchParams] = useSearchParams(); - const projectIdFromUrl = searchParams.get("project"); const selectedProject = useSelector( (store) => store.localVariables.projectId ); + const dispatch = useDispatch() + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); const [filters, setFilters] = useState({ @@ -48,7 +48,11 @@ const DailyTask = () => { dateRange?.endDate || null ); - + useEffect(() => { + if(selectedProject == null){ + dispatch(setProjectId(projectNames[0]?.id)); + } + },[]) const [TaskLists, setTaskLists] = useState([]); const [dates, setDates] = useState([]); const popoverRefs = useRef([]); diff --git a/src/pages/Activities/TaskPlannng.jsx b/src/pages/Activities/TaskPlannng.jsx index c2b2f8da..57bd9506 100644 --- a/src/pages/Activities/TaskPlannng.jsx +++ b/src/pages/Activities/TaskPlannng.jsx @@ -1,9 +1,23 @@ -import React from "react"; +import React,{useEffect} from "react"; import Breadcrumb from "../../components/common/Breadcrumb"; import InfraPlanning from "../../components/Activities/InfraPlanning"; +import { useProjectName } from "../../hooks/useProjects"; +import { useDispatch, useSelector } from "react-redux"; +import { setProjectId } from "../../slices/localVariablesSlice"; const TaskPlannng = () => { + const selectedProject = useSelector( + (store) => store.localVariables.projectId + ); + + const dispatch = useDispatch() + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); + useEffect(() => { + if(selectedProject == null){ + dispatch(setProjectId(projectNames[0]?.id)); + } + },[]) return ( <> diff --git a/src/pages/Gallary/ImageGallary.jsx b/src/pages/Gallary/ImageGallary.jsx index eb7bd8ad..6d4bd961 100644 --- a/src/pages/Gallary/ImageGallary.jsx +++ b/src/pages/Gallary/ImageGallary.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef, useCallback } from "react"; import "./ImageGallery.css"; import moment from "moment"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { useModal } from "./ModalContext"; import ImagePop from "./ImagePop"; import Avatar from "../../components/common/Avatar"; @@ -10,11 +10,22 @@ import eventBus from "../../services/eventBus"; import Breadcrumb from "../../components/common/Breadcrumb"; import { formatUTCToLocalTime } from "../../utils/dateUtils"; import useImageGallery from "../../hooks/useImageGallery"; +import { useProjectName } from "../../hooks/useProjects"; +import { setProjectId } from "../../slices/localVariablesSlice"; const SCROLL_THRESHOLD = 5; const ImageGallery = () => { const selectedProjectId = useSelector((store) => store.localVariables.projectId); + + const dispatch = useDispatch() + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); + useEffect(() => { + if(selectedProjectId == null){ + dispatch(setProjectId(projectNames[0]?.id)); + } + },[]) + const { images, allImagesData, diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index 002d77d4..09a820da 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -5,11 +5,19 @@ import { Link, NavLink, useNavigate } from "react-router-dom"; import Avatar from "../../components/common/Avatar"; import Breadcrumb from "../../components/common/Breadcrumb"; import ManageEmp from "../../components/Employee/ManageRole"; -import { useEmployeesAllOrByProjectId, useSuspendEmployee } from "../../hooks/useEmployees"; -import { useProjects } from "../../hooks/useProjects"; +import { + useEmployeesAllOrByProjectId, + useSuspendEmployee, +} from "../../hooks/useEmployees"; +import { useProjectName, useProjects } from "../../hooks/useProjects"; import { useProfile } from "../../hooks/useProfile"; import { hasUserPermission } from "../../utils/authUtils"; -import { ITEMS_PER_PAGE, MANAGE_EMPLOYEES, VIEW_ALL_EMPLOYEES, VIEW_TEAM_MEMBERS } from "../../utils/constants"; +import { + ITEMS_PER_PAGE, + MANAGE_EMPLOYEES, + VIEW_ALL_EMPLOYEES, + VIEW_TEAM_MEMBERS, +} from "../../utils/constants"; import { clearCacheKey } from "../../slices/apiDataManager"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import SuspendEmp from "../../components/Employee/SuspendEmp"; // Keep if you use SuspendEmp @@ -22,16 +30,20 @@ import { import EmployeeRepository from "../../repositories/EmployeeRepository"; import ManageEmployee from "../../components/Employee/ManageEmployee"; import ConfirmModal from "../../components/common/ConfirmModal"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import eventBus from "../../services/eventBus"; import { newlineChars } from "pdf-lib"; import GlobalModel from "../../components/common/GlobalModel"; import usePagination from "../../hooks/usePagination"; +import { setProjectId } from "../../slices/localVariablesSlice"; const EmployeeList = () => { const selectedProjectId = useSelector( (store) => store.localVariables.projectId ); + const { projectNames, loading: projectLoading, fetchData } = useProjectName(); + + const dispatch = useDispatch(); const [showInactive, setShowInactive] = useState(false); const [showAllEmployees, setShowAllEmployees] = useState(false); @@ -44,8 +56,8 @@ const EmployeeList = () => { ); const [employeeList, setEmployeeList] = useState([]); - const [ modelConfig, setModelConfig ] = useState(); - const [EmpForManageRole,setEmpForManageRole] = useState(null) + const [modelConfig, setModelConfig] = useState(); + const [EmpForManageRole, setEmpForManageRole] = useState(null); // const [currentPage, setCurrentPage] = useState(1); // const [itemsPerPage] = useState(ITEMS_PER_PAGE); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); @@ -55,117 +67,70 @@ const EmployeeList = () => { const [selectedEmployeeId, setSelecedEmployeeId] = useState(null); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null); - const [ employeeLodaing, setemployeeLodaing ] = useState( false ); - const ViewTeamMember = useHasUserPermission(VIEW_TEAM_MEMBERS) - const ViewAllEmployee = useHasUserPermission(VIEW_ALL_EMPLOYEES) - const { - mutate: suspendEmployee, - isPending: empLodaing -} = useSuspendEmployee({ - setIsDeleteModalOpen, - setemployeeLodaing -} ); - - + const [employeeLodaing, setemployeeLodaing] = useState(false); + const ViewTeamMember = useHasUserPermission(VIEW_TEAM_MEMBERS); + const ViewAllEmployee = useHasUserPermission(VIEW_ALL_EMPLOYEES); + const { mutate: suspendEmployee, isPending: empLodaing } = useSuspendEmployee( + { + setIsDeleteModalOpen, + setemployeeLodaing, + } + ); + useEffect(() => { + if (selectedProjectId === null) { + dispatch(setProjectId(projectNames[0]?.id)); + } + }, [selectedProjectId]); const navigate = useNavigate(); - const applySearchFilter = (data, text) => { - if (!text) { - return data; - } + if (!text) { + return data; + } - const lowercasedText = text.toLowerCase().trim(); + const lowercasedText = text.toLowerCase().trim(); - return data.filter((item) => { - const firstName = item.firstName || ""; - const middleName = item.middleName || ""; - const lastName = item.lastName || ""; + return data.filter((item) => { + const firstName = item.firstName || ""; + const middleName = item.middleName || ""; + const lastName = item.lastName || ""; - const fullName = `${firstName} ${middleName} ${lastName}` - .toLowerCase() - .trim() - .replace(/\s+/g, " "); + const fullName = `${firstName} ${middleName} ${lastName}` + .toLowerCase() + .trim() + .replace(/\s+/g, " "); - const email = item.email?.toLowerCase() || ""; - const phoneNumber = item.phoneNumber?.toLowerCase() || ""; - const jobRole = item.jobRole?.toLowerCase() || ""; - - return ( - fullName.includes(lowercasedText) || - email.includes(lowercasedText) || - phoneNumber.includes(lowercasedText) || - jobRole.includes(lowercasedText) - ); - }); -}; + const email = item.email?.toLowerCase() || ""; + const phoneNumber = item.phoneNumber?.toLowerCase() || ""; + const jobRole = item.jobRole?.toLowerCase() || ""; + return ( + fullName.includes(lowercasedText) || + email.includes(lowercasedText) || + phoneNumber.includes(lowercasedText) || + jobRole.includes(lowercasedText) + ); + }); + }; const handleSearch = (e) => { const value = e.target.value; setSearchText(value); setCurrentPage(1); }; -useEffect(() => { - const filtered = applySearchFilter(employeeList, searchText); - setFilteredData(filtered); -}, [searchText, employeeList]); - - const displayData = searchText ? filteredData : employeeList; - const { currentPage, totalPages, currentItems, paginate,setCurrentPage } = usePagination( - displayData, - ITEMS_PER_PAGE - ); - const openModal = () => { + const displayData = searchText ? filteredData : employeeList; + const { currentPage, totalPages, currentItems, paginate, setCurrentPage } = + usePagination(displayData, ITEMS_PER_PAGE); + const openModal = () => { setIsCreateModalOpen(true); - }; - -useEffect(() => { - if (!loading && Array.isArray(employees)) { - const sorted = [...employees].sort((a, b) => { - const nameA = `${a.firstName || ""}${a.middleName || ""}${a.lastName || ""}`.toLowerCase(); - const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""}`.toLowerCase(); - return nameA?.localeCompare(nameB); - }); - - setEmployeeList((prevList) => { - const prevJSON = JSON.stringify(prevList); - const nextJSON = JSON.stringify(sorted); - if (prevJSON !== nextJSON) { - return sorted; - } - return prevList; - }); - - setFilteredData((prev) => { - const prevJSON = JSON.stringify(prev); - const nextJSON = JSON.stringify(sorted); - if (prevJSON !== nextJSON) { - return sorted; - } - return prev; - }); - - // set currentPage to 1 only if needed - setCurrentPage((prevPage) => (prevPage !== 1 ? 1 : prevPage)); - } -}, [loading, employees, selectedProjectId, showAllEmployees]); - - - + }; const handleConfigData = (config) => { setModelConfig(config); }; - // useEffect(() => { - // if (modelConfig !== null) { - // openModal(); - // } - // }, [modelConfig, isCreateModalOpen]); - const tableRef = useRef(null); const handleExport = (type) => { if (!currentItems || currentItems.length === 0) return; @@ -190,15 +155,17 @@ useEffect(() => { const handleToggle = (e) => { setShowInactive(e.target.checked); - recallEmployeeData(e.target.checked, showAllEmployees ? null : selectedProjectId); // Use selectedProjectId here + recallEmployeeData( + e.target.checked, + showAllEmployees ? null : selectedProjectId + ); // Use selectedProjectId here }; -const handleAllEmployeesToggle = (e) => { - const isChecked = e.target.checked; - setShowInactive(false); - setShowAllEmployees(isChecked); - -}; + const handleAllEmployeesToggle = (e) => { + const isChecked = e.target.checked; + setShowInactive(false); + setShowAllEmployees(isChecked); + }; const handleEmployeeModel = (id) => { setSelecedEmployeeId(id); @@ -209,6 +176,43 @@ const handleAllEmployeesToggle = (e) => { setSelectedEmpFordelete(employee); setIsDeleteModalOpen(true); }; + useEffect(() => { + const filtered = applySearchFilter(employeeList, searchText); + setFilteredData(filtered); + }, [searchText, employeeList]); + useEffect(() => { + if (!loading && Array.isArray(employees)) { + const sorted = [...employees].sort((a, b) => { + const nameA = `${a.firstName || ""}${a.middleName || ""}${ + a.lastName || "" + }`.toLowerCase(); + const nameB = `${b.firstName || ""}${b.middleName || ""}${ + b.lastName || "" + }`.toLowerCase(); + return nameA?.localeCompare(nameB); + }); + + setEmployeeList((prevList) => { + const prevJSON = JSON.stringify(prevList); + const nextJSON = JSON.stringify(sorted); + if (prevJSON !== nextJSON) { + return sorted; + } + return prevList; + }); + + setFilteredData((prev) => { + const prevJSON = JSON.stringify(prev); + const nextJSON = JSON.stringify(sorted); + if (prevJSON !== nextJSON) { + return sorted; + } + return prev; + }); + + setCurrentPage((prevPage) => (prevPage !== 1 ? 1 : prevPage)); + } + }, [loading, employees, selectedProjectId, showAllEmployees]); useEffect(() => { if (!showAllEmployees) { @@ -218,36 +222,49 @@ const handleAllEmployeesToggle = (e) => { const handler = useCallback( (msg) => { - if(employees.some((item) => item.id == msg.employeeId)){ + if (employees.some((item) => item.id == msg.employeeId)) { setEmployeeList([]); - recallEmployeeData(showInactive, showAllEmployees ? null : selectedProjectId); // Use selectedProjectId here + recallEmployeeData( + showInactive, + showAllEmployees ? null : selectedProjectId + ); // Use selectedProjectId here } - },[employees, showInactive, showAllEmployees, selectedProjectId] // Add all relevant dependencies + }, + [employees, showInactive, showAllEmployees, selectedProjectId] // Add all relevant dependencies ); useEffect(() => { - eventBus.on("employee",handler); - return () => eventBus.off("employee",handler) - },[handler]) - + eventBus.on("employee", handler); + return () => eventBus.off("employee", handler); + }, [handler]); return ( <> {EmpForManageRole && ( - setEmpForManageRole( null )}> - setEmpForManageRole(null)} /> - - )} - - {showModal && ( - setShowModal(false)}> - setShowModal( false )} - IsAllEmployee={showAllEmployees} - /> + setEmpForManageRole(null)} + > + setEmpForManageRole(null)} + /> - )} + )} + + {showModal && ( + setShowModal(false)} + > + setShowModal(false)} + IsAllEmployee={showAllEmployees} + /> + + )} {IsDeleteModalOpen && (

{ ]} > - - {ViewTeamMember ? (
-
-
+ {ViewTeamMember ? ( +
+
+
+
+
+ {/* Switches: All Employees + Inactive */} +
+ {/* All Employees Switch */} + {ViewAllEmployee && ( +
+ + +
+ )} -
-
- {/* Switches: All Employees + Inactive */} -
- {/* All Employees Switch */} - {ViewAllEmployee && ( -
- - + {/* Show Inactive Employees Switch */} + {showAllEmployees && ( +
+ + +
+ )}
- ) } - {/* Show Inactive Employees Switch */} - {showAllEmployees && ( -
- -
- - - - - - - - - - - - - - - - {loading && ( - - - - )} - {/* Conditional messages for no data or no search results */} - {!loading && displayData?.length === 0 && searchText && !showAllEmployees ? ( - - - - ) : null} - {!loading && displayData?.length === 0 && (!searchText || showAllEmployees) ? ( - - + Export + + + + + {/* Add Employee Button */} + {Manage_Employee && ( + + )} + + + +
-
Name
-
-
Email
-
-
Contact
-
-
Role
-
- Joining Date - - Status - - Actions -
-

Loading...

-
- - '{searchText}' employee not found - {" "} -
+
+ + + + + + + + + + - ) : null} - - {/* Render current items */} - {currentItems && !loading && currentItems.map((item) => ( - - - - - - - + + {loading && ( + + - + )} + {/* Conditional messages for no data or no search results */} + {!loading && + displayData?.length === 0 && + searchText && + !showAllEmployees ? ( + + - {Manage_Employee && ( - + + + ) : null} + + {/* Render current items */} + {currentItems && + !loading && + currentItems.map((item) => ( + + - )} - - ))} - -
+
Name
+
+
Email
+
+
Contact
+
+
Role
+
+ Joining Date + + Status + + Actions +
- - - {item.email ? ( - - - {item.email} - - ) : ( - - NA - - )} - - - - {item.phoneNumber} - - - - - {item.jobRole || "Not Assign Yet"} - - - {moment(item.joiningDate)?.format("DD-MMM-YYYY")} +
+

Loading...

- {showInactive ? ( - - Inactive - - ) : ( - - Active - - )} +
+ + '{searchText}' employee not found + {" "} -
- -
-
+ No Data Found +
+
+ + {item.email ? ( + + + {item.email} + + ) : ( + + NA + + )} + + + + + {item.phoneNumber} + + + + + + {item.jobRole || "Not Assign Yet"} + + -
+ + {moment(item.joiningDate)?.format("DD-MMM-YYYY")} + + + {showInactive ? ( + + Inactive + + ) : ( + + Active + + )} + + {Manage_Employee && ( + +
+ +
+ + + {!item.isSystem && ( + <> + + + + )} +
+
+ + )} + + ))} + + - {/* Pagination */} - {!loading && displayData.length > ITEMS_PER_PAGE && ( - + )} +
-
):( + ) : (
-
- -

Access Denied: You don't have permission to perform this action. !

-
+
+ +

+ Access Denied: You don't have permission to perform this action. + ! +

+
)}
@@ -704,4 +760,4 @@ const handleAllEmployeesToggle = (e) => { ); }; -export default EmployeeList; \ No newline at end of file +export default EmployeeList; diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index f34586aa..ff1be7bb 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -1,11 +1,9 @@ -import { useParams } from "react-router-dom"; +import { useSelector } from "react-redux"; // Import useSelector import React, { useState, useEffect, useCallback } from "react"; -import ActivityTimeline from "../../components/Project/ActivityTimeline"; import ProjectOverview from "../../components/Project/ProjectOverview"; import AboutProject from "../../components/Project/AboutProject"; import ProjectNav from "../../components/Project/ProjectNav"; -import ProjectBanner from "../../components/Project/ProjectBanner"; import Teams from "../../components/Project/Teams"; import ProjectInfra from "../../components/Project/ProjectInfra"; import Loader from "../../components/common/Loader"; @@ -16,172 +14,116 @@ import { clearCacheKey, getCachedData, } from "../../slices/apiDataManager"; -import ProjectRepository from "../../repositories/ProjectRepository"; -import { ActivityeRepository } from "../../repositories/MastersRepository"; import "./ProjectDetails.css"; import { - useEmployeesByProjectAllocated, useProjectDetails, } from "../../hooks/useProjects"; -import { useDispatch } from "react-redux"; -import { setProjectId } from "../../slices/localVariablesSlice"; import { ComingSoonPage } from "../Misc/ComingSoonPage"; import Directory from "../Directory/Directory"; import eventBus from "../../services/eventBus"; import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChart"; const ProjectDetails = () => { - let { projectId } = useParams(); - const { - projects_Details, - loading: projectLoading, - error: ProjectError, - refetch - } = useProjectDetails(projectId); - const dispatch = useDispatch(); - const [project, setProject] = useState(null); - // const [projectDetails, setProjectDetails] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - // const fetchData = async () => { - // const project_cache = getCachedData("projectInfo"); - // if (!project_cache || project_cache?.projectId !== projectId) { - // ProjectRepository.getProjectByprojectId(projectId) - // .then((response) => { - // setProjectDetails(response.data); - // setProject(response.data); - // cacheData("projectInfo", { projectId, data: response.data }); - // setLoading(false); - // }) - // .catch((error) => { - // console.error(error); - // setError("Failed to fetch data."); - // setLoading(false); - // }); - // } else { - // setProjectDetails(project_cache.data); - // setProject(project_cache.data); - // setLoading(false); - // } - // }; + + const projectId = useSelector((store) => store.localVariables.projectId); + + const { + projects_Details, + loading: projectLoading, + error: projectError, + refetch, + } = useProjectDetails(projectId); const [activePill, setActivePill] = useState("profile"); - const handlePillClick = (pillKey) => { - setActivePill(pillKey); - }; - const handleDataChange = (data) => { - fetchData(); - }; - - const renderContent = () => { - if (projectLoading) return ; - switch (activePill) { - case "profile": { - return ( -
-
- -
-
- -
-
- ); - } - case "teams": { - return ( -
-
- {/* Teams */} - - {/* Teams */} -
-
- ); - break; - } - case "infra": { - return ( - - ); - break; - } - case "workplan": { - return ( - - ); - break; - } - case "directory": { - return ( -
- -
- ); - } - - default: - return ; - } - }; - - useEffect(() => { - dispatch(setProjectId(projectId)); - - }, [projects_Details, projectId]); const handler = useCallback( (msg) => { - if (msg.keyword === "Update_Project" && projects_Details.id === msg.response.id) { - refetch() + if (msg.keyword === "Update_Project" && projects_Details?.id === msg.response.id) { + refetch(); } }, - [projects_Details, handleDataChange] + [projects_Details, refetch] ); + useEffect(() => { eventBus.on("project", handler); return () => eventBus.off("project", handler); }, [handler]); + const handlePillClick = (pillKey) => { + setActivePill(pillKey); + }; + + const renderContent = () => { + if (projectLoading || !projects_Details) return ; + + switch (activePill) { + case "profile": + return ( + <> +
+
+ + +
+
+ +
+
+ + ); + + case "teams": + return ( +
+
+ +
+
+ ); + + case "infra": + return ( + + ); + + case "workplan": + return ( + + ); + + case "directory": + return ( +
+ +
+ ); + + default: + return ; + } + }; + return ( - <> - {} -
- +
+ -
- {projectLoading &&

Loading....

} - {/* {!projectLoading && project && ( - - )} */} - - -
- -
- - {renderContent()} +
+
- + + {renderContent()} +
); }; -export default ProjectDetails; +export default ProjectDetails; \ No newline at end of file diff --git a/src/pages/project/ProjectList.jsx b/src/pages/project/ProjectList.jsx index 7733a60a..75b8f1f4 100644 --- a/src/pages/project/ProjectList.jsx +++ b/src/pages/project/ProjectList.jsx @@ -5,11 +5,6 @@ import Breadcrumb from "../../components/common/Breadcrumb"; import ProjectRepository from "../../repositories/ProjectRepository"; import { useProjects, useCreateProject } from "../../hooks/useProjects"; import showToast from "../../services/toastService"; -// import { -// getCachedData, -// cacheData, -// clearCacheKey, -// } from "../../slices/apiDataManager"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useProfile } from "../../hooks/useProfile"; import { ITEMS_PER_PAGE, MANAGE_PROJECT } from "../../utils/constants"; @@ -20,11 +15,15 @@ import { defaultCheckBoxAppearanceProvider } from "pdf-lib"; import { useMutation } from "@tanstack/react-query"; import usePagination from "../../hooks/usePagination"; import GlobalModel from "../../components/common/GlobalModel"; +import { useDispatch, useSelector } from "react-redux"; +import { setProjectId } from "../../slices/localVariablesSlice"; const ProjectList = () => { const { profile: loginUser } = useProfile(); const [listView, setListView] = useState(false); const [showModal, setShowModal] = useState(false); + const selectedProject = useSelector((store)=>store.localVariables.projectId) + const dispatch = useDispatch() const { projects, loading, error, refetch } = useProjects(); const [projectList, setProjectList] = useState([]); @@ -75,6 +74,10 @@ const ProjectList = () => { }; useEffect(() => { + if(selectedProject == null){ + dispatch(setProjectId(projects[0]?.id)); + } + if (!loading && projects) { sortingProject(projects); } diff --git a/src/pages/project/ProjectListView.jsx b/src/pages/project/ProjectListView.jsx index 9deead71..a9ffc60d 100644 --- a/src/pages/project/ProjectListView.jsx +++ b/src/pages/project/ProjectListView.jsx @@ -62,7 +62,7 @@ const ProjectListView = ({ projectData, recall }) => { const handleClose = () => setShowModal(false); const handleViewProject = () => { - navigate(`/projects/${projectData.id}`); + navigate(`/projects/details`); }; const handleFormSubmit = (updatedProject) => { @@ -89,7 +89,7 @@ const ProjectListView = ({ projectData, recall }) => { navigate(`/projects/${projectInfo.id}`)} + onClick={() => navigate(`/projects/details`)} > {projectInfo.shortName ? `${projectInfo.name} (${projectInfo.shortName})` @@ -162,7 +162,7 @@ const ProjectListView = ({ projectData, recall }) => { navigate(`/projects/${projectInfo.id}`)} + onClick={() => navigate(`/projects/details`)} > View details @@ -193,4 +193,4 @@ const ProjectListView = ({ projectData, recall }) => { ); }; -export default ProjectListView; +export default ProjectListView; \ No newline at end of file diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 7c364ca9..5ce5b6d4 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -63,7 +63,7 @@ const router = createBrowserRouter( { path: "/", element: }, { path: "/dashboard", element: }, { path: "/projects", element: }, - { path: "/projects/:projectId", element: }, + { path: "/projects/details", element: }, { path: "/project/manage/:projectId", element: }, { path: "/employees", element: }, { path: "/employee/:employeeId", element: }, diff --git a/src/slices/localVariablesSlice.jsx b/src/slices/localVariablesSlice.jsx index ae0f104c..9bd787c6 100644 --- a/src/slices/localVariablesSlice.jsx +++ b/src/slices/localVariablesSlice.jsx @@ -5,7 +5,7 @@ const localVariablesSlice = createSlice({ initialState: { selectedMaster:"Application Role", regularizationCount:0, - projectId: "", + projectId: null, reload:false },