built out rest of functionality; add placeholder when there are no custom roles

This commit is contained in:
AlecM33
2023-08-16 13:43:22 -04:00
parent 25fb043292
commit 1d22aebbb9
10 changed files with 117 additions and 49 deletions

View File

@@ -96,6 +96,7 @@ export const LOBBY_EVENTS = function () {
EVENT_IDS.ADD_SPECTATOR, EVENT_IDS.ADD_SPECTATOR,
EVENT_IDS.KICK_PERSON, EVENT_IDS.KICK_PERSON,
EVENT_IDS.UPDATE_GAME_ROLES, EVENT_IDS.UPDATE_GAME_ROLES,
EVENT_IDS.UPDATE_GAME_TIMER,
EVENT_IDS.LEAVE_ROOM EVENT_IDS.LEAVE_ROOM
]; ];
}; };

View File

@@ -54,7 +54,7 @@ export class GameCreationStepManager {
let hours = parseInt(document.getElementById('game-hours').value); let hours = parseInt(document.getElementById('game-hours').value);
let minutes = parseInt(document.getElementById('game-minutes').value); let minutes = parseInt(document.getElementById('game-minutes').value);
hours = this.standardizeNumberInput(hours); hours = this.standardizeNumberInput(hours);
minutes = this.standardizeNumberInput(minutes) minutes = this.standardizeNumberInput(minutes);
if (this.timerIsValid(hours, minutes)) { if (this.timerIsValid(hours, minutes)) {
if (this.hasTimer(hours, minutes)) { if (this.hasTimer(hours, minutes)) {
this.currentGame.hasTimer = true; this.currentGame.hasTimer = true;
@@ -323,7 +323,7 @@ export class GameCreationStepManager {
document.getElementById(containerId).appendChild(div); document.getElementById(containerId).appendChild(div);
} }
timerIsValid(hours, minutes) { timerIsValid (hours, minutes) {
let valid = true; let valid = true;
if (hours === null && minutes === null) { if (hours === null && minutes === null) {
@@ -338,15 +338,14 @@ export class GameCreationStepManager {
valid = minutes <= PRIMITIVES.MAX_MINUTES; valid = minutes <= PRIMITIVES.MAX_MINUTES;
} }
return valid; return valid;
} }
hasTimer(hours, minutes) { hasTimer (hours, minutes) {
return hours !== null || minutes !== null; return hours !== null || minutes !== null;
} }
standardizeNumberInput(input) { standardizeNumberInput (input) {
return (isNaN(input) || input === 0) ? null : input; return (isNaN(input) || input === 0) ? null : input;
} }
} }

View File

@@ -166,6 +166,7 @@ export class RoleBox {
}; };
displayDefaultRoles = (selectEl) => { displayDefaultRoles = (selectEl) => {
document.querySelector('#custom-role-placeholder')?.remove();
document.querySelectorAll('#role-select .default-role, #role-select .custom-role').forEach(e => e.remove()); document.querySelectorAll('#role-select .default-role, #role-select .custom-role').forEach(e => e.remove());
this.categoryTransition.play(); this.categoryTransition.play();
for (let i = 0; i < this.defaultRoles.length; i ++) { for (let i = 0; i < this.defaultRoles.length; i ++) {
@@ -184,9 +185,21 @@ export class RoleBox {
this.addRoleEventListeners(selectEl, true, true, false, false, false); this.addRoleEventListeners(selectEl, true, true, false, false, false);
}; };
displayCustomRolePlaceHolder = () => {
const placeholder = document.createElement('div');
placeholder.setAttribute('id', 'custom-role-placeholder');
placeholder.innerText = 'Create a role with the button below.';
document.getElementById('role-select').appendChild(placeholder);
};
displayCustomRoles = (selectEl) => { displayCustomRoles = (selectEl) => {
document.querySelector('#custom-role-placeholder')?.remove();
document.querySelectorAll('#role-select .default-role, #role-select .custom-role').forEach(e => e.remove()); document.querySelectorAll('#role-select .default-role, #role-select .custom-role').forEach(e => e.remove());
this.categoryTransition.play(); this.categoryTransition.play();
if (this.customRoles.length === 0) {
this.displayCustomRolePlaceHolder();
return;
}
this.customRoles.sort((a, b) => { this.customRoles.sort((a, b) => {
if (a.team !== b.team) { if (a.team !== b.team) {
return a.team === ALIGNMENT.GOOD ? -1 : 1; return a.team === ALIGNMENT.GOOD ? -1 : 1;

View File

@@ -1,5 +1,5 @@
import { QRCode } from '../../third_party/qrcode.js'; import { QRCode } from '../../third_party/qrcode.js';
import {cancelCurrentToast, toast} from '../../front_end_components/Toast.js'; import { toast } from '../../front_end_components/Toast.js';
import { EVENT_IDS, PRIMITIVES, SOCKET_EVENTS, USER_TYPE_ICONS, USER_TYPES } from '../../../config/globals.js'; import { EVENT_IDS, PRIMITIVES, SOCKET_EVENTS, USER_TYPE_ICONS, USER_TYPES } from '../../../config/globals.js';
import { HTMLFragments } from '../../front_end_components/HTMLFragments.js'; import { HTMLFragments } from '../../front_end_components/HTMLFragments.js';
import { Confirmation } from '../../front_end_components/Confirmation.js'; import { Confirmation } from '../../front_end_components/Confirmation.js';
@@ -70,16 +70,22 @@ export class Lobby {
document.getElementById('game-content').style.display = 'none'; document.getElementById('game-content').style.display = 'none';
document.body.appendChild(timerEditContainer); document.body.appendChild(timerEditContainer);
document.body.appendChild(timerEditContainerBackground); document.body.appendChild(timerEditContainerBackground);
this.gameCreationStepManager
.renderTimerStep(this.stateBucket.currentGameState, '2', this.stateBucket.currentGameState, this.gameCreationStepManager.steps);
const timerEditPrompt = document.createElement('div'); const timerEditPrompt = document.createElement('div');
timerEditPrompt.setAttribute('id', 'timer-edit-prompt'); timerEditPrompt.setAttribute('id', 'timer-edit-prompt');
timerEditPrompt.innerHTML = HTMLFragments.TIMER_EDIT_BUTTONS; timerEditPrompt.innerHTML = HTMLFragments.TIMER_EDIT_BUTTONS;
this.gameCreationStepManager.steps['3'].forwardHandler = (e) => {
e.preventDefault();
if (e.type === 'click' || e.code === 'Enter') {
timerEditPrompt.querySelector('#save-timer-changes-button')?.click();
}
};
this.gameCreationStepManager
.renderTimerStep('mid-game-timer-editor', '3', this.stateBucket.currentGameState, this.gameCreationStepManager.steps);
timerEditPrompt.querySelector('#save-timer-changes-button').addEventListener('click', () => { timerEditPrompt.querySelector('#save-timer-changes-button').addEventListener('click', () => {
let hours = parseInt(document.getElementById('game-hours').value); let hours = parseInt(document.getElementById('game-hours').value);
let minutes = parseInt(document.getElementById('game-minutes').value); let minutes = parseInt(document.getElementById('game-minutes').value);
hours = this.gameCreationStepManager.standardizeNumberInput(hours); hours = this.gameCreationStepManager.standardizeNumberInput(hours);
minutes = this.gameCreationStepManager.standardizeNumberInput(minutes) minutes = this.gameCreationStepManager.standardizeNumberInput(minutes);
if (this.gameCreationStepManager.timerIsValid(hours, minutes)) { if (this.gameCreationStepManager.timerIsValid(hours, minutes)) {
let hasTimer, timerParams; let hasTimer, timerParams;
if (this.gameCreationStepManager.hasTimer(hours, minutes)) { if (this.gameCreationStepManager.hasTimer(hours, minutes)) {
@@ -116,7 +122,7 @@ export class Lobby {
}); });
timerEditContainer.appendChild(timerEditPrompt); timerEditContainer.appendChild(timerEditPrompt);
} };
this.editRolesHandler = (e) => { this.editRolesHandler = (e) => {
e.preventDefault(); e.preventDefault();
@@ -194,11 +200,17 @@ export class Lobby {
'Participants (' + inLobbyCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)'; 'Participants (' + inLobbyCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)';
} }
populateHeader () { setTimer () {
const timeString = getTimeString(this.stateBucket.currentGameState); const timeString = getTimeString(this.stateBucket.currentGameState);
const time = this.container.querySelector('#game-time'); const time = this.container.querySelector('#game-time');
time.innerText = timeString; time.innerText = timeString;
return timeString;
}
populateHeader () {
const timeString = this.setTimer();
const link = this.setLink(timeString); const link = this.setLink(timeString);
this.setPlayerCount(); this.setPlayerCount();
@@ -293,6 +305,13 @@ export class Lobby {
this.setPlayerCount(); this.setPlayerCount();
}); });
this.socket.on(EVENT_IDS.UPDATE_GAME_TIMER, (hasTimer, timerParams) => {
this.stateBucket.currentGameState.hasTimer = hasTimer;
this.stateBucket.currentGameState.timerParams = timerParams;
const timeString = this.setTimer();
this.setLink(timeString);
});
this.socket.on(EVENT_IDS.LEAVE_ROOM, (leftId, gameIsStartable) => { this.socket.on(EVENT_IDS.LEAVE_ROOM, (leftId, gameIsStartable) => {
if (leftId === this.stateBucket.currentGameState.client.id) { if (leftId === this.stateBucket.currentGameState.client.id) {
window.location = '/?message=' + encodeURIComponent('You left the room.'); window.location = '/?message=' + encodeURIComponent('You left the room.');
@@ -335,6 +354,7 @@ export class Lobby {
if (existingPrompt) { if (existingPrompt) {
enableStartButton(existingPrompt, this.startGameHandler); enableStartButton(existingPrompt, this.startGameHandler);
document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler); document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler);
document.getElementById('edit-timer-button').addEventListener('click', this.editTimerHandler);
} else { } else {
const newPrompt = document.createElement('div'); const newPrompt = document.createElement('div');
newPrompt.setAttribute('id', 'start-game-prompt'); newPrompt.setAttribute('id', 'start-game-prompt');
@@ -343,6 +363,7 @@ export class Lobby {
document.body.appendChild(newPrompt); document.body.appendChild(newPrompt);
enableStartButton(newPrompt, this.startGameHandler); enableStartButton(newPrompt, this.startGameHandler);
document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler); document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler);
document.getElementById('edit-timer-button').addEventListener('click', this.editTimerHandler);
} }
} }

View File

@@ -221,7 +221,10 @@ function setClientSocketHandlers (stateBucket, socket) {
socket.on(EVENT_IDS.START_GAME, () => { fetchGameStateHandler(startGameStateAckFn); }); socket.on(EVENT_IDS.START_GAME, () => { fetchGameStateHandler(startGameStateAckFn); });
socket.on(EVENT_IDS.RESTART_GAME, () => { fetchGameStateHandler(restartGameStateAckFn); }); socket.on(EVENT_IDS.RESTART_GAME, () => {
document.querySelector('#game-control-prompt')?.remove();
fetchGameStateHandler(restartGameStateAckFn);
});
socket.on(EVENT_IDS.SYNC_GAME_STATE, () => { socket.on(EVENT_IDS.SYNC_GAME_STATE, () => {
socket.emit( socket.emit(

View File

@@ -191,14 +191,14 @@
margin-top: 0.5em; margin-top: 0.5em;
} }
#deck-list-placeholder { #deck-list-placeholder, #custom-role-placeholder {
margin: auto; margin: auto;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
width: 290px; width: fit-content;
height: 50px; height: 50px;
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;

View File

@@ -106,13 +106,13 @@
max-width: 17em; max-width: 17em;
} }
#save-role-changes-button, #cancel-role-changes-button { #save-role-changes-button, #cancel-role-changes-button, #save-timer-changes-button, #cancel-timer-changes-button {
padding: 10px; padding: 10px;
font-size: 25px; font-size: 25px;
margin: 0.5em 0; margin: 0.5em 0;
} }
#role-edit-prompt { #role-edit-prompt, #timer-edit-prompt {
display: flex; display: flex;
margin: 10px 0; margin: 10px 0;
padding: 10px 0; padding: 10px 0;
@@ -123,11 +123,15 @@
background-color: #16141e; background-color: #16141e;
} }
#role-edit-prompt button { #timer-edit-prompt {
margin-top: 2em;
}
#role-edit-prompt button, #timer-edit-prompt button {
margin: 0 20px; margin: 0 20px;
} }
#save-role-changes-button img { #save-role-changes-button img, #save-timer-changes-button img {
width: 20px; width: 20px;
margin-left: 10px; margin-left: 10px;
} }
@@ -137,7 +141,8 @@
#mod-transfer-button, #mod-transfer-button,
#edit-roles-button, #edit-roles-button,
#save-role-changes-button, #save-role-changes-button,
#edit-timer-button { #edit-timer-button,
#save-timer-changes-button {
background-color: #045ea6; background-color: #045ea6;
border: 2px solid #024070; border: 2px solid #024070;
} }
@@ -147,12 +152,13 @@
#mod-transfer-button:hover, #mod-transfer-button:hover,
#edit-roles-button:hover, #edit-roles-button:hover,
#save-role-changes-button:hover, #save-role-changes-button:hover,
#edit-timer-button:hover { #edit-timer-button:hover,
#save-timer-changes-button:hover {
background-color: rgba(0, 120, 215, 0.45); background-color: rgba(0, 120, 215, 0.45);
border: 2px solid #045EA6; border: 2px solid #045EA6;
} }
#mid-game-role-editor { #mid-game-role-editor, #mid-game-timer-editor {
display: flex; display: flex;
border-radius: 5px; border-radius: 5px;
position: fixed; position: fixed;
@@ -166,7 +172,16 @@
overflow: auto; overflow: auto;
} }
#role-edit-container-background { #mid-game-timer-editor #game-time {
display: flex;
flex-wrap: wrap;
border-radius: 5px;
margin: 1em;
background-color: #16141e;
border: 2px solid #3b3a4a;
}
#role-edit-container-background, #timer-edit-container-background {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@@ -177,17 +192,15 @@
cursor: pointer; cursor: pointer;
} }
#mid-game-role-editor #step-2 { #mid-game-role-editor #step-2 , #mid-game-timer-editor #step-3 {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
overflow: auto; overflow: auto;
align-items: center; align-items: center;
padding: 0;
} }
#save-button {
}
#mid-game-role-editor #custom-roles-container { #mid-game-role-editor #custom-roles-container {
height: fit-content; height: fit-content;
@@ -641,6 +654,7 @@ label[for='moderator'] {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
animation: fade-in-slide-up 0.5s ease-in-out;
justify-content: center; justify-content: center;
position: fixed; position: fixed;
z-index: 3; z-index: 3;
@@ -1167,11 +1181,7 @@ canvas {
@keyframes fade-in-slide-up { @keyframes fade-in-slide-up {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(20px); transform: translateY(10px);
}
5% {
opacity: 1;
transform: translateY(0px);
} }
100% { 100% {
opacity: 1; opacity: 1;

View File

@@ -78,6 +78,7 @@ const EVENT_IDS = {
TIMER_EVENT: 'timerEvent', TIMER_EVENT: 'timerEvent',
KICK_PERSON: 'kickPerson', KICK_PERSON: 'kickPerson',
UPDATE_GAME_ROLES: 'updateGameRoles', UPDATE_GAME_ROLES: 'updateGameRoles',
UPDATE_GAME_TIMER: 'updateGameTimer',
LEAVE_ROOM: 'leaveRoom', LEAVE_ROOM: 'leaveRoom',
BROADCAST: 'broadcast' BROADCAST: 'broadcast'
}; };
@@ -103,6 +104,7 @@ const SYNCABLE_EVENTS = function () {
EVENT_IDS.END_TIMER, EVENT_IDS.END_TIMER,
EVENT_IDS.KICK_PERSON, EVENT_IDS.KICK_PERSON,
EVENT_IDS.UPDATE_GAME_ROLES, EVENT_IDS.UPDATE_GAME_ROLES,
EVENT_IDS.UPDATE_GAME_TIMER,
EVENT_IDS.LEAVE_ROOM EVENT_IDS.LEAVE_ROOM
]; ];
}; };

View File

@@ -56,6 +56,22 @@ class GameCreationRequest {
} }
return false; return false;
} }
static timerParamsAreValid = (hasTimer, timerParams) => {
if (hasTimer === false) {
return timerParams === null;
} else {
if (timerParams === null || typeof timerParams !== 'object') {
return false;
}
return (timerParams.hours === null && timerParams.minutes > 0 && timerParams.minutes < 60)
|| (timerParams.minutes === null && timerParams.hours > 0 && timerParams.hours < 6)
|| (timerParams.hours === 0 && timerParams.minutes > 0 && timerParams.minutes < 60)
|| (timerParams.minutes === 0 && timerParams.hours > 0 && timerParams.hours < 6)
|| (timerParams.hours > 0 && timerParams.hours < 6 && timerParams.minutes >= 0 && timerParams.minutes < 60);
}
}
} }
function valid (gameParams) { function valid (gameParams) {
@@ -65,24 +81,8 @@ function valid (gameParams) {
&& typeof gameParams.moderatorName === 'string' && typeof gameParams.moderatorName === 'string'
&& gameParams.moderatorName.length > 0 && gameParams.moderatorName.length > 0
&& gameParams.moderatorName.length <= 30 && gameParams.moderatorName.length <= 30
&& timerParamsAreValid(gameParams.hasTimer, gameParams.timerParams) && GameCreationRequest.timerParamsAreValid(gameParams.hasTimer, gameParams.timerParams)
&& GameCreationRequest.deckIsValid(gameParams.deck); && GameCreationRequest.deckIsValid(gameParams.deck);
} }
function timerParamsAreValid (hasTimer, timerParams) {
if (hasTimer === false) {
return timerParams === null;
} else {
if (timerParams === null || typeof timerParams !== 'object') {
return false;
}
return (timerParams.hours === null && timerParams.minutes > 0 && timerParams.minutes < 60)
|| (timerParams.minutes === null && timerParams.hours > 0 && timerParams.hours < 6)
|| (timerParams.hours === 0 && timerParams.minutes > 0 && timerParams.minutes < 60)
|| (timerParams.minutes === 0 && timerParams.hours > 0 && timerParams.hours < 6)
|| (timerParams.hours > 0 && timerParams.hours < 6 && timerParams.minutes >= 0 && timerParams.minutes < 60);
}
}
module.exports = GameCreationRequest; module.exports = GameCreationRequest;

View File

@@ -69,7 +69,7 @@ const Events = [
} }
vars.ackFn({ errorFlag: 1, message: 'This name is taken.' }); vars.ackFn({ errorFlag: 1, message: 'This name is taken.' });
} else if (socketArgs.newName.length > PRIMITIVES.MAX_PERSON_NAME_LENGTH) { } else if (socketArgs.newName.length > PRIMITIVES.MAX_PERSON_NAME_LENGTH) {
vars.ackFn({ errorFlag: 1, message: 'Your new name is too long - the max is' + PRIMITIVES.MAX_PERSON_NAME_LENGTH + ' characters.' }); vars.ackFn({ errorFlag: 1, message: 'Your new name is too long - the max is ' + PRIMITIVES.MAX_PERSON_NAME_LENGTH + ' characters.' });
vars.hasNameChanged = false; vars.hasNameChanged = false;
} else if (socketArgs.newName.length === 0) { } else if (socketArgs.newName.length === 0) {
vars.ackFn({ errorFlag: 1, message: 'Your new name cannot be empty.' }); vars.ackFn({ errorFlag: 1, message: 'Your new name cannot be empty.' });
@@ -381,6 +381,25 @@ const Events = [
} }
} }
}, },
{
id: EVENT_IDS.UPDATE_GAME_TIMER,
stateChange: async (game, socketArgs, vars) => {
if (GameCreationRequest.timerParamsAreValid(socketArgs.hasTimer, socketArgs.timerParams)) {
game.hasTimer = socketArgs.hasTimer;
game.timerParams = socketArgs.timerParams;
}
},
communicate: async (game, socketArgs, vars) => {
if (vars.ackFn) {
vars.ackFn();
}
vars.gameManager.namespace.in(game.accessCode).emit(
EVENT_IDS.UPDATE_GAME_TIMER,
game.hasTimer,
game.timerParams
);
}
},
{ {
id: EVENT_IDS.END_TIMER, id: EVENT_IDS.END_TIMER,
stateChange: async (game, socketArgs, vars) => { stateChange: async (game, socketArgs, vars) => {