fix: Picker WebSocket auth, event handling, and status display

- Authenticate with JWT before subscribing to session events
- Use message.type instead of message.event (matches server format)
- Handle all new shard monitor events (room.connected, lobby.*,
  game.started, game.ended, room.disconnected)
- Replace never-set 'waiting' status with 'monitoring'
- Show monitoring indicator with live player count

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-20 11:47:19 -04:00
parent 336ba0e608
commit 65036a4e1b

View File

@@ -8,7 +8,7 @@ import { formatLocalTime } from '../utils/dateUtils';
import PopularityBadge from '../components/PopularityBadge'; import PopularityBadge from '../components/PopularityBadge';
function Picker() { function Picker() {
const { isAuthenticated, loading: authLoading } = useAuth(); const { isAuthenticated, loading: authLoading, token } = useAuth();
const navigate = useNavigate(); const navigate = useNavigate();
const [activeSession, setActiveSession] = useState(null); const [activeSession, setActiveSession] = useState(null);
@@ -977,8 +977,10 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame })
return () => clearInterval(interval); return () => clearInterval(interval);
}, [loadGames]); }, [loadGames]);
// Setup WebSocket connection for real-time player count updates // Setup WebSocket connection for real-time session updates
useEffect(() => { useEffect(() => {
if (!token) return;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.hostname}:${window.location.port || (window.location.protocol === 'https:' ? 443 : 80)}/api/sessions/live`; const wsUrl = `${protocol}//${window.location.hostname}:${window.location.port || (window.location.protocol === 'https:' ? 443 : 80)}/api/sessions/live`;
@@ -986,22 +988,33 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame })
const ws = new WebSocket(wsUrl); const ws = new WebSocket(wsUrl);
ws.onopen = () => { ws.onopen = () => {
console.log('[WebSocket] Connected for player count updates'); console.log('[WebSocket] Connected, authenticating...');
// Subscribe to session events ws.send(JSON.stringify({ type: 'auth', token }));
ws.send(JSON.stringify({
type: 'subscribe',
sessionId: parseInt(sessionId)
}));
}; };
ws.onmessage = (event) => { ws.onmessage = (event) => {
try { try {
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
// Handle player count updates if (message.type === 'auth_success') {
if (message.event === 'player-count.updated') { console.log('[WebSocket] Authenticated, subscribing to session', sessionId);
console.log('[WebSocket] Player count updated:', message.data); ws.send(JSON.stringify({ type: 'subscribe', sessionId: parseInt(sessionId) }));
// Reload games to get updated player counts return;
}
const reloadEvents = [
'room.connected',
'lobby.player-joined',
'lobby.updated',
'game.started',
'game.ended',
'room.disconnected',
'player-count.updated',
'game.added',
];
if (reloadEvents.includes(message.type)) {
console.log(`[WebSocket] ${message.type}:`, message.data);
loadGames(); loadGames();
} }
} catch (error) { } catch (error) {
@@ -1027,7 +1040,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame })
} catch (error) { } catch (error) {
console.error('[WebSocket] Failed to connect:', error); console.error('[WebSocket] Failed to connect:', error);
} }
}, [sessionId, loadGames]); }, [sessionId, token, loadGames]);
const handleUpdateStatus = async (gameId, newStatus) => { const handleUpdateStatus = async (gameId, newStatus) => {
try { try {
@@ -1303,14 +1316,14 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame })
{/* Player Count Display */} {/* Player Count Display */}
{game.player_count_check_status && game.player_count_check_status !== 'not_started' && ( {game.player_count_check_status && game.player_count_check_status !== 'not_started' && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{game.player_count_check_status === 'waiting' && ( {game.player_count_check_status === 'monitoring' && !game.player_count && (
<span className="inline-flex items-center gap-1 text-xs bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 px-2 py-1 rounded"> <span className="inline-flex items-center gap-1 text-xs bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 px-2 py-1 rounded">
Waiting... 📡 Monitoring...
</span> </span>
)} )}
{game.player_count_check_status === 'checking' && ( {(game.player_count_check_status === 'checking' || (game.player_count_check_status === 'monitoring' && game.player_count)) && (
<span className="inline-flex items-center gap-1 text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded"> <span className="inline-flex items-center gap-1 text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded">
🔍 {game.player_count ? `${game.player_count} players (checking...)` : 'Checking...'} 📡 {game.player_count ? `${game.player_count} players` : 'Monitoring...'}
</span> </span>
)} )}
{game.player_count_check_status === 'completed' && game.player_count && ( {game.player_count_check_status === 'completed' && game.player_count && (
@@ -1406,7 +1419,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame })
</> </>
)} )}
{/* Stop button for active checks */} {/* Stop button for active checks */}
{isAuthenticated && (game.player_count_check_status === 'waiting' || game.player_count_check_status === 'checking') && ( {isAuthenticated && (game.player_count_check_status === 'monitoring' || game.player_count_check_status === 'checking') && (
<button <button
onClick={() => handleStopPlayerCountCheck(game.id)} onClick={() => handleStopPlayerCountCheck(game.id)}
className="text-xs text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400" className="text-xs text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400"