a3638fe954
Test and Lint / backend-test (push) Successful in 1m11s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m17s
Version and Release / version-bump (push) Successful in 43s
Version and Release / trigger-drone (push) Successful in 3s
- Add URL utility functions for building resource URLs - Update all components to use relative URLs in production - Add production deployment documentation - Update nginx config to proxy all required endpoints - Add .env.production.example with proper configuration
153 lines
5.5 KiB
TypeScript
153 lines
5.5 KiB
TypeScript
import { useEffect } from 'react';
|
|
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { ToastContainer } from 'react-toastify';
|
|
import 'react-toastify/dist/ReactToastify.css';
|
|
import { analyticsService } from './services/analytics.service';
|
|
|
|
import { GalleryAuthProvider, MaintenanceProvider } from './contexts';
|
|
import { ThemeProvider } from './contexts/ThemeContext';
|
|
import { GalleryPage } from './pages/GalleryPage';
|
|
import { PreviewPage } from './pages/gallery/PreviewPage';
|
|
import { LegalPage } from './pages/public/LegalPage';
|
|
import {
|
|
AdminLoginPage,
|
|
AdminDashboard,
|
|
EventsListPage,
|
|
CreateEventPageEnhanced as CreateEventPage,
|
|
EventDetailsPage,
|
|
EmailConfigPage,
|
|
ArchivesPage,
|
|
AnalyticsPage,
|
|
BrandingPage,
|
|
SettingsPage,
|
|
CMSPage
|
|
} from './pages/admin';
|
|
import { AdminLayout, AdminAuthWrapper } from './components/admin';
|
|
import { PageErrorBoundary, OfflineIndicator, SkipLink, DynamicFavicon } from './components/common';
|
|
import { MaintenanceWrapper } from './components/MaintenanceWrapper';
|
|
import { GlobalThemeProvider } from './components/GlobalThemeProvider';
|
|
import { getApiBaseUrl } from './utils/url';
|
|
|
|
// Create a client
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
refetchOnWindowFocus: false,
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
function App() {
|
|
// Initialize Umami Analytics based on settings
|
|
useEffect(() => {
|
|
const initializeAnalytics = async () => {
|
|
const umamiUrl = import.meta.env.VITE_UMAMI_URL;
|
|
const umamiWebsiteId = import.meta.env.VITE_UMAMI_WEBSITE_ID;
|
|
|
|
if (umamiUrl && umamiWebsiteId) {
|
|
try {
|
|
// Fetch public settings to check if analytics is enabled
|
|
const response = await fetch(`${getApiBaseUrl()}/public/settings`);
|
|
const settings = await response.json();
|
|
|
|
// Only initialize if analytics is enabled in settings
|
|
if (settings.enable_analytics !== false) {
|
|
analyticsService.initialize({
|
|
websiteId: umamiWebsiteId,
|
|
hostUrl: umamiUrl,
|
|
autoTrack: true,
|
|
doNotTrack: true
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch settings for analytics:', error);
|
|
// Initialize analytics anyway if settings fetch fails
|
|
analyticsService.initialize({
|
|
websiteId: umamiWebsiteId,
|
|
hostUrl: umamiUrl,
|
|
autoTrack: true,
|
|
doNotTrack: true
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
initializeAnalytics();
|
|
}, []);
|
|
|
|
return (
|
|
<PageErrorBoundary>
|
|
<QueryClientProvider client={queryClient}>
|
|
<MaintenanceProvider>
|
|
<ThemeProvider>
|
|
<GlobalThemeProvider>
|
|
<DynamicFavicon />
|
|
<Router>
|
|
<MaintenanceWrapper>
|
|
<SkipLink />
|
|
<Routes>
|
|
{/* Public gallery routes */}
|
|
<Route path="/gallery/preview" element={<PreviewPage />} />
|
|
<Route path="/gallery/:slug/:token?" element={
|
|
<GalleryAuthProvider>
|
|
<GalleryPage />
|
|
</GalleryAuthProvider>
|
|
} />
|
|
|
|
{/* Admin routes - wrap with AdminAuthProvider */}
|
|
<Route path="/admin" element={<AdminAuthWrapper />}>
|
|
<Route path="login" element={<AdminLoginPage />} />
|
|
<Route element={<AdminLayout />}>
|
|
<Route path="dashboard" element={<AdminDashboard />} />
|
|
<Route path="events" element={<EventsListPage />} />
|
|
<Route path="events/new" element={<CreateEventPage />} />
|
|
<Route path="events/:id" element={<EventDetailsPage />} />
|
|
<Route path="archives" element={<ArchivesPage />} />
|
|
<Route path="email" element={<EmailConfigPage />} />
|
|
<Route path="analytics" element={<AnalyticsPage />} />
|
|
<Route path="branding" element={<BrandingPage />} />
|
|
<Route path="settings" element={<SettingsPage />} />
|
|
<Route path="cms" element={<CMSPage />} />
|
|
<Route index element={<Navigate to="/admin/dashboard" replace />} />
|
|
</Route>
|
|
</Route>
|
|
|
|
{/* Public legal pages */}
|
|
<Route path="/impressum" element={<LegalPage />} />
|
|
<Route path="/datenschutz" element={<LegalPage />} />
|
|
<Route path="/:slug" element={<LegalPage />} />
|
|
|
|
{/* Default redirect */}
|
|
<Route path="/" element={<Navigate to="/admin/login" replace />} />
|
|
</Routes>
|
|
</MaintenanceWrapper>
|
|
</Router>
|
|
|
|
{/* Offline indicator */}
|
|
<OfflineIndicator />
|
|
|
|
{/* Toast notifications */}
|
|
<ToastContainer
|
|
position="bottom-right"
|
|
autoClose={5000}
|
|
hideProgressBar={false}
|
|
newestOnTop
|
|
closeOnClick
|
|
rtl={false}
|
|
pauseOnFocusLoss
|
|
draggable
|
|
pauseOnHover
|
|
theme="light"
|
|
/>
|
|
</GlobalThemeProvider>
|
|
</ThemeProvider>
|
|
</MaintenanceProvider>
|
|
</QueryClientProvider>
|
|
</PageErrorBoundary>
|
|
);
|
|
}
|
|
|
|
export default App;
|