mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
294 lines
16 KiB
TypeScript
294 lines
16 KiB
TypeScript
import React, { lazy, Suspense } from 'react';
|
|
import { ChakraProvider, extendTheme, Spinner, Center, Box } from '@chakra-ui/react';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from 'react-router-dom';
|
|
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
import { ClubThemeProvider } from './contexts/ClubThemeContext';
|
|
import { HelmetProvider } from 'react-helmet-async';
|
|
import { theme } from './App';
|
|
import { useUmami } from './hooks/useUmami';
|
|
import { useFontLoader } from './hooks/useFontLoader';
|
|
import DefaultSEO from './components/seo/DefaultSEO';
|
|
import CookieBanner from './components/CookieBanner';
|
|
import ProtectedRoute from './components/ProtectedRoute';
|
|
import { getSetupStatus } from './services/setup';
|
|
import { useState, useEffect } from 'react';
|
|
|
|
// Create a client
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 5 * 60 * 1000,
|
|
cacheTime: 10 * 60 * 1000,
|
|
refetchOnWindowFocus: false,
|
|
refetchOnMount: false,
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Loading component
|
|
const PageLoader = () => (
|
|
<Center h="100vh">
|
|
<Box textAlign="center">
|
|
<Spinner size="xl" color="brand.primary" thickness="4px" />
|
|
<Box mt={4} fontSize="sm" color="gray.600">Načítání...</Box>
|
|
</Box>
|
|
</Center>
|
|
);
|
|
|
|
// Lazy load pages for code splitting
|
|
const HomePage = lazy(() => import('./pages/HomePage'));
|
|
const BlogPage = lazy(() => import('./pages/BlogPage'));
|
|
const ArticleDetailPage = lazy(() => import('./pages/ArticleDetailPage'));
|
|
const ActivityDetailPage = lazy(() => import('./pages/ActivityDetailPage'));
|
|
const MatchDetailPage = lazy(() => import('./pages/MatchDetailPage'));
|
|
const ClubPage = lazy(() => import('./pages/ClubPage'));
|
|
const CalendarPage = lazy(() => import('./pages/CalendarPage'));
|
|
const TablesPage = lazy(() => import('./pages/TablesPage'));
|
|
const MatchesPage = lazy(() => import('./pages/MatchesPage'));
|
|
const PlayersPage = lazy(() => import('./pages/PlayersPage'));
|
|
const PlayerDetailPage = lazy(() => import('./pages/PlayerDetailPage'));
|
|
const SponsorsPage = lazy(() => import('./pages/SponsorsPage'));
|
|
const ContactPage = lazy(() => import('./pages/ContactPage'));
|
|
const GalleryPage = lazy(() => import('./pages/GalleryPage'));
|
|
const AlbumDetailPage = lazy(() => import('./pages/AlbumDetailPage'));
|
|
const AuthPage = lazy(() => import('./pages/AuthPage'));
|
|
const RegisterPage = lazy(() => import('./pages/RegisterPage'));
|
|
const ForgotPasswordPage = lazy(() => import('./pages/ForgotPasswordPage'));
|
|
const ResetPasswordPage = lazy(() => import('./pages/ResetPasswordPage'));
|
|
const ActivitiesCalendarPage = lazy(() => import('./pages/ActivitiesCalendarPage'));
|
|
const AboutPage = lazy(() => import('./pages/AboutPage'));
|
|
const SetupPage = lazy(() => import('./pages/SetupPage'));
|
|
const StylePreviewPage = lazy(() => import('./pages/StylePreviewPage'));
|
|
const NewsletterUnsubscribePage = lazy(() => import('./pages/NewsletterUnsubscribePage'));
|
|
const NewsletterPreferencesPage = lazy(() => import('./pages/NewsletterPreferencesPage'));
|
|
const VideosPage = lazy(() => import('./pages/VideosPage'));
|
|
const SearchPage = lazy(() => import('./pages/SearchPage'));
|
|
const ClothingPage = lazy(() => import('./pages/ClothingPage'));
|
|
const PollsPage = lazy(() => import('./pages/PollsPage'));
|
|
const OverlayScoreboardPage = lazy(() => import('./pages/OverlayScoreboardPage'));
|
|
const OverlaySponsorsPage = lazy(() => import('./pages/OverlaySponsorsPage'));
|
|
const NotFoundPage = lazy(() => import('./pages/NotFoundPage'));
|
|
const ForbiddenPage = lazy(() => import('./pages/ForbiddenPage'));
|
|
|
|
// Legal pages
|
|
const CookiePolicyPage = lazy(() => import('./pages/legal/CookiePolicyPage'));
|
|
const TermsPage = lazy(() => import('./pages/legal/TermsPage'));
|
|
const PrivacyPolicyPage = lazy(() => import('./pages/legal/PrivacyPolicyPage'));
|
|
|
|
// Admin pages
|
|
const AdminDashboardPage = lazy(() => import('./pages/admin/AdminDashboardPage'));
|
|
const ArticlesAdminPage = lazy(() => import('./pages/admin/ArticlesAdminPage'));
|
|
const SponsorsAdminPage = lazy(() => import('./pages/admin/SponsorsAdminPage'));
|
|
const CategoriesAdminPage = lazy(() => import('./pages/admin/CategoriesAdminPage'));
|
|
const MediaAdminPage = lazy(() => import('./pages/admin/MediaAdminPage'));
|
|
const MatchesAdminPage = lazy(() => import('./pages/admin/MatchesAdminPage'));
|
|
const PlayersAdminPage = lazy(() => import('./pages/admin/PlayersAdminPage'));
|
|
const TeamsAdminPage = lazy(() => import('./pages/admin/TeamsAdminPage'));
|
|
const BannersAdminPage = lazy(() => import('./pages/admin/BannersAdminPage'));
|
|
const MessagesAdminPage = lazy(() => import('./pages/admin/MessagesAdminPage'));
|
|
const SettingsAdminPage = lazy(() => import('./pages/admin/SettingsAdminPage'));
|
|
const UsersAdminPage = lazy(() => import('./pages/admin/UsersAdminPage'));
|
|
const NewsletterAdminPage = lazy(() => import('./pages/admin/NewsletterAdminPage'));
|
|
const CompetitionAliasesAdminPage = lazy(() => import('./pages/admin/CompetitionAliasesAdminPage'));
|
|
const PrefetchAdminPage = lazy(() => import('./pages/admin/PrefetchAdminPage'));
|
|
const AdminVideosPage = lazy(() => import('./pages/admin/AdminVideosPage'));
|
|
const GalleryAdminPage = lazy(() => import('./pages/admin/GalleryAdminPage'));
|
|
const AdminActivitiesPage = lazy(() => import('./pages/admin/AdminActivitiesPage'));
|
|
const AdminMerchPage = lazy(() => import('./pages/admin/AdminMerchPage'));
|
|
const AdminResetPasswordPage = lazy(() => import('./pages/admin/AdminResetPasswordPage'));
|
|
const AboutAdminPage = lazy(() => import('./pages/admin/AboutAdminPage'));
|
|
const AnalyticsAdminPage = lazy(() => import('./pages/admin/AnalyticsAdminPage'));
|
|
const FilesAdminPage = lazy(() => import('./pages/admin/FilesAdminPage'));
|
|
const ContactsAdminPage = lazy(() => import('./pages/admin/ContactsAdminPage'));
|
|
const NavigationAdminPage = lazy(() => import('./pages/admin/NavigationAdminPage'));
|
|
const PollsAdminPage = lazy(() => import('./pages/admin/PollsAdminPage'));
|
|
const CommentsAdminPage = lazy(() => import('./pages/admin/CommentsAdminPage'));
|
|
const AdminDocsPage = lazy(() => import('./pages/admin/AdminDocsPage'));
|
|
const ScoreboardAdminPage = lazy(() => import('./pages/admin/ScoreboardAdminPage'));
|
|
const MobileScoreboardControlPage = lazy(() => import('./pages/admin/MobileScoreboardControlPage'));
|
|
const ShortlinksAdminPage = lazy(() => import('./pages/admin/ShortlinksAdminPage'));
|
|
const EngagementAdminPage = lazy(() => import('./pages/admin/EngagementAdminPage'));
|
|
const SemiAdminPage = lazy(() => import('./pages/SemiAdminPage'));
|
|
|
|
// Analytics and font loader
|
|
const AnalyticsInitializer: React.FC = () => {
|
|
useUmami();
|
|
return null;
|
|
};
|
|
|
|
const FontLoader: React.FC = () => {
|
|
useFontLoader();
|
|
return null;
|
|
};
|
|
|
|
// Public route wrapper
|
|
const PublicRoute = ({ children }: { children: React.ReactNode }) => {
|
|
const { isAuthenticated, isLoading } = useAuth();
|
|
const [checkingSetup, setCheckingSetup] = useState(true);
|
|
const [requiresSetup, setRequiresSetup] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
let mounted = true;
|
|
(async () => {
|
|
try {
|
|
const s = await getSetupStatus();
|
|
if (mounted) setRequiresSetup(!!s.requires_setup);
|
|
} catch (_) {
|
|
if (mounted) setRequiresSetup(false);
|
|
} finally {
|
|
if (mounted) setCheckingSetup(false);
|
|
}
|
|
})();
|
|
return () => { mounted = false; };
|
|
}, []);
|
|
|
|
if (isLoading || checkingSetup) {
|
|
return <PageLoader />;
|
|
}
|
|
|
|
if (isAuthenticated) {
|
|
return <Navigate to="/admin" replace />;
|
|
}
|
|
|
|
const currentPath = window.location.pathname;
|
|
if (requiresSetup && currentPath !== '/setup') {
|
|
return <Navigate to="/setup" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
};
|
|
|
|
const AdminRoutesWrapper = () => {
|
|
return <Outlet />;
|
|
};
|
|
|
|
const AppLazy: React.FC = () => {
|
|
return (
|
|
<ChakraProvider theme={theme}>
|
|
<QueryClientProvider client={queryClient}>
|
|
<Router>
|
|
<AuthProvider>
|
|
<ClubThemeProvider>
|
|
<HelmetProvider>
|
|
<AnalyticsInitializer />
|
|
<FontLoader />
|
|
<DefaultSEO />
|
|
<Suspense fallback={<PageLoader />}>
|
|
<Routes>
|
|
{/* Public routes */}
|
|
<Route path="/" element={<HomePage />} />
|
|
<Route path="/hledat" element={<SearchPage />} />
|
|
<Route path="/search" element={<SearchPage />} />
|
|
<Route path="/overlay/scoreboard" element={<OverlayScoreboardPage />} />
|
|
<Route path="/overlay/sponsors" element={<OverlaySponsorsPage />} />
|
|
<Route path="/blog" element={<BlogPage />} />
|
|
<Route path="/klub" element={<ClubPage />} />
|
|
<Route path="/o-klubu" element={<AboutPage />} />
|
|
<Route path="/kalendar" element={<CalendarPage />} />
|
|
<Route path="/aktivity" element={<ActivitiesCalendarPage />} />
|
|
<Route path="/tabulky" element={<TablesPage />} />
|
|
<Route path="/zapasy" element={<MatchesPage />} />
|
|
<Route path="/players" element={<PlayersPage />} />
|
|
<Route path="/hraci" element={<PlayersPage />} />
|
|
<Route path="/players/:id" element={<PlayerDetailPage />} />
|
|
<Route path="/hraci/:id" element={<PlayerDetailPage />} />
|
|
<Route path="/sponzori" element={<SponsorsPage />} />
|
|
<Route path="/kontakt" element={<ContactPage />} />
|
|
<Route path="/ankety" element={<PollsPage />} />
|
|
<Route path="/galerie" element={<GalleryPage />} />
|
|
<Route path="/galerie/album/:id" element={<AlbumDetailPage />} />
|
|
<Route path="/videa" element={<VideosPage />} />
|
|
<Route path="/obleceni" element={<ClothingPage />} />
|
|
|
|
{/* Legal pages */}
|
|
<Route path="/pravidla-cookies" element={<CookiePolicyPage />} />
|
|
<Route path="/obchodni-podminky" element={<TermsPage />} />
|
|
<Route path="/zasady-ochrany-osobnich-udaju" element={<PrivacyPolicyPage />} />
|
|
|
|
{/* Article routes */}
|
|
<Route path="/news" element={<Navigate to="/blog" replace />} />
|
|
<Route path="/news/:slug" element={<ArticleDetailPage />} />
|
|
<Route path="/articles/slug/:slug" element={<ArticleDetailPage />} />
|
|
<Route path="/articles/:id" element={<ArticleDetailPage />} />
|
|
<Route path="/zapas/:id" element={<MatchDetailPage />} />
|
|
<Route path="/aktivita/:id" element={<ActivityDetailPage />} />
|
|
|
|
{/* Redirects */}
|
|
<Route path="/clanky" element={<Navigate to="/blog" replace />} />
|
|
<Route path="/aktuality" element={<Navigate to="/blog" replace />} />
|
|
|
|
{/* Setup */}
|
|
<Route path="/setup" element={<PublicRoute><SetupPage /></PublicRoute>} />
|
|
<Route path="/setup/styl" element={<PublicRoute><StylePreviewPage /></PublicRoute>} />
|
|
|
|
{/* Auth */}
|
|
<Route path="/login" element={<PublicRoute><AuthPage /></PublicRoute>} />
|
|
<Route path="/register" element={<PublicRoute><RegisterPage /></PublicRoute>} />
|
|
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
|
|
<Route path="/reset-password" element={<ResetPasswordPage />} />
|
|
<Route path="/newsletter/unsubscribe/:email" element={<NewsletterUnsubscribePage />} />
|
|
<Route path="/newsletter/preferences" element={<NewsletterPreferencesPage />} />
|
|
<Route path="/403" element={<ForbiddenPage />} />
|
|
<Route path="/semiadmin" element={<ProtectedRoute><SemiAdminPage /></ProtectedRoute>} />
|
|
|
|
{/* Admin routes */}
|
|
<Route element={<ProtectedRoute requiredRole="admin"><AdminRoutesWrapper /></ProtectedRoute>}>
|
|
<Route path="/admin" element={<AdminDashboardPage />} />
|
|
<Route path="/admin/docs" element={<AdminDocsPage />} />
|
|
<Route path="/admin/clanky" element={<ArticlesAdminPage />} />
|
|
<Route path="/admin/o-klubu" element={<AboutAdminPage />} />
|
|
<Route path="/admin/videa" element={<AdminVideosPage />} />
|
|
<Route path="/admin/galerie" element={<GalleryAdminPage />} />
|
|
<Route path="/admin/obleceni" element={<AdminMerchPage />} />
|
|
<Route path="/admin/aktivity" element={<AdminActivitiesPage />} />
|
|
<Route path="/admin/sponzori" element={<SponsorsAdminPage />} />
|
|
<Route path="/admin/kategorie" element={<CategoriesAdminPage />} />
|
|
<Route path="/admin/media" element={<MediaAdminPage />} />
|
|
<Route path="/admin/zapasy" element={<MatchesAdminPage />} />
|
|
<Route path="/admin/hraci" element={<PlayersAdminPage />} />
|
|
<Route path="/admin/tymy" element={<TeamsAdminPage />} />
|
|
<Route path="/admin/uzivatele" element={<UsersAdminPage />} />
|
|
<Route path="/admin/bannery" element={<BannersAdminPage />} />
|
|
<Route path="/admin/zpravy" element={<MessagesAdminPage />} />
|
|
<Route path="/admin/nastaveni" element={<SettingsAdminPage />} />
|
|
<Route path="/admin/newsletter" element={<NewsletterAdminPage />} />
|
|
<Route path="/admin/ankety" element={<PollsAdminPage />} />
|
|
<Route path="/admin/aliasy-soutezi" element={<CompetitionAliasesAdminPage />} />
|
|
<Route path="/admin/prefetch" element={<PrefetchAdminPage />} />
|
|
<Route path="/admin/users/send-reset" element={<AdminResetPasswordPage />} />
|
|
<Route path="/admin/scoreboard" element={<ScoreboardAdminPage />} />
|
|
<Route path="/admin/scoreboard/remote" element={<MobileScoreboardControlPage />} />
|
|
<Route path="/admin/analytika" element={<AnalyticsAdminPage />} />
|
|
<Route path="/admin/soubory" element={<FilesAdminPage />} />
|
|
<Route path="/admin/kontakty" element={<ContactsAdminPage />} />
|
|
<Route path="/admin/navigace" element={<NavigationAdminPage />} />
|
|
<Route path="/admin/komentare" element={<CommentsAdminPage />} />
|
|
<Route path="/admin/shortlinks" element={<ShortlinksAdminPage />} />
|
|
<Route path="/admin/engagement" element={<EngagementAdminPage />} />
|
|
</Route>
|
|
|
|
{/* Legacy admin routes */}
|
|
<Route path="/dashboard" element={<Navigate to="/admin" replace />} />
|
|
<Route path="/admin/sponsors" element={<ProtectedRoute requiredRole="admin"><SponsorsAdminPage /></ProtectedRoute>} />
|
|
<Route path="/admin/banners" element={<ProtectedRoute requiredRole="admin"><BannersAdminPage /></ProtectedRoute>} />
|
|
<Route path="/admin/messages" element={<ProtectedRoute requiredRole="admin"><MessagesAdminPage /></ProtectedRoute>} />
|
|
<Route path="/admin/settings" element={<ProtectedRoute requiredRole="admin"><SettingsAdminPage /></ProtectedRoute>} />
|
|
|
|
{/* 404 */}
|
|
<Route path="*" element={<NotFoundPage />} />
|
|
</Routes>
|
|
</Suspense>
|
|
<CookieBanner />
|
|
</HelmetProvider>
|
|
</ClubThemeProvider>
|
|
</AuthProvider>
|
|
</Router>
|
|
</QueryClientProvider>
|
|
</ChakraProvider>
|
|
);
|
|
};
|
|
|
|
export default AppLazy;
|