import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { characterApi, itemApi } from '../api/endpoints'; import { Bar } from '../components/Bar'; import { Zap, Heart, Star, Coins, Sword, Shield, BedDouble } from 'lucide-react'; const STATS = ['force', 'agilite', 'intelligence', 'chance', 'vitalite'] as const; const STAT_LABELS: Record = { force: 'Force', agilite: 'Agilité', intelligence: 'Intelligence', chance: 'Chance', vitalite: 'Vitalité', }; function CreateCharacter() { const qc = useQueryClient(); const [name, setName] = useState(''); const [pts, setPts] = useState>({ force:1, agilite:1, intelligence:1, chance:1, vitalite:1 }); const used = Object.values(pts).reduce((a, b) => a + b, 0) - 5; const remaining = 5 - used; const mut = useMutation({ mutationFn: () => characterApi.create(name, pts), onSuccess: () => qc.invalidateQueries({ queryKey: ['character'] }), }); const adjust = (stat: string, delta: number) => { const next = (pts[stat] ?? 1) + delta; if (next < 1 || next > 10) return; if (delta > 0 && remaining <= 0) return; setPts(p => ({ ...p, [stat]: next })); }; return (

Créer ton personnage

{remaining > 0 ? `${remaining} point${remaining > 1 ? 's' : ''} à répartir` : 'Tous les points répartis'}

setName(e.target.value)} style={{ marginBottom: '1rem' }} maxLength={30} />
{STATS.map(s => (
{STAT_LABELS[s]}
{pts[s]}
))}
{mut.isError &&

{(mut.error as Error).message}

}
); } function StatDistributor({ char }: { char: any }) { const qc = useQueryClient(); const [pts, setPts] = useState>({ force: 0, agilite: 0, intelligence: 0, chance: 0, vitalite: 0 }); const used = Object.values(pts).reduce((a, b) => a + b, 0); const remaining = (char.statPoints ?? 0) - used; const mut = useMutation({ mutationFn: () => characterApi.distributeStats(pts), onSuccess: () => { qc.invalidateQueries({ queryKey: ['character'] }); setPts({ force: 0, agilite: 0, intelligence: 0, chance: 0, vitalite: 0 }); }, }); const adjust = (stat: string, delta: number) => { const next = (pts[stat] ?? 0) + delta; if (next < 0) return; if (delta > 0 && remaining <= 0) return; setPts(p => ({ ...p, [stat]: next })); }; return (

Répartir {char.statPoints} point{char.statPoints > 1 ? 's' : ''} de stats

{remaining > 0 ? `${remaining} restant${remaining > 1 ? 's' : ''}` : 'Prêt à valider'}

{STATS.map(s => (
{STAT_LABELS[s]} ({char[s]})
0 ? '#3ddc84' : '#6b7a99', fontSize: 13 }}> {pts[s] > 0 ? `+${pts[s]}` : '0'}
))}
{mut.isError &&

{(mut.error as Error).message}

}
); } function CombatStatsPanel({ char }: { char: any }) { const { data: inventory } = useQuery({ queryKey: ['inventory'], queryFn: itemApi.inventory }); const weapon = inventory?.find((ci: any) => ci.equipped && ci.item.type === 'weapon'); const armor = inventory?.find((ci: any) => ci.equipped && ci.item.type === 'armor'); const weaponATK = weapon ? weapon.item.attackBonus + weapon.forgeLevel * 2 : 0; const armorDEF = armor ? armor.item.defenseBonus + armor.forgeLevel * 2 : 0; const baseDmg = 3 + weaponATK + Math.floor(char.force * 1.5); return (

Combat actuel

Attaque : {baseDmg} {weapon && ({weapon.item.name} {weapon.forgeLevel > 0 ? `+${weapon.forgeLevel}` : ''})}
Défense : {armorDEF} {armor && ({armor.item.name} {armor.forgeLevel > 0 ? `+${armor.forgeLevel}` : ''})}
Critique : {(5 + char.chance * 0.2).toFixed(1)}%
); } export function DashboardPage() { const qc = useQueryClient(); const { data: char, isLoading, isError } = useQuery({ queryKey: ['character'], queryFn: characterApi.me, retry: 1, }); const restMut = useMutation({ mutationFn: () => characterApi.rest(), onSuccess: () => qc.invalidateQueries({ queryKey: ['character'] }), }); if (isLoading) return
Chargement…
; if (isError || !char) return ; const xpNext = char.xpToNextLevel; const statPoints = char.statPoints ?? 0; const needsHeal = char.hpCurrent < char.hpMax; const endurance = char.enduranceCurrent; const REST_COST = 10; const COMBAT_COST = 5; const FORGE_COST = 10; const canRest = endurance >= REST_COST && needsHeal; return (
{/* Header perso */}
🐸

{char.name}

Niveau {char.level}
{char.gold} or {char.xp} / {xpNext} XP {statPoints > 0 && ( +{statPoints} pts à répartir )}
{/* Barres vitales */}

État

PV {char.hpCurrent} / {char.hpMax}
Endurance {endurance} / {char.enduranceMax}
XP {char.xp} / {xpNext}
{/* Budget endurance */}
⚡ Budget : {' '}{Math.floor(endurance / COMBAT_COST)} combats {' · '}{Math.floor(endurance / FORGE_COST)} forges {' · '}{Math.floor(endurance / REST_COST)} soins
{needsHeal && ( )} {needsHeal && !canRest && endurance < REST_COST && (

Endurance insuffisante pour les soins

)} {restMut.isError &&

{(restMut.error as Error).message}

}
{/* Stats */}

Statistiques

{STATS.map(s => (
{STAT_LABELS[s]} {char[s]}
))}
PV max {char.hpMax}
{/* Distributeur de stats */} {statPoints > 0 && (
)} {/* Équipement résumé */}
); }