457 lines
17 KiB
JavaScript
457 lines
17 KiB
JavaScript
import getGreetingMessage from "../../utils/greetingHandler";
|
|
import {
|
|
cacheData,
|
|
clearAllCache,
|
|
getCachedData,
|
|
useSelectedProject,
|
|
} from "../../slices/apiDataManager";
|
|
import AuthRepository from "../../repositories/AuthRepository";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import { changeMaster, setProjectId } from "../../slices/localVariablesSlice";
|
|
import useMaster from "../../hooks/masterHook/useMaster";
|
|
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 { 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 { useAuthModal, useLogout } from "../../hooks/useAuth";
|
|
|
|
const Header = () => {
|
|
const { profile } = useProfile();
|
|
const location = useLocation();
|
|
const dispatch = useDispatch();
|
|
const { data, loading } = useMaster();
|
|
const navigate = useNavigate();
|
|
const {onOpen} = useAuthModal()
|
|
const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT);
|
|
const { mutate : logout,isPending:logouting} = useLogout()
|
|
|
|
const isDashboardPath =
|
|
/^\/dashboard$/.test(location.pathname) || /^\/$/.test(location.pathname);
|
|
const isProjectPath = /^\/projects$/.test(location.pathname);
|
|
|
|
const showProjectDropdown = (pathname) => {
|
|
const isDirectoryPath = /^\/directory$/.test(pathname);
|
|
|
|
// const isProfilePage = /^\/employee$/.test(location.pathname);
|
|
const isProfilePage =
|
|
/^\/employee\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(
|
|
pathname
|
|
);
|
|
const isExpensePage = /^\/expenses$/.test(pathname);
|
|
|
|
return !(isDirectoryPath || isProfilePage || isExpensePage);
|
|
};
|
|
const allowedProjectStatusIds = [
|
|
"603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
|
"cdad86aa-8a56-4ff4-b633-9c629057dfef",
|
|
"b74da4c2-d07e-46f2-9919-e75e49b12731",
|
|
];
|
|
|
|
const getRole = (roles, joRoleId) => {
|
|
if (!Array.isArray(roles)) return "User";
|
|
let role = roles.find((role) => role.id === joRoleId);
|
|
return role ? role.name : "User";
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleProfilePage = () => {
|
|
navigate(`/employee/${profile?.employeeInfo?.id}`);
|
|
};
|
|
|
|
const { projectNames, loading: projectLoading, fetchData } = useProjectName();
|
|
|
|
const selectedProject = useSelectedProject();
|
|
|
|
const projectsForDropdown = isDashboardPath
|
|
? projectNames
|
|
: projectNames?.filter((project) =>
|
|
allowedProjectStatusIds.includes(project.projectStatusId)
|
|
);
|
|
|
|
let currentProjectDisplayName;
|
|
if (projectLoading) {
|
|
currentProjectDisplayName = "Loading...";
|
|
} else if (!projectNames || projectNames.length === 0) {
|
|
currentProjectDisplayName = "No Projects Assigned";
|
|
} else if (projectNames.length === 1) {
|
|
currentProjectDisplayName = projectNames[0].name;
|
|
} else {
|
|
if (selectedProject === null) {
|
|
currentProjectDisplayName = "All Projects";
|
|
} else {
|
|
const selectedProjectObj = projectNames.find(
|
|
(p) => p?.id === selectedProject
|
|
);
|
|
currentProjectDisplayName = selectedProjectObj
|
|
? selectedProjectObj.name
|
|
: "All Projects";
|
|
}
|
|
}
|
|
|
|
const { openChangePassword } = useChangePassword();
|
|
|
|
useEffect(() => {
|
|
if (
|
|
projectNames &&
|
|
projectNames.length > 0 &&
|
|
selectedProject === undefined &&
|
|
!getCachedData("hasReceived")
|
|
) {
|
|
if (projectNames.length === 1) {
|
|
dispatch(setProjectId(projectNames[0]?.id || null));
|
|
} else {
|
|
if (isDashboardPath) {
|
|
dispatch(setProjectId(null));
|
|
} else {
|
|
const firstAllowedProject = projectNames.find((project) =>
|
|
allowedProjectStatusIds.includes(project.projectStatusId)
|
|
);
|
|
dispatch(setProjectId(firstAllowedProject?.id || null));
|
|
}
|
|
}
|
|
}
|
|
}, [projectNames, selectedProject, dispatch, isDashboardPath]);
|
|
|
|
const handler = useCallback(
|
|
async (data) => {
|
|
if (!HasManageProjectPermission) {
|
|
await fetchData();
|
|
const projectExist = data.projectIds.some(
|
|
(item) => item === selectedProject
|
|
);
|
|
if (projectExist) {
|
|
cacheData("hasReceived", false);
|
|
}
|
|
}
|
|
},
|
|
[fetchData, selectedProject, HasManageProjectPermission]
|
|
);
|
|
|
|
const newProjectHandler = useCallback(
|
|
async (msg) => {
|
|
if (HasManageProjectPermission && msg.keyword === "Create_Project") {
|
|
await fetchData();
|
|
} else if (projectNames?.some((item) => item.id === msg.response.id)) {
|
|
await fetchData();
|
|
}
|
|
cacheData("hasReceived", false);
|
|
},
|
|
[HasManageProjectPermission, projectNames, fetchData]
|
|
);
|
|
|
|
useEffect(() => {
|
|
dispatch(changeMaster("Job Role"));
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
eventBus.on("assign_project_one", handler);
|
|
eventBus.on("project", newProjectHandler);
|
|
|
|
return () => {
|
|
eventBus.off("assign_project_one", handler);
|
|
eventBus.off("project", newProjectHandler);
|
|
};
|
|
}, [handler, newProjectHandler]);
|
|
|
|
const handleProjectChange = (project) => {
|
|
dispatch(setProjectId(project));
|
|
|
|
if (isProjectPath && project !== null) {
|
|
navigate("/projects/details");
|
|
}
|
|
};
|
|
|
|
const shouldShowDropdown = projectNames && projectNames.length > 1;
|
|
|
|
return (
|
|
<nav
|
|
className="layout-navbar container-fluid mb-3 navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
|
|
id="layout-navbar"
|
|
>
|
|
<div className="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
|
|
<a
|
|
aria-label="toggle for sidebar"
|
|
className="nav-item nav-link px-0 me-xl-4"
|
|
>
|
|
<i className="bx bx-menu bx-sm"></i>
|
|
</a>
|
|
</div>
|
|
<div
|
|
className="navbar-nav-right d-flex align-items-center justify-content-between"
|
|
id="navbar-collapse"
|
|
>
|
|
{showProjectDropdown(location.pathname) && (
|
|
<div className="align-items-center">
|
|
<i className="rounded-circle bx bx-building-house bx-sm-lg bx-md me-2"></i>
|
|
<div className="btn-group">
|
|
{shouldShowDropdown ? (
|
|
<button
|
|
className={`btn btn-sm-sm btn-xl dropdown-toggle px-1`}
|
|
type="button"
|
|
data-bs-toggle="dropdown"
|
|
aria-expanded="false"
|
|
>
|
|
{currentProjectDisplayName}
|
|
</button>
|
|
) : (
|
|
<span className="btn btn-sm-sm btn-xl px-1">
|
|
{currentProjectDisplayName}
|
|
</span>
|
|
)}
|
|
|
|
{shouldShowDropdown &&
|
|
projectsForDropdown &&
|
|
projectsForDropdown.length > 0 && (
|
|
<ul
|
|
className="dropdown-menu"
|
|
style={{ overflow: "auto", maxHeight: "300px" }}
|
|
>
|
|
{isDashboardPath && (
|
|
<li>
|
|
<button
|
|
className="dropdown-item"
|
|
onClick={() => handleProjectChange(null)}
|
|
>
|
|
All Projects
|
|
</button>
|
|
</li>
|
|
)}
|
|
{[...projectsForDropdown]
|
|
.sort((a, b) => a?.name?.localeCompare(b.name))
|
|
.map((project) => (
|
|
<li key={project?.id}>
|
|
<button
|
|
className="dropdown-item"
|
|
onClick={() => handleProjectChange(project?.id)}
|
|
>
|
|
{project?.name}
|
|
{project?.shortName && (
|
|
<span className="text-primary fw-semibold ms-1">
|
|
({project?.shortName})
|
|
</span>
|
|
)}
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<ul className="navbar-nav flex-row align-items-center ms-md-auto">
|
|
<li className="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
|
|
<a
|
|
className="nav-link dropdown-toggle hide-arrow"
|
|
data-bs-toggle="dropdown"
|
|
data-bs-auto-close="true"
|
|
aria-expanded="false"
|
|
>
|
|
<i className="icon-base bx bx-grid-alt icon-md"></i>
|
|
</a>
|
|
<div className="dropdown-menu dropdown-menu-end p-0">
|
|
<div className="dropdown-menu-header border-bottom">
|
|
<div className="dropdown-header d-flex align-items-center py-3">
|
|
<h6 className="mb-0 me-auto">Shortcuts</h6>
|
|
<a
|
|
className="dropdown-shortcuts-add py-2 cusror-pointer"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
aria-label="Add shortcuts"
|
|
data-bs-original-title="Add shortcuts"
|
|
>
|
|
<i className="icon-base bx bx-plus-circle text-heading"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div className="dropdown-shortcuts-list scrollable-container ps">
|
|
<div className="row row-bordered overflow-visible g-0">
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/dashboard`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bx-home icon-26px text-heading"></i>
|
|
</span>
|
|
Dashboard
|
|
</a>
|
|
<small>User Dashboard</small>
|
|
</div>
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/projects`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bx-building-house icon-26px text-heading"></i>
|
|
</span>
|
|
Projects
|
|
</a>
|
|
<small>Projects List</small>
|
|
</div>
|
|
</div>
|
|
<div className="row row-bordered overflow-visible g-0">
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/employees`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i>
|
|
</span>
|
|
Employees
|
|
</a>
|
|
<small>Manage Employees</small>
|
|
</div>
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/activities/attendance`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bx-user-check icon-26px text-heading"></i>
|
|
</span>
|
|
Attendance
|
|
</a>
|
|
<small>Manage Attendance</small>
|
|
</div>
|
|
</div>
|
|
<div className="row row-bordered overflow-visible g-0">
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/activities/task`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i>
|
|
</span>
|
|
Allocate Work
|
|
</a>
|
|
<small>Work Allocations</small>
|
|
</div>
|
|
<div className="dropdown-shortcuts-item col">
|
|
<a
|
|
onClick={() => navigate(`/activities/records`)}
|
|
className="text-heading text-truncate cursor-pointer"
|
|
>
|
|
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
<i className="icon-base bx bx-list-ul icon-26px text-heading"></i>
|
|
</span>
|
|
Daily Work Log
|
|
</a>
|
|
<small>Daily Work Allocations</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li className="nav-item navbar-dropdown dropdown-user dropdown">
|
|
<a
|
|
aria-label="dropdown profile avatar"
|
|
className="nav-link dropdown-toggle hide-arrow"
|
|
href="#"
|
|
data-bs-toggle="dropdown"
|
|
>
|
|
<div className="avatar avatar-online">
|
|
<Avatar
|
|
firstName={`${profile?.employeeInfo?.firstName}`}
|
|
lastName={`${profile?.employeeInfo?.lastName}`}
|
|
/>
|
|
</div>
|
|
</a>
|
|
<ul className="dropdown-menu dropdown-menu-end">
|
|
<li onClick={handleProfilePage}>
|
|
<a aria-label="go to profile" className="dropdown-item">
|
|
<div className="d-flex">
|
|
<div className="flex-shrink-0 me-3">
|
|
<div className="avatar avatar-online">
|
|
<Avatar
|
|
firstName={`${profile?.employeeInfo?.firstName}`}
|
|
lastName={`${profile?.employeeInfo?.lastName}`}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex-grow-1">
|
|
<span className="fw-medium d-block">
|
|
{profile?.employeeInfo?.firstName}
|
|
</span>
|
|
<small className="text-muted">
|
|
{getRole(data, profile?.employeeInfo?.joRoleId)}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<div className="dropdown-divider"></div>
|
|
</li>
|
|
<li onClick={()=>onOpen()}>
|
|
{" "}
|
|
<a
|
|
className="dropdown-item cusor-pointer"
|
|
>
|
|
<i className="bx bx-transfer-alt me-2"></i>
|
|
<span className="align-middle">Switch Workspace</span>
|
|
</a>
|
|
</li>
|
|
<li onClick={handleProfilePage}>
|
|
<a
|
|
aria-label="go to profile"
|
|
className="dropdown-item cusor-pointer"
|
|
>
|
|
<i className="bx bx-user me-2"></i>
|
|
<span className="align-middle">My Profile</span>
|
|
</a>
|
|
</li>
|
|
<li onClick={handleProfilePage}>
|
|
<a
|
|
aria-label="go to setting "
|
|
className="dropdown-item cusor-pointer"
|
|
>
|
|
<i className="bx bx-cog me-2"></i>
|
|
<span className="align-middle">Settings</span>
|
|
</a>
|
|
</li>
|
|
<li onClick={openChangePassword}>
|
|
{" "}
|
|
<a
|
|
aria-label="go to profile"
|
|
className="dropdown-item cusor-pointer"
|
|
>
|
|
<i className="bx bx-lock-alt me-2"></i>
|
|
<span className="align-middle">Change Password</span>
|
|
</a>
|
|
</li>
|
|
|
|
|
|
<li>
|
|
<div className="dropdown-divider"></div>
|
|
</li>
|
|
<li>
|
|
<a
|
|
aria-label="click to log out"
|
|
className="dropdown-item cusor-pointer"
|
|
onClick={()=>logout()}
|
|
>
|
|
{logouting ? "Please Wait":<> <i className="bx bx-log-out me-2"></i>
|
|
<span className="align-middle">SignOut</span></>}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
);
|
|
};
|
|
export default Header; |