// Rôle : point d'entrée React, assemble données, routes, shell et overlays. /* eslint-disable react-refresh/only-export-components -- point d'entrée Vite sans export de composant. */ import { lazy, Suspense, useCallback, useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; import "./styles/main.scss"; import { AppOverlays } from "./components/AppOverlays.jsx"; import { Shell } from "./components/Shell.jsx"; import { useIndexedToolboxes } from "./features/toolboxes/storage/useIndexedToolboxes.js"; import { useToolboxActions } from "./features/toolboxes/useToolboxActions.js"; import { useAppData } from "./hooks/useAppData.js"; import { useGameFilters } from "./hooks/useGameFilters.js"; import { useToolboxAlerts } from "./hooks/useToolboxAlerts.js"; import { RouteContent } from "./router/RouteContent.jsx"; import { useHashRoute } from "./router/hashRouter.js"; import { normalizeCalendarData, normalizeTimerData } from "./features/toolboxes/storage/toolboxStorage.js"; const ToolboxDrawer = lazy(() => import("./features/toolboxes/ToolboxPages.jsx").then((module) => ({ default: module.ToolboxDrawer }))); const DEFAULT_NOTIFICATION_DURATION_MS = 120000; const SHORT_NOTIFICATION_DURATION_MS = 5000; function getNotificationDuration(message, options = {}) { if (Number.isFinite(options.durationMs)) return Math.max(1000, Number(options.durationMs)); const normalized = String(message || "").toLowerCase(); return /\bcopi[ée]|\bcoll[ée]|presse-papiers/.test(normalized) ? SHORT_NOTIFICATION_DURATION_MS : DEFAULT_NOTIFICATION_DURATION_MS; } function App() { const route = useHashRoute(); const { siteContent, siteContentError, games, gamesError, mhwilds, diablo4 } = useAppData(route); const [filters, setFilters] = useGameFilters(); const [confirmModal, setConfirmModal] = useState(null); const [createModal, setCreateModal] = useState(null); const [linkModalGameId, setLinkModalGameId] = useState(""); const [drawerGameId, setDrawerGameId] = useState(""); const [image, setImage] = useState(null); const [pendingTutorialToolboxId, setPendingTutorialToolboxId] = useState(""); const [notifications, setNotifications] = useState([]); const [storageError, setStorageError] = useState(""); const handleStorageError = useCallback((message) => setStorageError(message), []); const store = useIndexedToolboxes(handleStorageError); const notify = useCallback((message, options = {}) => { setNotifications((current) => [ { id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, message, durationMs: getNotificationDuration(message, options) }, ...current ].slice(0, 5)); }, []); const dismissNotification = useCallback((notificationId) => { setNotifications((current) => current.filter((notification) => notification.id !== notificationId)); }, []); useEffect(() => { function handleNotification(event) { if (event.detail?.message) notify(event.detail.message, event.detail); } window.addEventListener("sokkog:notify", handleNotification); return () => window.removeEventListener("sokkog:notify", handleNotification); }, [notify]); const t = (key, { capitalize = false } = {}) => { const value = mhwilds.translations[key] || String(key || "").replace(/_/g, " "); return capitalize ? value.charAt(0).toUpperCase() + value.slice(1) : value; }; const getGame = (gameId) => games.find((item) => item.id === gameId); const getToolboxGameId = (toolbox) => Object.entries(store.links).find(([, toolboxId]) => toolboxId === toolbox?.id)?.[0] || ""; const getToolboxGame = (toolbox) => getGame(getToolboxGameId(toolbox)); const actions = useToolboxActions({ store, notify, creationTemplate: siteContent?.toolboxes?.creationTemplate, setCreateModal, setConfirmModal, setLinkModalGameId, setDrawerGameId, setImage }); useToolboxAlerts({ toolboxes: store.toolboxes, moduleData: store.moduleData, links: store.links, route, drawerGameId, normalizeTimerData, normalizeCalendarData, textContent: siteContent?.toolboxes?.modules, notify }); if (!siteContent) { return ( Contenu indisponible {siteContentError || "Chargement du contenu..."} ); } return ( {drawerGameId && ( )} ); } createRoot(document.querySelector("#app")).render();
{siteContentError || "Chargement du contenu..."}