All checks were successful
Deploy Development / deploy (push) Successful in 34s
Test Suite / pytest-backend (push) Successful in 6s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Successful in 26s
Test Suite / pytest-backend (pull_request) Successful in 5s
Test Suite / lint-backend (pull_request) Successful in 1s
Test Suite / build-frontend (pull_request) Successful in 6s
Test Suite / playwright-tests (pull_request) Successful in 23s
- Introduced a new SettingsSystemInfoPage to display technical system information. - Updated AccountSettingsPage to include a link to the new system information page, enhancing user access to app version, build, environment, and database schema details. - Removed unused version state from Dashboard component to streamline data handling.
200 lines
6.3 KiB
JavaScript
200 lines
6.3 KiB
JavaScript
import React from 'react'
|
|
import {
|
|
BrowserRouter as Router,
|
|
Routes,
|
|
Route,
|
|
Navigate,
|
|
NavLink,
|
|
useLocation,
|
|
Outlet,
|
|
} 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 VerifyPage from './pages/VerifyPage'
|
|
import Dashboard from './pages/Dashboard'
|
|
import AccountSettingsPage from './pages/AccountSettingsPage'
|
|
import SettingsSystemInfoPage from './pages/SettingsSystemInfoPage'
|
|
import ExercisesListPage from './pages/ExercisesListPage'
|
|
import ExerciseDetailPage from './pages/ExerciseDetailPage'
|
|
import ExerciseFormPage from './pages/ExerciseFormPage'
|
|
import ClubsPage from './pages/ClubsPage'
|
|
import SkillsPage from './pages/SkillsPage'
|
|
import TrainingPlanningPage from './pages/TrainingPlanningPage'
|
|
import TrainingFrameworkProgramsListPage from './pages/TrainingFrameworkProgramsListPage'
|
|
import TrainingFrameworkProgramEditPage from './pages/TrainingFrameworkProgramEditPage'
|
|
import TrainingUnitRunPage from './pages/TrainingUnitRunPage'
|
|
import TrainingCoachPage from './pages/TrainingCoachPage'
|
|
import AdminCatalogsPage from './pages/AdminCatalogsPage'
|
|
import AdminHierarchyPage from './pages/AdminHierarchyPage'
|
|
import AdminMaturityModelsPage from './pages/AdminMaturityModelsPage'
|
|
import TrainerContextsPage from './pages/TrainerContextsPage'
|
|
import MediaWikiImportPage from './pages/MediaWikiImportPage'
|
|
import AdminUsersPage from './pages/AdminUsersPage'
|
|
import ActiveClubSwitcher from './components/ActiveClubSwitcher'
|
|
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={26} strokeWidth={2} />
|
|
<span>{item.shortLabel || item.label}</span>
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
)
|
|
}
|
|
|
|
function ProtectedLayout() {
|
|
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 app-header--mobile-stack">
|
|
<div className="app-header-mobile__top">
|
|
<div className="app-logo">🥋 Shinkan</div>
|
|
</div>
|
|
<ActiveClubSwitcher variant="mobile" />
|
|
</div>
|
|
<div className="app-main">
|
|
<Outlet />
|
|
</div>
|
|
<Nav isAdmin={isAdmin} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
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>
|
|
<Route path="/verify" element={<VerifyPage />} />
|
|
|
|
<Route
|
|
path="/login"
|
|
element={
|
|
<PublicRoute>
|
|
<LoginPage />
|
|
</PublicRoute>
|
|
}
|
|
/>
|
|
|
|
<Route element={<ProtectedLayout />}>
|
|
<Route index element={<Dashboard />} />
|
|
<Route path="profile" element={<Navigate to="/settings" replace />} />
|
|
<Route path="settings" element={<AccountSettingsPage />} />
|
|
<Route path="settings/system" element={<SettingsSystemInfoPage />} />
|
|
<Route path="exercises">
|
|
<Route index element={<ExercisesListPage />} />
|
|
<Route path="new" element={<ExerciseFormPage />} />
|
|
<Route path=":id/edit" element={<ExerciseFormPage />} />
|
|
<Route path=":id" element={<ExerciseDetailPage />} />
|
|
</Route>
|
|
<Route path="clubs" element={<ClubsPage />} />
|
|
<Route path="skills" element={<SkillsPage />} />
|
|
<Route path="planning/framework-programs/new" element={<TrainingFrameworkProgramEditPage />} />
|
|
<Route path="planning/framework-programs/:id" element={<TrainingFrameworkProgramEditPage />} />
|
|
<Route path="planning/framework-programs" element={<TrainingFrameworkProgramsListPage />} />
|
|
<Route path="planning/run/:unitId/coach" element={<TrainingCoachPage />} />
|
|
<Route path="planning/run/:unitId" element={<TrainingUnitRunPage />} />
|
|
<Route path="planning" element={<TrainingPlanningPage />} />
|
|
<Route path="admin" element={<Navigate to="/admin/hierarchy" replace />} />
|
|
<Route path="admin/users" element={<AdminUsersPage />} />
|
|
<Route path="admin/hierarchy" element={<AdminHierarchyPage />} />
|
|
<Route path="admin/maturity-models" element={<AdminMaturityModelsPage />} />
|
|
<Route path="admin/catalogs" element={<AdminCatalogsPage />} />
|
|
<Route path="admin/mediawiki-import" element={<MediaWikiImportPage />} />
|
|
<Route path="trainer-contexts" element={<TrainerContextsPage />} />
|
|
</Route>
|
|
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
)
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<AuthProvider>
|
|
<Router>
|
|
<AppRoutes />
|
|
</Router>
|
|
</AuthProvider>
|
|
)
|
|
}
|
|
|
|
export default App
|