import React, { Suspense, lazy } from 'react' import LoginPage from './pages/LoginPage' import { lazyWithRetry } from './utils/lazyWithRetry' import { RouterProvider, createBrowserRouter, Navigate, NavLink, useLocation, Outlet, } from 'react-router-dom' import { AuthProvider, useAuth } from './context/AuthContext' import { EntitlementsProvider } from './context/EntitlementsContext' import { FormEditorActionsProvider, FormEditorBottomSlot } from './context/FormEditorActionsContext' import { ToastProvider } from './context/ToastContext' import { OrgInboxProvider, useOrgInbox } from './context/OrgInboxContext' import DesktopSidebar from './components/DesktopSidebar' import { getMainNavItems } from './config/appNav' import { isOnboardingAllowedPath, isOnboardingRestricted } from './utils/accountState' import AdminHomeRedirect from './components/AdminHomeRedirect' import PlatformAdminRoute from './components/PlatformAdminRoute' import ActiveClubSwitcher from './components/ActiveClubSwitcher' import InactiveMembershipBanner from './components/InactiveMembershipBanner' import './app.css' const OnboardingPage = lazyWithRetry(() => import('./pages/OnboardingPage')) const VerifyPage = lazy(() => import('./pages/VerifyPage')) const Dashboard = lazy(() => import('./pages/Dashboard')) const AccountSettingsPage = lazy(() => import('./pages/AccountSettingsPage')) const SettingsSystemInfoPage = lazy(() => import('./pages/SettingsSystemInfoPage')) const ExercisesListPage = lazy(() => import('./pages/ExercisesListPage')) const ExerciseDetailPage = lazy(() => import('./pages/ExerciseDetailPage')) const ExerciseFormPage = lazy(() => import('./pages/ExerciseFormPage')) const ProgressionGraphEditPage = lazy(() => import('./pages/ProgressionGraphEditPage')) const ClubsPage = lazy(() => import('./pages/ClubsPage')) const InboxPage = lazy(() => import('./pages/InboxPage')) const SkillsPage = lazy(() => import('./pages/SkillsPage')) const TrainingPlanningPage = lazy(() => import('./pages/TrainingPlanningPage')) const TrainingPlanTemplatesListPage = lazy(() => import('./pages/TrainingPlanTemplatesListPage')) const TrainingPlanTemplateEditPage = lazy(() => import('./pages/TrainingPlanTemplateEditPage')) const PlanningLayout = lazy(() => import('./layouts/PlanningLayout')) const TrainingFrameworkProgramsListPage = lazy(() => import('./pages/TrainingFrameworkProgramsListPage'), ) const TrainingFrameworkProgramEditPage = lazy(() => import('./pages/TrainingFrameworkProgramEditPage'), ) const TrainingModulesListPage = lazy(() => import('./pages/TrainingModulesListPage')) const TrainingModuleEditPage = lazy(() => import('./pages/TrainingModuleEditPage')) const TrainingUnitRunPage = lazy(() => import('./pages/TrainingUnitRunPage')) const TrainingUnitEditPage = lazy(() => import('./pages/TrainingUnitEditPage')) const TrainingCoachPage = lazy(() => import('./pages/TrainingCoachPage')) const AdminCatalogsPage = lazy(() => import('./pages/AdminCatalogsPage')) const AdminHierarchyPage = lazy(() => import('./pages/AdminHierarchyPage')) const AdminMaturityModelsPage = lazy(() => import('./pages/AdminMaturityModelsPage')) const TrainerContextsPage = lazy(() => import('./pages/TrainerContextsPage')) const MediaWikiImportPage = lazy(() => import('./pages/MediaWikiImportPage')) const AdminUsersPage = lazy(() => import('./pages/AdminUsersPage')) const AdminClubCreationRequestsPage = lazy(() => import('./pages/AdminClubCreationRequestsPage')) const AdminRightsPage = lazy(() => import('./pages/AdminRightsPage')) const MediaLibraryPage = lazy(() => import('./pages/MediaLibraryPage')) const LegalPage = lazy(() => import('./pages/LegalPage')) const AdminLegalDocumentsPage = lazy(() => import('./pages/AdminLegalDocumentsPage')) const AdminAiSkillRetrievalPage = lazy(() => import('./pages/AdminAiSkillRetrievalPage')) const AdminAiPromptsPage = lazy(() => import('./pages/AdminAiPromptsPage')) const AdminExerciseEnrichmentPage = lazy(() => import('./pages/AdminExerciseEnrichmentPage')) const AdminUserContentPage = lazy(() => import('./pages/AdminUserContentPage')) const SettingsLegalPage = lazy(() => import('./pages/SettingsLegalPage')) /** Shield „Admin“: nur Super-Admin (global). Vereinsorga: Vereine → Mitglieder. */ function computeShowAdminNav(currentUser) { return currentUser?.role === 'superadmin' } function AppRouteFallback() { return (
) } // Bottom Navigation (Mobile) function Nav({ showAdminNav, onboardingOnly }) { const { canShowInboxNav, inboxCount } = useOrgInbox() const items = getMainNavItems(showAdminNav, { showInbox: canShowInboxNav, onboardingOnly, }) const loc = useLocation() const navItemActive = (pathname, item, routerIsActive) => { if (item.to.startsWith('/admin')) return pathname.startsWith('/admin') return routerIsActive } return ( ) } function ProtectedLayout() { const { isAuthenticated, loading, user, logout } = useAuth() const handleLogout = async () => { if (!confirm('Wirklich abmelden?')) return await logout() window.location.href = '/login' } if (loading) { return (
) } if (!isAuthenticated) { return } const location = useLocation() const onboardingOnly = isOnboardingRestricted(user) if (onboardingOnly && !isOnboardingAllowedPath(location.pathname)) { return } const showAdminNav = computeShowAdminNav(user) && !onboardingOnly return (
🥋 Shinkan
{!onboardingOnly ? : null}
) } function PublicRoute({ children }) { const { isAuthenticated, loading } = useAuth() if (loading) { return (
) } return !isAuthenticated ? children : } /** * Data Router — erforderlich für `useBlocker` (ungespeicherte Änderungen). * Klassisches `BrowserRouter` stellt keinen DataRouterContext bereit; ohne Migration * werfen Seiten mit `useUnsavedChangesBlocker` beim Rendern eine Invariante. */ const appRouter = createBrowserRouter([ { path: '/verify', element: }, { path: '/login', element: ( ), }, { path: '/impressum', element: }, { path: '/datenschutz', element: }, { path: '/nutzungsbedingungen', element: }, { path: '/medienrichtlinie', element: }, { element: , children: [ { index: true, element: }, { path: 'onboarding', element: }, { path: 'profile', element: }, { path: 'settings', element: }, { path: 'settings/system', element: }, { path: 'settings/legal', element: }, { path: 'media', element: }, { path: 'progression-graphs/:id', element: }, { path: 'exercises', children: [ { index: true, element: }, { path: 'new', element: }, { path: ':id/edit', element: }, { path: ':id', element: }, ], }, { path: 'clubs', element: }, { path: 'inbox', element: }, { path: 'skills', element: }, { path: 'planning', element: , children: [ { index: true, element: }, { path: 'framework-programs', element: }, { path: 'training-modules', element: }, { path: 'plan-templates', element: }, { path: 'units/new', element: }, { path: 'units/:id/edit', element: }, ], }, { path: 'planning/framework-programs/new', element: }, { path: 'planning/framework-programs/:id', element: }, { path: 'planning/training-modules/new', element: }, { path: 'planning/training-modules/:id', element: }, { path: 'planning/plan-templates/:id', element: }, { path: 'planning/run/:unitId/coach', element: }, { path: 'planning/run/:unitId', element: }, { path: 'admin', element: }, { path: 'admin/users', element: ( ), }, { path: 'admin/club-creation-requests', element: ( ), }, { path: 'admin/rights', element: ( ), }, { path: 'admin/membership', element: }, { path: 'admin/hierarchy', element: ( ), }, { path: 'admin/maturity-models', element: ( ), }, { path: 'admin/catalogs', element: ( ), }, { path: 'admin/mediawiki-import', element: ( ), }, { path: 'admin/legal-documents', element: ( ), }, { path: 'admin/ai-skill-retrieval', element: ( ), }, { path: 'admin/ai-prompts', element: ( ), }, { path: 'admin/exercise-enrichment', element: ( ), }, { path: 'admin/user-content', element: ( ), }, { path: 'trainer-contexts', element: }, ], }, { path: '*', element: }, ]) function App() { return ( }> ) } export default App