sokko-g/website/src/main.jsx
Shinuwa 2e6d8a2c0c
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
keepsafe rework & alert ajustments
2026-07-26 17:48:14 +02:00

154 lines
5.5 KiB
JavaScript

// Rôle : point d'entrée React, assemble données, routes, shell et overlays.
import React, { 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 { ToolboxDrawer } from "./features/toolboxes/ToolboxPages.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 { useTimerAlerts } from "./hooks/useTimerAlerts.js";
import { RouteContent } from "./router/RouteContent.jsx";
import { useHashRoute } from "./router/hashRouter.js";
import { normalizeTimerData } from "./features/toolboxes/storage/toolboxStorage.js";
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 [notifications, setNotifications] = useState([]);
const [storageError, setStorageError] = useState("");
const store = useIndexedToolboxes((message) => setStorageError(message));
const notify = useCallback((message) => {
setNotifications((current) => [
{ id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, message },
...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);
}
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,
setCreateModal,
setConfirmModal,
setLinkModalGameId,
setDrawerGameId,
setImage
});
useTimerAlerts({
toolboxes: store.toolboxes,
moduleData: store.moduleData,
links: store.links,
route,
drawerGameId,
normalizeTimerData,
textContent: siteContent?.toolboxes?.modules?.timer,
notify
});
if (!siteContent) {
return (
<main className="startup-error">
<section className="empty">
<h1>Contenu indisponible</h1>
<p>{siteContentError || "Chargement du contenu..."}</p>
</section>
</main>
);
}
return (
<Shell route={route} content={siteContent} games={games} toolboxes={store.toolboxes} links={store.links} actions={actions}>
<RouteContent
route={route}
siteContent={siteContent}
games={games}
gamesError={gamesError}
mhwilds={mhwilds}
diablo4={diablo4}
filters={filters}
setFilters={setFilters}
t={t}
toolboxes={store.toolboxes}
links={store.links}
getGame={getGame}
getToolboxGame={getToolboxGame}
actions={actions}
storageUsage={store.storageUsage}
toastPosition={store.toastPosition}
setToastPosition={store.setToastPosition}
getModuleData={store.getModuleData}
updateToolbox={actions.updateToolbox}
updateModuleData={store.updateModuleData}
addImageFiles={actions.addImageFiles}
/>
{drawerGameId && (
<ToolboxDrawer
gameId={drawerGameId}
game={getGame(drawerGameId)}
siteContent={siteContent}
toolboxes={store.toolboxes}
links={store.links}
actions={actions}
storageUsage={store.storageUsage}
getModuleData={store.getModuleData}
updateToolbox={actions.updateToolbox}
updateModuleData={store.updateModuleData}
addImageFiles={actions.addImageFiles}
/>
)}
<AppOverlays
actions={actions}
confirmModal={confirmModal}
setConfirmModal={setConfirmModal}
createModal={createModal}
setCreateModal={setCreateModal}
linkModalGameId={linkModalGameId}
setLinkModalGameId={setLinkModalGameId}
setDrawerGameId={setDrawerGameId}
storageError={storageError}
setStorageError={setStorageError}
image={image}
setImage={setImage}
notifications={notifications}
dismissNotification={dismissNotification}
toastPosition={store.toastPosition}
getGame={getGame}
toolboxes={store.toolboxes}
links={store.links}
/>
</Shell>
);
}
createRoot(document.querySelector("#app")).render(<App />);