All checks were successful
Build & Deploy Costco Grocery List / build (push) Successful in 1m10s
Build & Deploy Costco Grocery List / verify-images (push) Successful in 3s
Build & Deploy Costco Grocery List / deploy (push) Successful in 11s
Build & Deploy Costco Grocery List / notify (push) Successful in 1s
118 lines
3.8 KiB
JavaScript
118 lines
3.8 KiB
JavaScript
import "../../styles/components/Navbar.css";
|
|
|
|
import { useContext, useState } from "react";
|
|
import { Link, useNavigate } from "react-router-dom";
|
|
import { logoutRequest } from "../../api/auth";
|
|
import { AuthContext } from "../../context/AuthContext";
|
|
import useActionToast from "../../hooks/useActionToast";
|
|
import getApiErrorMessage from "../../lib/getApiErrorMessage";
|
|
import HouseholdSwitcher from "../household/HouseholdSwitcher";
|
|
|
|
export default function Navbar() {
|
|
const navigate = useNavigate();
|
|
const { role, logout, username } = useContext(AuthContext);
|
|
const toast = useActionToast();
|
|
const [showUserMenu, setShowUserMenu] = useState(false);
|
|
|
|
const closeMenus = () => {
|
|
setShowUserMenu(false);
|
|
};
|
|
|
|
const handleLogout = async () => {
|
|
let loggedOutRemotely = true;
|
|
let fallbackReason = "";
|
|
try {
|
|
await logoutRequest();
|
|
} catch (error) {
|
|
// Clear local auth state even if server logout fails.
|
|
loggedOutRemotely = false;
|
|
fallbackReason = getApiErrorMessage(error, "Unable to end server session");
|
|
} finally {
|
|
logout();
|
|
closeMenus();
|
|
if (loggedOutRemotely) {
|
|
toast.success("Logged out", "Logged out successfully");
|
|
} else {
|
|
toast.info("Logged out locally", `Server logout failed: ${fallbackReason}`);
|
|
}
|
|
navigate("/login");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<nav className="navbar">
|
|
<div className="navbar-section navbar-spacer" aria-hidden="true"></div>
|
|
|
|
{/* Center: Home + Household + Manage */}
|
|
<div className="navbar-section navbar-center">
|
|
<div className="navbar-center-nav">
|
|
<Link
|
|
to="/"
|
|
className="navbar-icon-link navbar-icon-left"
|
|
title="Home"
|
|
aria-label="Home"
|
|
onClick={closeMenus}
|
|
>
|
|
<span aria-hidden="true">⌂</span>
|
|
</Link>
|
|
|
|
<div className="navbar-household-wrap">
|
|
<HouseholdSwitcher />
|
|
</div>
|
|
|
|
<Link
|
|
to="/manage"
|
|
className="navbar-icon-link navbar-icon-right"
|
|
title="Manage"
|
|
aria-label="Manage"
|
|
onClick={closeMenus}
|
|
>
|
|
<span aria-hidden="true">⚙</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right: User Menu */}
|
|
<div className="navbar-section navbar-right">
|
|
<button
|
|
className="navbar-user-btn"
|
|
onClick={() => {
|
|
setShowUserMenu(!showUserMenu);
|
|
}}
|
|
aria-label="User menu"
|
|
>
|
|
<span className="navbar-user-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" focusable="false" aria-hidden="true">
|
|
<path d="M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5Zm0 2c-4.14 0-7.5 2.69-7.5 6v1h15v-1c0-3.31-3.36-6-7.5-6Z" />
|
|
</svg>
|
|
</span>
|
|
<span className="navbar-user-name">{username}</span>
|
|
</button>
|
|
|
|
{showUserMenu && (
|
|
<>
|
|
<div className="menu-overlay" onClick={closeMenus}></div>
|
|
<div className="navbar-dropdown user-dropdown">
|
|
<div className="user-dropdown-info">
|
|
<span className="user-dropdown-username">{username}</span>
|
|
<span className="user-dropdown-role">{role}</span>
|
|
</div>
|
|
<Link to="/settings" className="user-dropdown-link" onClick={closeMenus}>
|
|
User Settings
|
|
</Link>
|
|
{role === "system_admin" && (
|
|
<Link to="/admin" className="user-dropdown-link" onClick={closeMenus}>
|
|
Admin Settings
|
|
</Link>
|
|
)}
|
|
<button className="user-dropdown-logout" onClick={handleLogout}>
|
|
Logout
|
|
</button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|