fix: Corregir errores de linter y dependencias de React para Gitea
Some checks failed
CI/CD - Francia Ocupada (La Resistencia) / build-and-deploy (push) Failing after 5s

- Memoizar acciones en useSocket (useMemo)
- Memoizar funciones en useSessionStorage (useCallback)
- Completar dependency arrays en page.tsx y dashboard/page.tsx
- Resolver advertencias de 'exhaustive-deps' para asegurar builds limpios
This commit is contained in:
Resistencia Dev
2025-12-22 18:50:02 +01:00
parent 3ac48e50fb
commit e953babdb8
4 changed files with 64 additions and 83 deletions

View File

@@ -46,7 +46,7 @@ export default function Dashboard() {
socket.off('admin_action_success'); socket.off('admin_action_success');
}; };
} }
}, [isAuthenticated, socket]); }, [isAuthenticated, socket, setActiveGames, setGameHistory]);
const handleLogin = (e: React.FormEvent) => { const handleLogin = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
@@ -308,7 +308,7 @@ export default function Dashboard() {
</div> </div>
</div> </div>
<div className={`text-[9px] font-black uppercase px-2 py-1 rounded shadow-sm ${entry.winner === 'resistance' ? 'bg-green-500/20 text-green-500' : <div className={`text-[9px] font-black uppercase px-2 py-1 rounded shadow-sm ${entry.winner === 'resistance' ? 'bg-green-500/20 text-green-500' :
entry.winner === 'spies' ? 'bg-red-500/20 text-red-500' : 'bg-gray-700/20 text-gray-500' entry.winner === 'spies' ? 'bg-red-500/20 text-red-500' : 'bg-gray-700/20 text-gray-500'
}`}> }`}>
{entry.winner ? (entry.winner === 'resistance' ? 'RES' : 'SPIES') : 'LOGOUT'} {entry.winner ? (entry.winner === 'resistance' ? 'RES' : 'SPIES') : 'LOGOUT'}
</div> </div>

View File

@@ -55,7 +55,7 @@ export default function Home() {
setHasReconnected(true); setHasReconnected(true);
} }
}, [session, isConnected, hasReconnected]); }, [session, isConnected, hasReconnected, actions, setPlayerName, setFullPlayerName, setView, setHasReconnected]);
// Efecto para cambiar a vista de juego cuando el servidor nos une // Efecto para cambiar a vista de juego cuando el servidor nos une
useEffect(() => { useEffect(() => {
@@ -71,7 +71,7 @@ export default function Home() {
updateSession({ currentView: 'lobby', roomId: undefined }); updateSession({ currentView: 'lobby', roomId: undefined });
} }
} }
}, [gameState, view, hasReconnected]); }, [gameState, view, hasReconnected, updateSession, setView]);
// Listener para errores de socket que deben expulsar al lobby // Listener para errores de socket que deben expulsar al lobby
useEffect(() => { useEffect(() => {
@@ -88,7 +88,7 @@ export default function Home() {
return () => { return () => {
socket.off('error', handleError); socket.off('error', handleError);
}; };
}, [socket, updateSession]); }, [socket, updateSession, setView]);
const handleLogin = (e: React.FormEvent) => { const handleLogin = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'; import { useState, useEffect, useCallback } from 'react';
interface SessionData { interface SessionData {
playerName: string; playerName: string;
@@ -25,24 +25,26 @@ export function useSessionStorage() {
}, []); }, []);
// Guardar sesión // Guardar sesión
const saveSession = (data: SessionData) => { const saveSession = useCallback((data: SessionData) => {
localStorage.setItem('resistencia_session', JSON.stringify(data)); localStorage.setItem('resistencia_session', JSON.stringify(data));
setSession(data); setSession(data);
}; }, []);
// Actualizar sesión parcialmente // Actualizar sesión parcialmente
const updateSession = (partial: Partial<SessionData>) => { const updateSession = useCallback((partial: Partial<SessionData>) => {
if (session) { setSession(prev => {
const updated = { ...session, ...partial }; if (!prev) return null;
saveSession(updated); const updated = { ...prev, ...partial };
} localStorage.setItem('resistencia_session', JSON.stringify(updated));
}; return updated;
});
}, []);
// Limpiar sesión // Limpiar sesión
const clearSession = () => { const clearSession = useCallback(() => {
localStorage.removeItem('resistencia_session'); localStorage.removeItem('resistencia_session');
setSession(null); setSession(null);
}; }, []);
return { return {
session, session,

View File

@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState, useMemo } from 'react';
import { io, Socket } from 'socket.io-client'; import { io, Socket } from 'socket.io-client';
import { GameState, Player } from '../../../shared/types'; import { GameState } from '../../../shared/types';
const SOCKET_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const SOCKET_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
@@ -35,25 +35,23 @@ export const useSocket = () => {
}); });
// Manejar propio unirse a partida // Manejar propio unirse a partida
socketInstance.on('game_joined', ({ roomId, state }) => { socketInstance.on('game_joined', ({ state }) => {
setGameState(state); setGameState(state);
// Podríamos guardar el roomId en localStorage o similar si quisiéramos persistencia
}); });
socketInstance.on('error', (msg: string) => { socketInstance.on('error', (msg: string) => {
alert(msg); // Simple error handling for now alert(msg);
}); });
// Manejar finalización de partida por el host // Manejar finalización de partida por el host
socketInstance.on('game_finalized', () => { socketInstance.on('game_finalized', () => {
console.log('La partida ha sido finalizada por el host'); console.log('La partida ha sido finalizada por el host');
setGameState(null); // Resetear estado para volver al lobby setGameState(null);
}); });
// Manejar cuando un jugador abandona la partida // Manejar cuando un jugador abandona la partida
socketInstance.on('player_left_game', ({ playerName }: { playerName: string }) => { socketInstance.on('player_left_game', ({ playerName }: { playerName: string }) => {
console.log(`${playerName} ha abandonado la partida`); console.log(`${playerName} ha abandonado la partida`);
// El servidor ya habrá cerrado la partida, solo mostramos mensaje
}); });
setSocket(socketInstance); setSocket(socketInstance);
@@ -63,71 +61,52 @@ export const useSocket = () => {
}; };
}, []); }, []);
// Funciones helper para enviar acciones const actions = useMemo(() => ({
const createGame = (hostName: string, maxPlayers: number, password?: string) => { createGame: (hostName: string, maxPlayers: number, password?: string) => {
socket?.emit('create_game', { hostName, maxPlayers, password }); socket?.emit('create_game', { hostName, maxPlayers, password });
}; },
joinGame: (roomId: string, playerName: string, password?: string) => {
const joinGame = (roomId: string, playerName: string, password?: string) => { socket?.emit('join_game', { roomId, playerName, password });
socket?.emit('join_game', { roomId, playerName, password }); },
}; refreshRooms: () => {
socket?.emit('get_rooms');
const refreshRooms = () => { },
socket?.emit('get_rooms'); startGame: () => {
}; socket?.emit('start_game', { roomId: gameState?.roomId });
},
const startGame = () => { proposeTeam: (teamIds: string[]) => {
socket?.emit('start_game', { roomId: gameState?.roomId }); socket?.emit('propose_team', { roomId: gameState?.roomId, teamIds });
}; },
voteTeam: (approve: boolean) => {
const proposeTeam = (teamIds: string[]) => { socket?.emit('vote_team', { roomId: gameState?.roomId, approve });
socket?.emit('propose_team', { roomId: gameState?.roomId, teamIds }); },
}; voteMission: (success: boolean) => {
socket?.emit('vote_mission', { roomId: gameState?.roomId, success });
const voteTeam = (approve: boolean) => { },
socket?.emit('vote_team', { roomId: gameState?.roomId, approve }); voteLeader: (approve: boolean) => socket?.emit('vote_leader', { roomId: gameState?.roomId, approve }),
}; assassinKill: (targetId: string) => {
socket?.emit('assassin_kill', { roomId: gameState?.roomId, targetId });
const voteMission = (success: boolean) => { },
socket?.emit('vote_mission', { roomId: gameState?.roomId, success }); leaveGame: () => {
}; socket?.emit('leave_game', { roomId: gameState?.roomId });
},
const assassinKill = (targetId: string) => { reconnectSession: (sessionData: { playerName: string; roomId?: string }) => {
socket?.emit('assassin_kill', { roomId: gameState?.roomId, targetId }); socket?.emit('reconnect_session', sessionData);
}; },
finishIntro: () => socket?.emit('finish_intro', { roomId: gameState?.roomId }),
const leaveGame = () => { finishReveal: () => socket?.emit('finish_reveal', { roomId: gameState?.roomId }),
socket?.emit('leave_game', { roomId: gameState?.roomId }); finishRollCall: () => socket?.emit('finish_roll_call', { roomId: gameState?.roomId }),
}; finishMissionReveal: () => socket?.emit('finish_reveal', { roomId: gameState?.roomId }),
finishMissionResult: () => socket?.emit('finish_mission_result', { roomId: gameState?.roomId }),
const reconnectSession = (sessionData: { playerName: string; roomId?: string }) => { restartGame: () => socket?.emit('restart_game', { roomId: gameState?.roomId }),
socket?.emit('reconnect_session', sessionData); finalizeGame: () => socket?.emit('finalize_game', { roomId: gameState?.roomId })
}; }), [socket, gameState?.roomId]);
return { return {
socket, socket,
isConnected, isConnected,
gameState, gameState,
roomsList, roomsList,
actions: { actions
createGame,
joinGame,
refreshRooms,
startGame,
proposeTeam,
voteTeam,
voteMission,
voteLeader: (approve: boolean) => socket?.emit('vote_leader', { roomId: gameState?.roomId, approve }),
assassinKill,
leaveGame,
reconnectSession,
finishIntro: () => socket?.emit('finish_intro', { roomId: gameState?.roomId }),
finishReveal: () => socket?.emit('finish_reveal', { roomId: gameState?.roomId }),
finishRollCall: () => socket?.emit('finish_roll_call', { roomId: gameState?.roomId }),
finishMissionReveal: () => socket?.emit('finish_reveal', { roomId: gameState?.roomId }),
finishMissionResult: () => socket?.emit('finish_mission_result', { roomId: gameState?.roomId }),
restartGame: () => socket?.emit('restart_game', { roomId: gameState?.roomId }),
finalizeGame: () => socket?.emit('finalize_game', { roomId: gameState?.roomId })
}
}; };
}; };