// CRITICAL: React must be imported first before any Zustand/react imports import React from 'react'; import ReactDOM from 'react-dom/client'; // Global error handlers (debug logs removed) if (typeof window !== 'undefined') { window.addEventListener('error', (event) => { // Error handling without debug logs }, true); window.addEventListener('unhandledrejection', (event) => { // Unhandled rejection handling without debug logs }); } import { BrowserRouter } from 'react-router-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; // Action 4.6.1.5: Import QueryClient singleton setter import { setQueryClient } from './utils/queryClientSingleton'; // CRITICAL FIX: Import lazy de react-hot-toast pour éviter les collisions de noms de variables après minification import { LazyToaster } from './components/feedback/LazyToaster'; import { App } from './app/App'; import { logger } from './utils/logger'; import './index.css'; import './styles/design-system.css'; import './styles/global-effects.css'; import './styles/header.css'; // FIX URGENT: Charger en dernier pour override les classes focus: problématiques import './styles/fix-input-focus.css'; // FIX DÉFINITIF: Styles forcés pour le formulaire de connexion import './styles/fix-login-form.css'; // Initialize i18next before React renders import './lib/i18n'; // FIX #20: Initialize Sentry for error tracking import { initSentry } from './lib/sentry'; // FE-API-019: Initialize MSW for development if enabled import { env } from './config/env'; // Action 11.2.1.4: Initialize grid overlay utility (dev only) import { initGridOverlay } from './utils/gridOverlay'; // Fix display issues (dev only) - KEPT for diagnostic tools only import './utils/fixDisplayIssues'; // Fix input focus (dev only) - Détecte clavier vs souris import { fixInputFocus } from './utils/fixInputFocus'; // HMR Force Update: 1765126900 // FIX #20: Initialize Sentry before React renders initSentry(); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false, // Keep disabled (intentional - avoid unnecessary refetches) // Edge 6.1: Handle stale data in cache - Ensure stale data refreshed appropriately staleTime: 1 * 60 * 1000, // Default: Consider data fresh for 1 minute (individual hooks can override) gcTime: 5 * 60 * 1000, // Default: Keep in cache for 5 minutes (formerly cacheTime) refetchOnMount: true, // Refetch stale data when component mounts (ensures fresh data) refetchOnReconnect: true, // Refetch stale data when network reconnects }, }, }); // Action 4.6.1.5: Set QueryClient singleton for state invalidation setQueryClient(queryClient); // FE-API-019: Initialize MSW worker for development async function enableMocking() { // FIX: Désactiver MSW par défaut pour éviter les erreurs "module is not defined" // MSW doit être explicitement activé avec VITE_USE_MSW=1 if (!env.USE_MSW) { return; } if (import.meta.env.DEV) { try { const { worker } = await import('./mocks/browser'); // Start the worker await worker.start({ onUnhandledRequest: 'bypass', // Don't warn about unhandled requests serviceWorker: { url: '/mockServiceWorker.js', options: { // FIX: Désactiver le service worker MSW si problème de module // Le service worker peut causer des erreurs "module is not defined" scope: '/', }, }, }); // FIX #18: Utiliser logger structuré const { logger } = await import('./utils/logger'); logger.info('[MSW] Mock Service Worker started', { component: 'MSW' }); } catch (error) { // FIX: Ignorer les erreurs MSW pour ne pas bloquer l'app console.warn('[MSW] Failed to start mock service worker:', error); } } } /** * Wait for all stylesheets to be loaded before rendering * This prevents "Layout was forced before the page was fully loaded" warning * FIX: Version améliorée avec vérification plus robuste */ const waitForStylesheets = (): Promise => { return new Promise((resolve) => { // Function to check if stylesheets are ready const checkStylesheets = (): boolean => { try { // Check if document is ready if (document.readyState !== 'complete' && document.readyState !== 'interactive') { return false; } // Check all stylesheets const stylesheets = Array.from(document.styleSheets); if (stylesheets.length === 0) { // No stylesheets yet, wait a bit return false; } // Check if all stylesheets are loaded let loadedCount = 0; for (const sheet of stylesheets) { try { // Try to access sheet.cssRules to check if it's loaded // This will throw if the stylesheet is not loaded yet if (sheet.cssRules !== null || sheet.href === null) { loadedCount++; } } catch (e) { // Cross-origin stylesheets will throw, but they're usually loaded // Check if it's a cross-origin error (CORS) or a loading error if (sheet.href !== null) { // Has href but can't access rules - likely cross-origin, assume loaded loadedCount++; } } } // All stylesheets must be loaded return loadedCount === stylesheets.length; } catch (e) { return false; } }; // If already complete and stylesheets are ready, wait a bit more to ensure processing if (document.readyState === 'complete' && checkStylesheets()) { // Use multiple requestAnimationFrame calls to ensure stylesheets are processed // Add extra delay to prevent "Layout was forced" warning requestAnimationFrame(() => { requestAnimationFrame(() => { requestAnimationFrame(() => { // Additional delay to ensure all CSS is applied and layout is calculated // This prevents the "Layout was forced before the page was fully loaded" warning setTimeout(() => { // One more check to ensure stylesheets are still ready if (checkStylesheets()) { resolve(); } else { // If not ready, wait a bit more setTimeout(() => resolve(), 100); } }, 100); // Increased delay for better reliability }); }); }); return; } // Wait for load event which fires after all resources (including stylesheets) are loaded if (document.readyState === 'loading') { window.addEventListener('load', () => { // Wait a bit more to ensure all stylesheets are processed let attempts = 0; const maxAttempts = 20; // Increased attempts const checkInterval = setInterval(() => { attempts++; if (checkStylesheets() || attempts >= maxAttempts) { clearInterval(checkInterval); // Use multiple requestAnimationFrame to ensure DOM is ready requestAnimationFrame(() => { requestAnimationFrame(() => { requestAnimationFrame(() => { setTimeout(() => { resolve(); }, 50); }); }); }); } }, 50); // Check every 50ms }, { once: true }); } else { // Interactive state - check and wait let attempts = 0; const maxAttempts = 20; // Increased attempts const checkInterval = setInterval(() => { attempts++; if (checkStylesheets() || attempts >= maxAttempts) { clearInterval(checkInterval); requestAnimationFrame(() => { requestAnimationFrame(() => { requestAnimationFrame(() => { setTimeout(() => { resolve(); }, 50); }); }); }); } }, 50); } }); }; import { ThemeProvider } from './components/theme/ThemeProvider'; const renderApp = () => { ReactDOM.createRoot(document.getElementById('root')!).render( , ); }; // CRITICAL FIX: Précharger react-hot-toast AVANT de rendre l'app // pour éviter les collisions de noms de variables (ie) lors de la minification // Le module sera chargé dans un chunk séparé, évitant les conflits const preloadToast = import('react-hot-toast') .then((mod) => { return mod; }) .catch((err) => { // Ignorer les erreurs de préchargement }); // Start MSW and preload toast before rendering the app Promise.all([enableMocking(), preloadToast]) .then(() => { // Initialization completed }) .catch((error) => { logger.error('[Init] Failed to initialize; continuing', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, }); }) .then(() => { // Wait for stylesheets to be loaded before rendering // This prevents "Layout was forced before the page was fully loaded" warning return waitForStylesheets(); }) .finally(() => { // Action 11.2.1.4: Initialize grid overlay utility (dev only) initGridOverlay(); renderApp(); // Fix input focus après rendu if (import.meta.env.DEV) { setTimeout(() => { fixInputFocus(); }, 500); } });