diff --git a/client/src/config/globals.js b/client/src/config/globals.js index 5b374b8..6a46d43 100644 --- a/client/src/config/globals.js +++ b/client/src/config/globals.js @@ -9,7 +9,6 @@ export const globals = { ACCESS_CODE_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789', COMMANDS: { FETCH_GAME_STATE: 'fetchGameState', - GET_ENVIRONMENT: 'getEnvironment', START_GAME: 'startGame', PAUSE_TIMER: 'pauseTimer', RESUME_TIMER: 'resumeTimer', @@ -18,8 +17,7 @@ export const globals = { REVEAL_PLAYER: 'revealPlayer', TRANSFER_MODERATOR: 'transferModerator', CHANGE_NAME: 'changeName', - END_GAME: 'endGame', - FETCH_IN_PROGRESS_STATE: 'fetchInitialInProgressState' + END_GAME: 'endGame' }, STATUS: { LOBBY: 'lobby', diff --git a/client/src/modules/GameCreationStepManager.js b/client/src/modules/GameCreationStepManager.js index a425727..0e1c078 100644 --- a/client/src/modules/GameCreationStepManager.js +++ b/client/src/modules/GameCreationStepManager.js @@ -105,6 +105,10 @@ export class GameCreationStepManager { window.location = ('/game/' + res.content); } }).catch((e) => { + let button = document.getElementById("create-game"); + button.innerText = "Create Game"; + button.classList.remove('submitted'); + button.addEventListener('click', this.steps["4"].forwardHandler); if (e.status === 429) { toast('You\'ve sent this request too many times.', 'error', true, true, 6); } @@ -395,6 +399,9 @@ function showButtons (back, forward, forwardHandler, backHandler, builtGame = nu createButton.setAttribute('id', 'create-game'); createButton.classList.add('app-button'); createButton.addEventListener('click', () => { + createButton.removeEventListener('click', forwardHandler); + createButton.classList.add('submitted'); + createButton.innerText = 'Creating...' forwardHandler( builtGame.deck.filter((card) => card.quantity > 0), builtGame.hasTimer, diff --git a/client/src/modules/GameStateRenderer.js b/client/src/modules/GameStateRenderer.js index 188741a..474adfb 100644 --- a/client/src/modules/GameStateRenderer.js +++ b/client/src/modules/GameStateRenderer.js @@ -254,7 +254,7 @@ function renderPotentialMods (gameState, group, transferModHandlers, socket) { if ((member.out || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) { const container = document.createElement('div'); container.classList.add('potential-moderator'); - container.setAttribute("tabindex", "0"); + container.setAttribute('tabindex', '0'); container.dataset.pointer = member.id; container.innerText = member.name; transferModHandlers[member.id] = (e) => { diff --git a/client/src/scripts/game.js b/client/src/scripts/game.js index 9c1ac9a..1b9ce22 100644 --- a/client/src/scripts/game.js +++ b/client/src/scripts/game.js @@ -8,82 +8,105 @@ import { ModalManager } from '../modules/ModalManager.js'; import { stateBucket } from '../modules/StateBucket.js'; import { io } from 'socket.io-client'; import { injectNavbar } from '../modules/Navbar.js'; +import { XHRUtility } from '../modules/XHRUtility.js'; const game = () => { injectNavbar(); - const timerWorker = new Worker(new URL('../modules/Timer.js', import.meta.url)); - const socket = io('/in-game'); - socket.on('disconnect', () => { - toast('Disconnected. Attempting reconnect...', 'error', true, false); - }); - socket.on('connect', () => { - console.log('connect event fired'); - socket.emit(globals.COMMANDS.GET_ENVIRONMENT, function (returnedEnvironment) { - prepareGamePage(returnedEnvironment, socket, timerWorker); + XHRUtility.xhr( + '/api/games/environment', + 'GET', + null, + null + ) + .then((res) => { + joinGame(res); + }).catch((res) => { + toast(res.content, 'error', true); }); - }); }; -function prepareGamePage (environment, socket, timerWorker) { - let userId = UserUtility.validateAnonUserSignature(environment); +function joinGame (environmentResponse) { + let cookie = UserUtility.validateAnonUserSignature(environmentResponse.content); const splitUrl = window.location.href.split('/game/'); const accessCode = splitUrl[1]; if (/^[a-zA-Z0-9]+$/.test(accessCode) && accessCode.length === globals.ACCESS_CODE_LENGTH) { - socket.emit(globals.COMMANDS.FETCH_GAME_STATE, accessCode, userId, function (gameState) { - stateBucket.currentGameState = gameState; - document.querySelector('.spinner-container')?.remove(); - document.querySelector('.spinner-background')?.remove(); - - if (gameState === null) { - window.location = '/not-found?reason=' + encodeURIComponent('game-not-found'); - } else { - document.getElementById('game-content').innerHTML = templates.INITIAL_GAME_DOM; - toast('You are connected.', 'success', true, true, 2); - userId = gameState.client.cookie; - UserUtility.setAnonymousUserId(userId, environment); + XHRUtility.xhr( + '/api/games/' + accessCode + '/players', + 'PATCH', + null, + JSON.stringify({ cookie: cookie }) + ) + .then((res) => { + cookie = res.content; + UserUtility.setAnonymousUserId(res.content, environmentResponse.content); + const timerWorker = new Worker(new URL('../modules/Timer.js', import.meta.url)); + const socket = io('/in-game'); + const gameTimerManager = new GameTimerManager(stateBucket, socket); const gameStateRenderer = new GameStateRenderer(stateBucket, socket); - let gameTimerManager; - if (stateBucket.currentGameState.timerParams) { - gameTimerManager = new GameTimerManager(stateBucket, socket); + socket.on('disconnect', () => { + toast('Disconnected. Attempting reconnect...', 'error', true, false); + }); + socket.on('connect', () => { + prepareGamePage( + environmentResponse.content, + socket, + timerWorker, + cookie, + accessCode, + gameStateRenderer, + gameTimerManager + ); + }); + setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager); + }).catch((res) => { + if (res.status === 404) { + window.location = '/not-found?reason=' + encodeURIComponent('game-not-found'); + } else if (res.status >= 500) { + toast( + 'The server is experiencing problems. Please try again later', + 'error', + true + ); } - initializeGame(stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager); - - if (!gameState.client.hasEnteredName) { - document.getElementById('prompt').innerHTML = templates.NAME_CHANGE_MODAL; - document.getElementById('change-name-form').onsubmit = (e) => { - e.preventDefault(); - const name = document.getElementById('player-new-name').value; - if (validateName(name)) { - socket.emit(globals.COMMANDS.CHANGE_NAME, gameState.accessCode, { - name: name, - personId: gameState.client.id - }, (result) => { - switch (result) { - case 'taken': - toast('This name is already taken.', 'error', true, true, 8); - break; - case 'changed': - ModalManager.dispelModal('change-name-modal', 'change-name-modal-background'); - toast('Name set.', 'success', true, true, 5); - propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id); - processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker); - } - }); - } else { - toast('Name must be between 1 and 30 characters.', 'error', true, true, 8); - } - }; - } - } - }); - } else { - window.location = '/not-found?reason=' + encodeURIComponent('invalid-access-code'); + }); } } -function initializeGame (stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager) { - setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager); - processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker); +function prepareGamePage (environment, socket, timerWorker, cookie, accessCode, gameStateRenderer, gameTimerManager) { + socket.emit(globals.COMMANDS.FETCH_GAME_STATE, accessCode, cookie, function (gameState) { + stateBucket.currentGameState = gameState; + document.querySelector('.spinner-container')?.remove(); + document.querySelector('.spinner-background')?.remove(); + document.getElementById('game-content').innerHTML = templates.INITIAL_GAME_DOM; + toast('You are connected.', 'success', true, true, 2); + processGameState(stateBucket.currentGameState, cookie, socket, gameStateRenderer, gameTimerManager, timerWorker); + if (!gameState.client.hasEnteredName) { + document.getElementById('prompt').innerHTML = templates.NAME_CHANGE_MODAL; + document.getElementById('change-name-form').onsubmit = (e) => { + e.preventDefault(); + const name = document.getElementById('player-new-name').value; + if (validateName(name)) { + socket.emit(globals.COMMANDS.CHANGE_NAME, gameState.accessCode, { + name: name, + personId: gameState.client.id + }, (result) => { + switch (result) { + case 'taken': + toast('This name is already taken.', 'error', true, true, 8); + break; + case 'changed': + ModalManager.dispelModal('change-name-modal', 'change-name-modal-background'); + toast('Name set.', 'success', true, true, 5); + propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id); + processGameState(stateBucket.currentGameState, cookie, socket, gameStateRenderer, gameTimerManager, timerWorker); + } + }); + } else { + toast('Name must be between 1 and 30 characters.', 'error', true, true, 8); + } + }; + } + }); } function processGameState (currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker, refreshPrompt = true) { @@ -163,79 +186,72 @@ function displayClientInfo (name, userType) { } function setClientSocketHandlers (stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager) { - if (!socket.hasListeners(globals.EVENTS.PLAYER_JOINED)) { - socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => { - toast(player.name + ' joined!', 'success', false, true, 3); - stateBucket.currentGameState.people.push(player); - stateBucket.currentGameState.isFull = gameIsFull; + socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => { + toast(player.name + ' joined!', 'success', false, true, 3); + stateBucket.currentGameState.people.push(player); + stateBucket.currentGameState.isFull = gameIsFull; + gameStateRenderer.renderLobbyPlayers(); + if ( + gameIsFull + && ( + stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR + || stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR + ) + ) { + displayStartGamePromptForModerators(stateBucket.currentGameState, gameStateRenderer); + } + }); + + socket.on(globals.EVENTS.PLAYER_LEFT, (player) => { + removeStartGameFunctionalityIfPresent(gameStateRenderer); + toast(player.name + ' has left!', 'error', false, true, 3); + const index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id); + if (index >= 0) { + stateBucket.currentGameState.people.splice( + index, + 1 + ); gameStateRenderer.renderLobbyPlayers(); - if ( - gameIsFull - && ( - stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR - || stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR - ) - ) { - displayStartGamePromptForModerators(stateBucket.currentGameState, gameStateRenderer); - } - }); - } + } + }); - if (!socket.hasListeners(globals.EVENTS.PLAYER_LEFT)) { - socket.on(globals.EVENTS.PLAYER_LEFT, (player) => { - removeStartGameFunctionalityIfPresent(gameStateRenderer); - toast(player.name + ' has left!', 'error', false, true, 3); - const index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id); - if (index >= 0) { - stateBucket.currentGameState.people.splice( - index, - 1 + socket.on(globals.EVENTS.START_GAME, () => { + socket.emit( + globals.COMMANDS.FETCH_GAME_STATE, + stateBucket.currentGameState.accessCode, + stateBucket.currentGameState.client.cookie, + function (gameState) { + stateBucket.currentGameState = gameState; + processGameState( + stateBucket.currentGameState, + gameState.client.cookie, + socket, + gameStateRenderer, + gameTimerManager, + timerWorker ); - gameStateRenderer.renderLobbyPlayers(); } - }); - } + ); + }); - if (!socket.hasListeners(globals.EVENTS.START_GAME)) { - socket.on(globals.EVENTS.START_GAME, () => { - socket.emit( - globals.COMMANDS.FETCH_IN_PROGRESS_STATE, - stateBucket.currentGameState.accessCode, - stateBucket.currentGameState.client.cookie, - function (gameState) { - stateBucket.currentGameState = gameState; - processGameState( - stateBucket.currentGameState, - gameState.client.cookie, - socket, - gameStateRenderer, - gameTimerManager, - timerWorker - ); - } - ); - }); - } - if (!socket.hasListeners(globals.EVENTS.SYNC_GAME_STATE)) { - socket.on(globals.EVENTS.SYNC_GAME_STATE, () => { - socket.emit( - globals.COMMANDS.FETCH_IN_PROGRESS_STATE, - stateBucket.currentGameState.accessCode, - stateBucket.currentGameState.client.cookie, - function (gameState) { - stateBucket.currentGameState = gameState; - processGameState( - stateBucket.currentGameState, - gameState.client.cookie, - socket, - gameStateRenderer, - gameTimerManager, - timerWorker - ); - } - ); - }); - } + socket.on(globals.EVENTS.SYNC_GAME_STATE, () => { + socket.emit( + globals.COMMANDS.FETCH_GAME_STATE, + stateBucket.currentGameState.accessCode, + stateBucket.currentGameState.client.cookie, + function (gameState) { + stateBucket.currentGameState = gameState; + processGameState( + stateBucket.currentGameState, + gameState.client.cookie, + socket, + gameStateRenderer, + gameTimerManager, + timerWorker + ); + } + ); + }); if (timerWorker && gameTimerManager) { gameTimerManager.attachTimerSocketListeners(socket, timerWorker, gameStateRenderer); diff --git a/client/src/scripts/home.js b/client/src/scripts/home.js index 15cf119..8e2733c 100644 --- a/client/src/scripts/home.js +++ b/client/src/scripts/home.js @@ -21,7 +21,7 @@ function roomCodeIsValid (code) { function attemptToJoinGame (code) { XHRUtility.xhr( - '/api/games/availability/' + code.toLowerCase().trim(), + '/api/games/' + code.toLowerCase().trim() + 'availability', 'GET', null, null diff --git a/client/src/styles/GLOBAL.css b/client/src/styles/GLOBAL.css index 052a35c..cd568a3 100644 --- a/client/src/styles/GLOBAL.css +++ b/client/src/styles/GLOBAL.css @@ -11,10 +11,6 @@ th, thead, tr, tt, u, ul, var { border: 0; background: transparent; } -@font-face { - font-family: 'signika-negative'; - src: url("../webfonts/Diavlo_LIGHT_II_37.woff2") format("woff2"); -} @font-face { font-family: 'signika-negative'; @@ -164,6 +160,11 @@ button { border: 2px solid #8a1c1c !important; } +.submitted { + filter: opacity(0.5); + pointer-events: none; +} + .container { padding: 5px; border-radius: 3px; diff --git a/client/src/views/404.html b/client/src/views/404.html index 5e96291..358c0ce 100644 --- a/client/src/views/404.html +++ b/client/src/views/404.html @@ -1,68 +1,68 @@ -
- - -