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">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;