This commit is contained in:
Tomáš Dvořák
2025-10-16 13:32:05 +02:00
commit 12cba639b9
663 changed files with 168914 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import './styles/global-enhancements.css';
import './styles/admin-enhancements.css';
import App, { theme } from './App';
import { ColorModeScript } from '@chakra-ui/react';
import reportWebVitals from './reportWebVitals';
import { HelmetProvider } from 'react-helmet-async';
// Cookie consent utilities
type Consent = { analytics?: boolean };
const getConsent = (): Consent | null => {
try {
const raw = localStorage.getItem('cookie_consent');
return raw ? JSON.parse(raw) : null;
} catch {
return null;
}
};
const onConsentChange = (cb: (c: Consent) => void) => {
window.addEventListener('cookie-consent-change', (e: Event) => {
const detail = (e as CustomEvent).detail as Consent;
cb(detail || {});
});
};
// Example analytics initializer (placeholder)
const initAnalytics = () => {
// Place your analytics loader here (e.g., GA/Matomo), gated by consent.analytics
// This function will be called only when analytics consent is granted.
};
// Error Boundary component
class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean}> {
constructor(props: {children: React.ReactNode}) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught by ErrorBoundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
<h2>Something went wrong.</h2>
<p>Please refresh the page or try again later.</p>
</div>
);
}
return this.props.children;
}
}
// Log unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
// Optionally report to monitoring service here
});
const rootElement = document.getElementById('root');
if (!rootElement) {
// Failed to find the root element
} else {
try {
// Initialize CSS variables immediately to prevent flash of fallback colors
const r = document.documentElement;
// Try to load cached colors from localStorage for instant display
let cachedColors: any = null;
try {
const cached = localStorage.getItem('club_theme_cache');
if (cached) {
cachedColors = JSON.parse(cached);
// Use cache if it's less than 24 hours old
const age = Date.now() - (cachedColors.timestamp || 0);
if (age > 24 * 60 * 60 * 1000) {
cachedColors = null; // Cache expired
}
}
} catch (e) {
// Ignore localStorage errors
}
// Set CSS variables - use cached values if available, otherwise defaults
r.style.setProperty('--club-primary', cachedColors?.primary || '#0b5cff');
r.style.setProperty('--club-secondary', cachedColors?.secondary || '#ffd200');
r.style.setProperty('--club-accent', cachedColors?.accent || '#141414');
r.style.setProperty('--club-text-on-primary', cachedColors?.textOnPrimary || '#ffffff');
if (cachedColors?.textOnSecondary) r.style.setProperty('--club-text-on-secondary', cachedColors.textOnSecondary);
if (cachedColors?.textOnAccent) r.style.setProperty('--club-text-on-accent', cachedColors.textOnAccent);
r.style.setProperty('--club-bg-light', cachedColors?.background || '#ffffff');
r.style.setProperty('--club-text-light', cachedColors?.text || '#000000');
// Load fonts
const link = document.createElement('link');
link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@600;700;800&display=swap';
link.rel = 'stylesheet';
document.head.appendChild(link);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<ErrorBoundary>
<HelmetProvider>
{/* Ensure color mode (light/dark) persists and matches Chakra config before UI renders */}
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<App />
</HelmetProvider>
</ErrorBoundary>
</React.StrictMode>
);
// App rendered
// Initialize analytics if consent allows
const current = getConsent();
if (current?.analytics) {
initAnalytics();
}
// React to future consent changes
onConsentChange((c) => {
if (c?.analytics) {
initAnalytics();
}
});
} catch (error) {
// Optionally report to monitoring service
// console.error('Error rendering application:', error);
rootElement.innerHTML = `
<div style="padding: 20px; font-family: Arial, sans-serif; color: #721c24; background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px;">
<h2>Application Error</h2>
<p>${String(error)}</p>
<p>Please check the console for more details and refresh the page.</p>
</div>
`;
}
}
// Report web vitals (disabled logging by default). Hook up your analytics here if needed.
reportWebVitals();