shinkan-jinkendo/frontend/src/App.jsx
Lars 377f365473
Some checks failed
Deploy Development / deploy (push) Successful in 34s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 5s
Test Suite / playwright-tests (push) Failing after 1m54s
feat: Add TrainerContextsPage to navigation
- 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>
2026-04-23 14:26:10 +02:00

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