TurnManager stateless avec sessions en mémoire (TTL 10min). SpellSystem : 15 sorts (5 par voie du Dao), mana, cooldowns, buffs/debuffs. CompanionAI : Mira (heal/support) et Vell (tank/dps) — IA contextuelle. Monster AI : 3 profils (agressif, défensif, chaotique). Nouvelles entités : Spell, PlayerSpell, PlayerDaoPath. Character +mana. Monster +aiProfile +isBoss. Migration : 1743004800000-TurnCombatSystem. Frontend : TurnCombatPage (select/combat/result), sélecteur compagnon, barres HP/MP, log scrollable, sous-menu sorts avec cooldowns. Endpoints : 8 routes sous /combat/turn/ (start, action, session, spells, unlocked, unlock, dao, dao/choose). Combat simple (POST /combat/start) et grind ×5/×10 inchangés.
73 lines
3.3 KiB
TypeScript
73 lines
3.3 KiB
TypeScript
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { Toaster } from 'react-hot-toast';
|
|
import { AuthProvider, useAuth } from './context/AuthContext';
|
|
import { Layout } from './components/Layout';
|
|
import { LoginPage } from './pages/LoginPage';
|
|
import { AuthCallback } from './pages/AuthCallback';
|
|
import { DashboardPage } from './pages/DashboardPage';
|
|
import { CombatPage } from './pages/CombatPage';
|
|
import { TurnCombatPage } from './pages/TurnCombatPage';
|
|
import { InventoryPage } from './pages/InventoryPage';
|
|
import { CraftPage } from './pages/CraftPage';
|
|
import { ForgePage } from './pages/ForgePage';
|
|
import { QuestPage } from './pages/QuestPage';
|
|
import { AchievementsPage } from './pages/AchievementsPage';
|
|
import { ShopPage } from './pages/ShopPage';
|
|
import { GuidePage } from './pages/GuidePage';
|
|
import { NotFoundPage } from './pages/NotFoundPage';
|
|
|
|
const qc = new QueryClient({ defaultOptions: { queries: { retry: 1, staleTime: 30_000 } } });
|
|
|
|
function ProtectedLayout({ children }: { children: React.ReactNode }) {
|
|
const { user, loading } = useAuth();
|
|
if (loading) return (
|
|
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#6b7a99', fontSize: 14 }}>
|
|
Chargement…
|
|
</div>
|
|
);
|
|
if (!user) return <Navigate to="/login" replace />;
|
|
return <Layout>{children}</Layout>;
|
|
}
|
|
|
|
function AppRoutes() {
|
|
return (
|
|
<Routes>
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="/auth/callback" element={<AuthCallback />} />
|
|
<Route path="/guide" element={<GuidePage />} />
|
|
<Route path="/dashboard" element={<ProtectedLayout><DashboardPage /></ProtectedLayout>} />
|
|
<Route path="/quests" element={<ProtectedLayout><QuestPage /></ProtectedLayout>} />
|
|
<Route path="/combat" element={<ProtectedLayout><CombatPage /></ProtectedLayout>} />
|
|
<Route path="/combat/tactical" element={<ProtectedLayout><TurnCombatPage /></ProtectedLayout>} />
|
|
<Route path="/inventory" element={<ProtectedLayout><InventoryPage /></ProtectedLayout>} />
|
|
<Route path="/craft" element={<ProtectedLayout><CraftPage /></ProtectedLayout>} />
|
|
<Route path="/forge" element={<ProtectedLayout><ForgePage /></ProtectedLayout>} />
|
|
<Route path="/achievements" element={<ProtectedLayout><AchievementsPage /></ProtectedLayout>} />
|
|
<Route path="/shop" element={<ProtectedLayout><ShopPage /></ProtectedLayout>} />
|
|
<Route path="*" element={<NotFoundPage />} />
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<QueryClientProvider client={qc}>
|
|
<AuthProvider>
|
|
<BrowserRouter>
|
|
<AppRoutes />
|
|
</BrowserRouter>
|
|
</AuthProvider>
|
|
<Toaster
|
|
position="bottom-right"
|
|
toastOptions={{
|
|
duration: 3000,
|
|
style: { background: '#1e2535', color: '#dce4f0', border: '1px solid #2a3448', fontSize: 13 },
|
|
success: { iconTheme: { primary: '#3ddc84', secondary: '#1e2535' } },
|
|
error: { iconTheme: { primary: '#e84040', secondary: '#1e2535' }, duration: 4000 },
|
|
}}
|
|
/>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|