fix: Sistema de votación de líder completamente refactorizado
- Timer de 10 segundos que se reinicia correctamente al cambiar de líder - Votación por mayoría calculada sobre votos emitidos, no total de jugadores - Si nadie vota, líder rechazado automáticamente - Alemanes pueden ver carta de sabotaje en misiones - Reset correcto de selectedTeam al cambiar de fase - Contador de votos fallidos incrementa correctamente - Logs mejorados para debugging Fixes: - Timer visual se reinicia con key basada en currentLeaderId - Facción verificada correctamente (Faction.ALEMANES vs 'spies') - forceResolveLeaderVote llama a resolución con votos actuales - selectedTeam se limpia al salir de TEAM_BUILDING
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import { GameState, GamePhase, Player, GAME_CONFIG } from '../../../shared/types';
|
||||
import { GameState, GamePhase, Player, GAME_CONFIG, Faction } from '../../../shared/types';
|
||||
import MissionReveal from './MissionReveal';
|
||||
import MissionResult from './MissionResult';
|
||||
|
||||
@@ -41,6 +41,13 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
|
||||
}
|
||||
}, [gameState.phase]);
|
||||
|
||||
// Reset selectedTeam cuando no estamos en TEAM_BUILDING o cambia el líder
|
||||
useEffect(() => {
|
||||
if (gameState.phase !== GamePhase.TEAM_BUILDING) {
|
||||
setSelectedTeam([]);
|
||||
}
|
||||
}, [gameState.phase, gameState.currentLeaderId]);
|
||||
|
||||
|
||||
const currentPlayer = gameState.players.find(p => p.id === currentPlayerId);
|
||||
const isLeader = gameState.currentLeaderId === currentPlayerId; // FIX: Usar currentLeaderId del estado
|
||||
@@ -368,9 +375,9 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
|
||||
¿Aceptas a <span className="text-yellow-400">{gameState.players.find(p => p.id === gameState.currentLeaderId)?.name}</span> como Líder?
|
||||
</div>
|
||||
|
||||
{/* Timer */}
|
||||
{/* Timer visual (solo muestra el tiempo, el servidor controla el timeout) */}
|
||||
{!gameState.leaderVotes?.[currentPlayerId] && (
|
||||
<VotingTimer onTimeout={() => actions.voteLeader(null)} />
|
||||
<VotingTimer key={gameState.currentLeaderId} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -547,8 +554,8 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
|
||||
</motion.div>
|
||||
</button>
|
||||
|
||||
{/* Carta de Sabotaje segundo (solo para espías) */}
|
||||
{currentPlayer?.faction === 'spies' && (
|
||||
{/* Carta de Sabotaje segundo (solo para alemanes) */}
|
||||
{currentPlayer?.faction === Faction.ALEMANES && (
|
||||
<button onClick={() => handleMissionVote(false)} className="group transition-opacity" style={{ opacity: missionVote !== null && missionVote !== false ? 0.5 : 1 }} disabled={missionVote !== null}>
|
||||
<motion.div
|
||||
className="w-64 h-96 bg-gradient-to-br from-red-600 to-red-900 rounded-2xl shadow-2xl border-4 border-red-400 flex flex-col items-center justify-center p-6 transform transition-all hover:scale-110 hover:-rotate-3 hover:shadow-red-500/50"
|
||||
@@ -563,8 +570,8 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* Carta de Sabotaje primero (solo para espías) */}
|
||||
{currentPlayer?.faction === 'spies' && (
|
||||
{/* Carta de Sabotaje primero (solo para alemanes) */}
|
||||
{currentPlayer?.faction === Faction.ALEMANES && (
|
||||
<button onClick={() => handleMissionVote(false)} className="group transition-opacity" style={{ opacity: missionVote !== null && missionVote !== false ? 0.5 : 1 }} disabled={missionVote !== null}>
|
||||
<motion.div
|
||||
className="w-64 h-96 bg-gradient-to-br from-red-600 to-red-900 rounded-2xl shadow-2xl border-4 border-red-400 flex flex-col items-center justify-center p-6 transform transition-all hover:scale-110 hover:-rotate-3 hover:shadow-red-500/50"
|
||||
@@ -713,18 +720,17 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
|
||||
);
|
||||
}
|
||||
|
||||
// Subcomponente para el Timer de Votación
|
||||
function VotingTimer({ onTimeout }: { onTimeout: () => void }) {
|
||||
// Subcomponente para el Timer de Votación (solo visual, el servidor controla el timeout real)
|
||||
function VotingTimer() {
|
||||
const [timeLeft, setTimeLeft] = useState(10);
|
||||
|
||||
useEffect(() => {
|
||||
if (timeLeft <= 0) {
|
||||
onTimeout();
|
||||
return;
|
||||
return; // El servidor se encargará de forzar la resolución
|
||||
}
|
||||
const interval = setInterval(() => setTimeLeft(t => t - 1), 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [timeLeft, onTimeout]);
|
||||
}, [timeLeft]);
|
||||
|
||||
return (
|
||||
<div className="absolute top-4 right-4 bg-red-600/80 text-white w-16 h-16 rounded-full flex items-center justify-center border-4 border-red-400 animate-pulse text-2xl font-bold font-mono">
|
||||
|
||||
Reference in New Issue
Block a user