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
- 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.
144 lines
4.1 KiB
JavaScript
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
|