- Import TrainerContextsPage in App.jsx - Add route /trainer-contexts - Add 'Meine Bereiche' to main navigation (appNav.js) - Icon: Target (Zielscheibe) für Trainer-Bereiche - Visible in both desktop sidebar and mobile bottom nav version: 0.5.0 module: TrainerContextsPage 1.0.0 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
219 lines
5.0 KiB
JavaScript
219 lines
5.0 KiB
JavaScript
import React from 'react'
|
|
import { BrowserRouter as Router, Routes, Route, Navigate, NavLink, useLocation } from 'react-router-dom'
|
|
import { AuthProvider, useAuth } from './context/AuthContext'
|
|
import DesktopSidebar from './components/DesktopSidebar'
|
|
import { getMainNavItems } from './config/appNav'
|
|
import LoginPage from './pages/LoginPage'
|
|
import Dashboard from './pages/Dashboard'
|
|
import ProfilePage from './pages/ProfilePage'
|
|
import ExercisesPage from './pages/ExercisesPage'
|
|
import ClubsPage from './pages/ClubsPage'
|
|
import SkillsPage from './pages/SkillsPage'
|
|
import TrainingPlanningPage from './pages/TrainingPlanningPage'
|
|
import AdminCatalogsPage from './pages/AdminCatalogsPage'
|
|
import TrainerContextsPage from './pages/TrainerContextsPage'
|
|
import './app.css'
|
|
|
|
// Bottom Navigation (Mobile)
|
|
function Nav({ isAdmin }) {
|
|
const items = getMainNavItems(isAdmin)
|
|
const loc = useLocation()
|
|
|
|
const navItemActive = (pathname, item, routerIsActive) => {
|
|
if (item.to.startsWith('/admin')) return pathname.startsWith('/admin')
|
|
return routerIsActive
|
|
}
|
|
|
|
return (
|
|
<nav className="bottom-nav">
|
|
{items.map((item) => (
|
|
<NavLink
|
|
key={item.to}
|
|
to={item.to}
|
|
end={!!item.end}
|
|
className={({ isActive }) =>
|
|
'nav-item' +
|
|
(navItemActive(loc.pathname, item, isActive) ? ' active' : '')
|
|
}
|
|
>
|
|
<item.Icon size={20} strokeWidth={2} />
|
|
<span>{item.shortLabel || item.label}</span>
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
)
|
|
}
|
|
|
|
// Protected Route Component
|
|
function ProtectedRoute({ children }) {
|
|
const { isAuthenticated, loading, user, logout } = useAuth()
|
|
|
|
const handleLogout = () => {
|
|
if (confirm('Wirklich abmelden?')) {
|
|
logout()
|
|
window.location.href = '/'
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div style={{
|
|
minHeight: '100vh',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'var(--bg)'
|
|
}}>
|
|
<div className="spinner"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
return <Navigate to="/login" replace />
|
|
}
|
|
|
|
const isAdmin = user?.role === 'admin' || user?.role === 'superadmin'
|
|
|
|
return (
|
|
<>
|
|
<DesktopSidebar
|
|
isAdmin={isAdmin}
|
|
user={user}
|
|
onLogout={handleLogout}
|
|
/>
|
|
<div className="app-shell">
|
|
<div className="app-shell__column">
|
|
<div className="app-header app-header--mobile">
|
|
<div className="app-logo">🥋 Shinkan</div>
|
|
</div>
|
|
<div className="app-main">{children}</div>
|
|
<Nav isAdmin={isAdmin} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
// Public Route Component (redirect to dashboard if already logged in)
|
|
function PublicRoute({ children }) {
|
|
const { isAuthenticated, loading } = useAuth()
|
|
|
|
if (loading) {
|
|
return (
|
|
<div style={{
|
|
minHeight: '100vh',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'var(--bg)'
|
|
}}>
|
|
<div className="spinner"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return !isAuthenticated ? children : <Navigate to="/" replace />
|
|
}
|
|
|
|
function AppRoutes() {
|
|
return (
|
|
<Routes>
|
|
{/* Public Routes */}
|
|
<Route
|
|
path="/login"
|
|
element={
|
|
<PublicRoute>
|
|
<LoginPage />
|
|
</PublicRoute>
|
|
}
|
|
/>
|
|
|
|
{/* Protected Routes */}
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<ProtectedRoute>
|
|
<Dashboard />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/profile"
|
|
element={
|
|
<ProtectedRoute>
|
|
<ProfilePage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/exercises"
|
|
element={
|
|
<ProtectedRoute>
|
|
<ExercisesPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/clubs"
|
|
element={
|
|
<ProtectedRoute>
|
|
<ClubsPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/skills"
|
|
element={
|
|
<ProtectedRoute>
|
|
<SkillsPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/planning"
|
|
element={
|
|
<ProtectedRoute>
|
|
<TrainingPlanningPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/admin"
|
|
element={<Navigate to="/admin/catalogs" replace />}
|
|
/>
|
|
<Route
|
|
path="/admin/catalogs"
|
|
element={
|
|
<ProtectedRoute>
|
|
<AdminCatalogsPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/trainer-contexts"
|
|
element={
|
|
<ProtectedRoute>
|
|
<TrainerContextsPage />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
|
|
{/* Catch all - redirect to dashboard or login */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
)
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<AuthProvider>
|
|
<Router>
|
|
<AppRoutes />
|
|
</Router>
|
|
</AuthProvider>
|
|
)
|
|
}
|
|
|
|
export default App
|