shinkan-jinkendo/frontend/src/components/Navigation.jsx
Lars 24c70c5ea0
All checks were successful
Deploy Development / deploy (push) Successful in 40s
Test Suite / pytest-backend (push) Successful in 25s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 7s
Test Suite / playwright-tests (push) Successful in 23s
feat(memberships, profiles, clubs): enhance active club membership handling
- Introduced a new utility function to filter and return only active club memberships, improving role management and access control.
- Updated various components and pages to utilize the new active club memberships function, ensuring only relevant memberships are considered.
- Enhanced user interface elements to reflect the status of club memberships, including visual indicators for inactive memberships.
- Improved backend logic for resolving tenant contexts and managing club roles based on active memberships.
2026-05-09 10:42:56 +02:00

144 lines
4.1 KiB
JavaScript

import { Link, useLocation, useNavigate } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { getResolvedActiveClubIdForUi, activeClubMemberships } from '../utils/activeClub'
function Navigation() {
const location = useLocation()
const navigate = useNavigate()
const { user, logout, setActiveClub } = useAuth()
const clubs = activeClubMemberships(user?.clubs)
const selectClubId = getResolvedActiveClubIdForUi(user)
const handleLogout = async () => {
await logout()
navigate('/login')
}
const isActive = (path) => location.pathname === path
return (
<nav style={{
background: 'var(--surface)',
borderBottom: '1px solid var(--border)',
padding: '0 1rem',
position: 'sticky',
top: 0,
zIndex: 1000
}}>
<div style={{
width: '100%',
maxWidth: 'none',
margin: '0',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
height: '60px'
}}>
{/* Logo/Title */}
<Link to="/" style={{
fontSize: '1.25rem',
fontWeight: 600,
color: 'var(--text1)',
textDecoration: 'none'
}}>
🥋 Shinkan
</Link>
{/* Main Navigation */}
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Link
to="/"
style={{
color: isActive('/') ? 'var(--accent)' : 'var(--text2)',
textDecoration: 'none',
fontWeight: isActive('/') ? 600 : 400
}}
>
Dashboard
</Link>
<Link
to="/exercises"
style={{
color: isActive('/exercises') ? 'var(--accent)' : 'var(--text2)',
textDecoration: 'none',
fontWeight: isActive('/exercises') ? 600 : 400
}}
>
Übungen
</Link>
<Link
to="/clubs"
style={{
color: isActive('/clubs') ? 'var(--accent)' : 'var(--text2)',
textDecoration: 'none',
fontWeight: isActive('/clubs') ? 600 : 400
}}
>
Vereine
</Link>
<Link
to="/profile"
style={{
color: isActive('/profile') ? 'var(--accent)' : 'var(--text2)',
textDecoration: 'none',
fontWeight: isActive('/profile') ? 600 : 400
}}
>
Profil
</Link>
{(clubs?.length ?? 0) > 1 && (
<label style={{ display: 'flex', alignItems: 'center', gap: '0.35rem', fontSize: '0.8125rem', color: 'var(--text2)' }}>
<span>Verein</span>
<select
className="form-input"
style={{ padding: '0.35rem 0.5rem', minWidth: '9rem', fontSize: '0.8125rem' }}
value={selectClubId ?? ''}
onChange={(e) => {
const v = e.target.value
if (v) setActiveClub(Number(v))
}}
>
{clubs.map((c) => (
<option key={c.id} value={c.id}>{c.name}</option>
))}
</select>
</label>
)}
{/* User Menu */}
<div style={{
borderLeft: '1px solid var(--border)',
paddingLeft: '1rem',
marginLeft: '0.5rem',
display: 'flex',
alignItems: 'center',
gap: '0.75rem'
}}>
<span style={{ color: 'var(--text2)', fontSize: '0.875rem' }}>
{user?.name || user?.email}
</span>
<button
onClick={handleLogout}
style={{
padding: '0.5rem 1rem',
background: 'transparent',
border: '1px solid var(--border)',
borderRadius: '6px',
color: 'var(--text2)',
cursor: 'pointer',
fontSize: '0.875rem'
}}
>
Abmelden
</button>
</div>
</div>
</div>
</nav>
)
}
export default Navigation