import { lazy, Suspense, useEffect, useMemo, useState, type ReactNode } from "react";
import { BASE_CLASS_IDS, classById } from "./app/characterCatalog";
import { useShellStore } from "./app/shellStore";
import { preloadAbilityCatalogsForClasses } from "./game/abilityCatalog";
import { useManastormAdminStore } from "./game/manastormAdminStore";
import { useAuthoritativeDualScreenSync, useForcedThorDisplays } from "./platform/useThorDualScreen";
import { LoginScreen } from "./ui/LoginScreen";
import { OnlineGroupCoordinator } from "./app/OnlineGroupCoordinator";
const GameRuntime = lazy(() => import("./GameRuntime"));
const CharacterCreateScreen = lazy(() => import("./ui/CharacterCreateScreen").then((module) => ({ default: module.CharacterCreateScreen })));
const CharacterSelectScreen = lazy(() => import("./ui/CharacterSelectScreen").then((module) => ({ default: module.CharacterSelectScreen })));
const ClassHallScreen = lazy(() => import("./ui/ClassHallScreen").then((module) => ({ default: module.ClassHallScreen })));
const DungeonSelectScreen = lazy(() => import("./ui/DungeonSelectScreen").then((module) => ({ default: module.DungeonSelectScreen })));
const MainMenuScreen = lazy(() => import("./ui/MainMenuScreen").then((module) => ({ default: module.MainMenuScreen })));
const ManastormSelectScreen = lazy(() => import("./ui/ManastormSelectScreen").then((module) => ({ default: module.ManastormSelectScreen })));
const ArenaSelectScreen = lazy(() => import("./ui/ArenaSelectScreen").then((module) => ({ default: module.ArenaSelectScreen })));
const ArenaRuntime = lazy(() => import("./ArenaRuntime"));
const GmAdminScreen = lazy(() => import("./ui/GmAdminScreen").then((module) => ({ default: module.GmAdminScreen })));
function ShellTransition() {
return
HMOpening expeditionPreparing the next screen...
;
}
function RuntimeCatalogGate({ children }: { readonly children: ReactNode }) {
const character = useShellStore((state) => (
state.characters.find((candidate) => candidate.id === state.selectedCharacterId) ?? null
));
const classIds = useMemo(() => {
if (!character) return [];
const definition = classById(character.classId);
if (definition.mode === "conquest") return [...BASE_CLASS_IDS, character.classId];
return [character.classId, ...(character.secondaryClassId ? [character.secondaryClassId] : [])];
}, [character]);
const requestKey = classIds.join(":");
const [loadedKey, setLoadedKey] = useState("");
const [failedKey, setFailedKey] = useState("");
useEffect(() => {
if (!requestKey) return;
let active = true;
setFailedKey("");
void preloadAbilityCatalogsForClasses(classIds).then(() => {
if (active) setLoadedKey(requestKey);
}).catch(() => {
if (active) setFailedKey(requestKey);
});
return () => { active = false; };
}, [classIds, requestKey]);
if (!requestKey || loadedKey === requestKey) return children;
if (failedKey === requestKey) {
return !Catalog unavailableReload the app to retry loading combat data.
;
}
return ;
}
export default function App() {
useForcedThorDisplays();
useAuthoritativeDualScreenSync();
const phase = useShellStore((state) => state.phase);
const session = useShellStore((state) => state.session);
const refreshManastormConfig = useManastormAdminStore((state) => state.refresh);
useEffect(() => {
void refreshManastormConfig(session);
}, [refreshManastormConfig, session]);
let screen = null;
if (phase === "login") screen = ;
else if (phase === "characters") screen = }>;
else if (phase === "create-character") screen = }>;
else if (phase === "main-menu") screen = }>;
else if (phase === "class-hall") screen = }>;
else if (phase === "dungeons") screen = }>;
else if (phase === "manastorms") screen = }>;
else if (phase === "arenas") screen = }>;
else if (phase === "arena-game") screen = }>;
else if (phase === "gm-admin") screen = }>;
else if (phase === "game") screen = }>;
const requiresRuntimeCatalog = !["login", "characters", "create-character"].includes(phase);
return <>{requiresRuntimeCatalog ? {screen} : screen}>;
}