feat: écran choix voie du Dao — s'affiche avant le premier combat tactique
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 33s

This commit is contained in:
2026-03-25 01:33:19 +01:00
parent cae0ef5d57
commit 2001c867cb

View File

@@ -23,6 +23,19 @@ export function TurnCombatPage() {
const { data: monsters } = useQuery({ queryKey: ['monsters'], queryFn: combatApi.monsters }); const { data: monsters } = useQuery({ queryKey: ['monsters'], queryFn: combatApi.monsters });
const { data: zones } = useQuery({ queryKey: ['zones'], queryFn: combatApi.zones }); const { data: zones } = useQuery({ queryKey: ['zones'], queryFn: combatApi.zones });
const { data: spells } = useQuery({ queryKey: ['turnSpells'], queryFn: turnCombatApi.unlockedSpells }); const { data: spells } = useQuery({ queryKey: ['turnSpells'], queryFn: turnCombatApi.unlockedSpells });
const { data: daoPaths } = useQuery({ queryKey: ['daoPaths'], queryFn: turnCombatApi.dao });
const hasDaoPath = daoPaths && daoPaths.length > 0 && daoPaths.some((p: any) => p.isPrimary || p.is_primary);
const chooseDaoMut = useMutation({
mutationFn: (path: string) => turnCombatApi.chooseDaoPath(path),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['daoPaths'] });
qc.invalidateQueries({ queryKey: ['turnSpells'] });
toast.success('Voie du Dao choisie !');
},
onError: (err: Error) => toast.error(err.message),
});
const endurance = char?.enduranceCurrent ?? 0; const endurance = char?.enduranceCurrent ?? 0;
const canFight = endurance >= COMBAT_COST; const canFight = endurance >= COMBAT_COST;
@@ -65,6 +78,58 @@ export function TurnCombatPage() {
actionMut.mutate({ type, spellId }); actionMut.mutate({ type, spellId });
}; };
// ========== PHASE: CHOOSE DAO PATH ==========
if (!hasDaoPath) {
const paths = [
{ id: 'ecoute', name: 'Écoute', color: '#88c8e8', icon: '👁️', archetype: 'Le stratège',
desc: 'Perception du flux, chant offensif, ancrage mémoriel. Tu deviens ce que Gorn t\'a appris : observer, comprendre.',
spell: 'Perception du Flux (révèle faiblesses, +20% dégâts)' },
{ id: 'resonance', name: 'Résonance', color: '#f4c94e', icon: '💪', archetype: 'Le protecteur',
desc: 'Onde de choc, bouclier, contre-attaque. Tu deviens ce que Vell a appris : la vraie force protège.',
spell: 'Onde de Choc (dégâts AoE, Force ×1.5)' },
{ id: 'harmonie', name: 'Harmonie', color: '#3ddc84', icon: '🎵', archetype: 'L\'harmoniste',
desc: 'Chant apaisant, purge, soin d\'équipe. Tu deviens ce que Mira est : le chant qui guérit.',
spell: 'Chant Apaisant (soin Int ×2 + 10% HP max)' },
];
return (
<div>
<h2 style={{ margin: '0 0 0.5rem', color: '#d4af37', fontSize: 20 }}>Le Dao du Courant s'éveille</h2>
<p style={{ color: '#9ca3af', fontSize: 13, margin: '0 0 1.5rem', lineHeight: 1.6 }}>
Gorn est parti. Le Serment est prêté. Le courant coule en toi.<br />
<strong style={{ color: '#dce4f0' }}>Quelle voie du Dao vas-tu suivre ?</strong>
</p>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
{paths.map(p => (
<button
key={p.id}
onClick={() => chooseDaoMut.mutate(p.id)}
disabled={chooseDaoMut.isPending}
className="card"
style={{
padding: '1rem', cursor: 'pointer', border: '2px solid transparent',
textAlign: 'left', transition: 'border-color 0.2s',
}}
onMouseEnter={e => (e.currentTarget.style.borderColor = p.color)}
onMouseLeave={e => (e.currentTarget.style.borderColor = 'transparent')}
>
<div style={{ fontSize: 28, marginBottom: 8 }}>{p.icon}</div>
<div style={{ fontSize: 16, fontWeight: 700, color: p.color }}>{p.name}</div>
<div style={{ fontSize: 11, color: '#6b7a99', marginBottom: 8 }}>{p.archetype}</div>
<div style={{ fontSize: 12, color: '#9ca3af', lineHeight: 1.5, marginBottom: 10 }}>{p.desc}</div>
<div style={{ fontSize: 11, color: '#dce4f0', padding: '6px 8px', background: '#1e2535', borderRadius: 6 }}>
✨ Sort offert : {p.spell}
</div>
</button>
))}
</div>
<p style={{ color: '#6b7a99', fontSize: 11, marginTop: 12, textAlign: 'center' }}>
Tu pourras explorer les autres voies plus tard — ta voie principale progresse plus vite.
</p>
</div>
);
}
// ========== PHASE: SELECT ========== // ========== PHASE: SELECT ==========
if (phase === 'select') { if (phase === 'select') {
const monstersByZone = new Map<string, Monster[]>(); const monstersByZone = new Map<string, Monster[]>();