170 lines
9.7 KiB
JavaScript
170 lines
9.7 KiB
JavaScript
const q = s => document.querySelector(s);
|
|
|
|
function qsParam(name){
|
|
const p = new URLSearchParams(window.location.search);
|
|
return p.get(name);
|
|
}
|
|
|
|
const gameId = qsParam('game');
|
|
console.log('[waiting.js] loaded - build: v2 -', { gameId, url: window.location.href });
|
|
if(!gameId){ document.body.innerHTML = '<p>Game ID missing in URL</p>'; }
|
|
else {
|
|
// Query explicit backend first to avoid interpreting same-origin static 404 as game-deleted
|
|
fetch(`http://localhost:4000/api/game/${gameId}`).then(r => {
|
|
if(r.status === 404){
|
|
// game deleted — eject user to lobby and clear session state
|
|
sessionStorage.removeItem(`playerId:${gameId}`);
|
|
alert('La partie a été supprimée par l\'hôte. Retour au lobby.');
|
|
window.location.href = 'index.html';
|
|
throw new Error('game deleted');
|
|
}
|
|
if(!r.ok) throw new Error('no api');
|
|
return r.json();
|
|
}).then(g => {
|
|
q('#wait-game-id').textContent = g.name || '';
|
|
renderWaitingPlayers(g.players||[]);
|
|
// if game already started, redirect immediately to the game page
|
|
if (g.started) { window.location.href = `game.html?game=${g.id}`; return; }
|
|
// display current player nick and color if we have a playerId
|
|
const stored = sessionStorage.getItem(`playerId:${gameId}`);
|
|
if(stored){
|
|
const me = (g.players||[]).find(p=>p.id===stored);
|
|
if(me){ q('#player-nick').textContent = 'Vous'; q('#player-color').textContent = me.colorChoice || '-'; }
|
|
}
|
|
// owner-only start button
|
|
const ownerId = g.players && g.players[0] && g.players[0].id;
|
|
if(ownerId && stored && ownerId === stored){ q('#start-btn')?.classList.remove('hidden'); } else { q('#start-btn')?.classList.add('hidden'); }
|
|
// disable start button unless there are at least 2 players
|
|
const startBtn = q('#start-btn');
|
|
if(startBtn){ if((g.players||[]).length < 2){ startBtn.disabled = true; } else { startBtn.disabled = false; } }
|
|
if(!g.started) startPolling(gameId);
|
|
// try to connect socket.io for instant updates and identification
|
|
tryConnectSocket(gameId);
|
|
}).catch(()=>{
|
|
// fallback: attempt same-origin server, then localStorage
|
|
fetch(`/api/game/${gameId}`).then(r=>{
|
|
if(r.status === 404){ sessionStorage.removeItem(`playerId:${gameId}`); alert('La partie a été supprimée par l\'hôte. Retour au lobby.'); window.location.href = 'index.html'; throw new Error('game deleted'); }
|
|
if(!r.ok) throw new Error('no api');
|
|
return r.json();
|
|
}).then(g=>{
|
|
q('#wait-game-id').textContent = g.name || '';
|
|
renderWaitingPlayers(g.players||[]);
|
|
// if game already started, redirect immediately to the game page
|
|
if (g.started) { window.location.href = `game.html?game=${g.id}`; return; }
|
|
const stored = sessionStorage.getItem(`playerId:${gameId}`);
|
|
if(stored){ const me = (g.players||[]).find(p=>p.id===stored); if(me){ q('#player-nick').textContent = 'Vous'; q('#player-color').textContent = me.colorChoice || '-'; } }
|
|
const ownerId = g.players && g.players[0] && g.players[0].id;
|
|
if(ownerId && stored && ownerId === stored){ q('#start-btn')?.classList.remove('hidden'); } else { q('#start-btn')?.classList.add('hidden'); }
|
|
// disable start button unless there are at least 2 players
|
|
const startBtn = q('#start-btn');
|
|
if(startBtn){ if((g.players||[]).length < 2){ startBtn.disabled = true; } else { startBtn.disabled = false; } }
|
|
if(!g.started) startPolling(gameId);
|
|
tryConnectSocket(gameId);
|
|
}).catch(()=>{
|
|
const all = JSON.parse(localStorage.getItem('games') || '[]');
|
|
const g = all.find(x=>x.id === gameId);
|
|
if(g){ q('#wait-game-id').textContent = g.name || ''; renderWaitingPlayers(g.players || []); } else { startPolling(gameId); }
|
|
});
|
|
});
|
|
}
|
|
|
|
// Socket.IO wiring: connect to backend explicitly and join game room; send identify so server can map socket->player
|
|
function tryConnectSocket(gameId){
|
|
if(typeof io === 'undefined') return; // socket lib not loaded
|
|
// connect explicitly to backend to avoid same-origin static server 404
|
|
const sock = io('http://localhost:4000', { transports: ['websocket', 'polling'] });
|
|
sock.on('connect', () => {
|
|
console.log('socket connected from waiting page', sock.id);
|
|
sock.emit('join-game', gameId);
|
|
const stored = sessionStorage.getItem(`playerId:${gameId}`) || (()=>{ const all = JSON.parse(localStorage.getItem('games') || '[]'); const g = all.find(x=>x.id===gameId); return g && g.players && g.players[0] && g.players[0].id; })();
|
|
if(stored) sock.emit('identify', { gameId, playerId: stored });
|
|
});
|
|
sock.on('reconnect', (attempt) => { console.log('waiting socket reconnected', attempt); });
|
|
sock.on('game-deleted', (payload) => {
|
|
if(payload && payload.gameId === gameId){
|
|
sessionStorage.removeItem(`playerId:${gameId}`);
|
|
alert('La partie a été supprimée par l\'hôte. Retour au lobby.');
|
|
window.location.href = 'index.html';
|
|
}
|
|
});
|
|
sock.on('player-update', (g) => {
|
|
if(!g) return;
|
|
console.log('[waiting.js] player-update received', g);
|
|
renderWaitingPlayers(g.players||[]);
|
|
// update start button visibility/disabled state live
|
|
try { console.log('[waiting.js] updating start button'); updateStartButton(g); } catch(e){ console.error('updateStartButton error', e); }
|
|
});
|
|
sock.on('game-start', (g) => {
|
|
if(!g) return;
|
|
// redirect to game view when started
|
|
window.location.href = `game.html?game=${g.id}`;
|
|
});
|
|
sock.on('connect_error', (err) => {
|
|
console.warn('socket connect error', err);
|
|
// leave polling as fallback
|
|
});
|
|
}
|
|
|
|
function updateStartButton(g){
|
|
const stored = sessionStorage.getItem(`playerId:${gameId}`);
|
|
const ownerId = g.players && g.players[0] && g.players[0].id;
|
|
const startBtn = q('#start-btn');
|
|
console.log('[waiting.js] updateStartButton values', { ownerId, stored, playersLength: (g.players||[]).length, startBtnExists: !!startBtn });
|
|
if(ownerId && stored && ownerId === stored){ startBtn?.classList.remove('hidden'); } else { startBtn?.classList.add('hidden'); }
|
|
if(startBtn){ startBtn.disabled = ((g.players||[]).length < 2); }
|
|
}
|
|
|
|
function renderWaitingPlayers(players){
|
|
const ul = q('#wait-players'); ul.innerHTML = '';
|
|
if(!players || players.length === 0) ul.innerHTML = '<li>Aucun joueur</li>';
|
|
(players||[]).forEach((p, i) => { const li = document.createElement('li'); li.textContent = `Joueur ${i+1} (${p.colorAssigned || p.colorChoice})`; ul.appendChild(li); });
|
|
}
|
|
|
|
let poll = null;
|
|
function startPolling(id){
|
|
if(poll) clearInterval(poll);
|
|
poll = setInterval(()=>{
|
|
// Prefer explicit backend host to avoid same-origin 404 from static server
|
|
fetch(`http://localhost:4000/api/game/${id}`).then(r=>{ if(!r.ok) throw new Error('no api'); return r.json(); }).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{
|
|
// fallback to same-origin if backend not reachable
|
|
fetch(`/api/game/${id}`).then(r=>{ if(!r.ok) throw new Error('no api'); return r.json(); }).then(g=>{ renderWaitingPlayers(g.players||[]); if(g.started){ clearInterval(poll); window.location.href = `game.html?game=${g.id}`; } }).catch(()=>{});
|
|
});
|
|
}, 1000);
|
|
}
|
|
|
|
// Join handled from lobby; waiting room doesn't provide a join button
|
|
|
|
q('#start-btn')?.addEventListener('click', () => {
|
|
// force explicit backend host (no fallback) so request always goes to :4000
|
|
console.log('[waiting] start click - POST to http://localhost:4000/api/start', { gameId });
|
|
fetch('http://localhost:4000/api/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ id: gameId }) })
|
|
.then(async (r) => {
|
|
const body = await r.json().catch(()=>({}));
|
|
if(!r.ok) throw body;
|
|
return body;
|
|
})
|
|
.then((resp)=>{ try { window.location.href = `game.html?game=${resp.game.id}`; } catch(e) { alert('Partie démarrée'); } })
|
|
.catch((err)=>{ const msg = (err && err.error) ? err.error : (typeof err === 'string' ? err : JSON.stringify(err)); alert('Impossible de démarrer: ' + msg); console.error('start error', err); });
|
|
});
|
|
|
|
q('#leave-btn')?.addEventListener('click', () => {
|
|
const stored = sessionStorage.getItem(`playerId:${gameId}`) || null;
|
|
const playerId = stored || (() => { const all = JSON.parse(localStorage.getItem('games') || '[]'); const g = all.find(x=>x.id===gameId); return g && g.players && g.players[0] && g.players[0].id; })();
|
|
if(!playerId){ alert('Impossible de déterminer votre identifiant de joueur pour quitter'); return; }
|
|
// prefer explicit backend host to avoid same-origin static server 404s
|
|
fetch(`http://localhost:4000/api/leave`, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ gameId, playerId }) })
|
|
.then(r=>{ if(!r.ok) throw new Error('leave failed'); return r.json(); }).then(resp=>{
|
|
if(resp.deleted){ alert('Vous étiez l\'hôte — la partie a été supprimée'); window.location.href = 'index.html'; }
|
|
else { alert('Vous avez quitté la partie'); window.location.href = 'index.html'; }
|
|
}).catch(()=>{
|
|
// fallback to same-origin in case backend is proxied
|
|
fetch('/api/leave', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ gameId, playerId }) })
|
|
.then(r=>{ if(!r.ok) throw new Error('leave failed'); return r.json(); }).then(resp=>{
|
|
if(resp.deleted){ alert('Vous étiez l\'hôte — la partie a été supprimée'); window.location.href = 'index.html'; }
|
|
else { alert('Vous avez quitté la partie'); window.location.href = 'index.html'; }
|
|
}).catch(err=>{
|
|
console.error('leave failed', err);
|
|
alert('Impossible de quitter la partie — le serveur est injoignable. Si le problème persiste, vérifiez que le backend tourne sur :4000.');
|
|
});
|
|
});
|
|
});
|