Replace the mobile profile card with a compact page header, account menu, and contextual dashboard toolbar while preserving desktop behavior.
110 lines
3.4 KiB
JavaScript
110 lines
3.4 KiB
JavaScript
import { useEffect, useMemo, useState } from 'react';
|
|
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
|
import './NavigationTabs.css';
|
|
|
|
const NavigationTabs = ({ isAdmin, onProtectedNavigate, profileName, onLogout }) => {
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const [mobileOpen, setMobileOpen] = useState(false);
|
|
|
|
const tabs = useMemo(() => {
|
|
const items = [
|
|
{ to: '/', label: 'Slots buchen' },
|
|
{ to: '/store-watch', label: 'Betriebs-Monitoring' },
|
|
{ to: '/journal', label: 'Abhol-Journal' }
|
|
];
|
|
if (isAdmin) {
|
|
items.push({ to: '/debug', label: 'Debug' });
|
|
items.push({ to: '/admin', label: 'Admin' });
|
|
}
|
|
return items;
|
|
}, [isAdmin]);
|
|
|
|
const activeTab = tabs.find((tab) => tab.to === location.pathname) || tabs[0];
|
|
|
|
const handleClick = (event, to) => {
|
|
event.preventDefault();
|
|
if (to === location.pathname) {
|
|
return;
|
|
}
|
|
const label = tabs.find((tab) => tab.to === to)?.label || '';
|
|
const proceed = () => navigate(to);
|
|
if (onProtectedNavigate) {
|
|
onProtectedNavigate(`zur Seite "${label}" zu wechseln`, proceed);
|
|
return;
|
|
}
|
|
proceed();
|
|
};
|
|
|
|
useEffect(() => {
|
|
setMobileOpen(false);
|
|
}, [location.pathname]);
|
|
|
|
const renderLink = (tab, className) => {
|
|
const isActive = location.pathname === tab.to;
|
|
return (
|
|
<Link
|
|
key={tab.to}
|
|
to={tab.to}
|
|
onClick={(event) => handleClick(event, tab.to)}
|
|
className={`${className}${isActive ? ' is-active' : ''}`}
|
|
aria-current={isActive ? 'page' : undefined}
|
|
>
|
|
{tab.label}
|
|
</Link>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<nav className="app-navigation" aria-label="Navigation">
|
|
<div className="app-navigation__mobile-header">
|
|
<span className="app-navigation__current-page">{activeTab.label}</span>
|
|
<button
|
|
type="button"
|
|
className="app-navigation__menu-toggle"
|
|
aria-label={mobileOpen ? 'Navigation schließen' : 'Navigation öffnen'}
|
|
aria-expanded={mobileOpen}
|
|
aria-controls="mobile-navigation"
|
|
onClick={() => setMobileOpen((open) => !open)}
|
|
>
|
|
<svg viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
{mobileOpen ? (
|
|
<>
|
|
<line x1="18" y1="6" x2="6" y2="18" />
|
|
<line x1="6" y1="6" x2="18" y2="18" />
|
|
</>
|
|
) : (
|
|
<>
|
|
<line x1="3" y1="6" x2="21" y2="6" />
|
|
<line x1="3" y1="12" x2="21" y2="12" />
|
|
<line x1="3" y1="18" x2="21" y2="18" />
|
|
</>
|
|
)}
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
{mobileOpen && (
|
|
<div id="mobile-navigation" className="app-navigation__mobile-menu">
|
|
<div className="app-navigation__mobile-links">
|
|
{tabs.map((tab) => renderLink(tab, 'app-navigation__mobile-link'))}
|
|
</div>
|
|
<div className="app-navigation__account">
|
|
<div>
|
|
<span>Angemeldet</span>
|
|
<strong>{profileName || 'Profil'}</strong>
|
|
</div>
|
|
<button type="button" onClick={onLogout}>Logout</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="app-navigation__desktop">
|
|
{tabs.map((tab) => renderLink(tab, 'app-navigation__desktop-link'))}
|
|
</div>
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
export default NavigationTabs;
|