mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
allow moderators to kick players and spectators
This commit is contained in:
@@ -53,7 +53,8 @@ export const globals = {
|
||||
ADD_SPECTATOR: 'addSpectator',
|
||||
UPDATE_SPECTATORS: 'updateSpectators',
|
||||
RESTART_GAME: 'restartGame',
|
||||
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod'
|
||||
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod',
|
||||
KICK_PERSON: 'kickPerson'
|
||||
},
|
||||
TIMER_EVENTS: function () {
|
||||
return [
|
||||
@@ -66,7 +67,8 @@ export const globals = {
|
||||
LOBBY_EVENTS: function () {
|
||||
return [
|
||||
this.EVENT_IDS.PLAYER_JOINED,
|
||||
this.EVENT_IDS.ADD_SPECTATOR
|
||||
this.EVENT_IDS.ADD_SPECTATOR,
|
||||
this.EVENT_IDS.KICK_PERSON
|
||||
];
|
||||
},
|
||||
IN_PROGRESS_EVENTS: function () {
|
||||
|
||||
@@ -139,6 +139,15 @@ export const HTMLFragments = {
|
||||
<button id='close-mod-transfer-modal-button' class='app-button cancel'>Cancel</button>
|
||||
</div>
|
||||
</div>`,
|
||||
PLAYER_OPTIONS_MODAL:
|
||||
`<div id='player-options-modal-background' class='modal-background'></div>
|
||||
<div tabindex='-1' id='player-options-modal' class='modal'>
|
||||
<h2>Person Options:</h2>
|
||||
<div id='player-options-modal-content'></div>
|
||||
<div class='modal-button-container'>
|
||||
<button id='close-player-options-modal-button' class='app-button cancel'>Close</button>
|
||||
</div>
|
||||
</div>`,
|
||||
MODERATOR_GAME_VIEW:
|
||||
`<div id='game-header'>
|
||||
<div id='timer-container-moderator'>
|
||||
|
||||
@@ -51,7 +51,7 @@ export class InProgress {
|
||||
this.stateBucket.currentGameState.accessCode
|
||||
);
|
||||
setTimeout(() => {
|
||||
if (this.socket.hasListeners(globals.EVENT_IDS.GET_TIME_REMAINING)) {
|
||||
if (this.socket.hasListeners(globals.EVENT_IDS.GET_TIME_REMAINING) && document.getElementById('game-timer') !== null) {
|
||||
document.getElementById('game-timer').innerText = 'Timer not found.';
|
||||
document.getElementById('game-timer').classList.add('timer-error');
|
||||
}
|
||||
@@ -65,8 +65,16 @@ export class InProgress {
|
||||
const spectatorCount = this.container.querySelector('#spectator-count');
|
||||
const spectatorHandler = (e) => {
|
||||
if (e.type === 'click' || e.code === 'Enter') {
|
||||
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.people
|
||||
.filter(p => p.userType === globals.USER_TYPES.SPECTATOR)), null, true);
|
||||
Confirmation(
|
||||
SharedStateUtil.buildSpectatorList(
|
||||
this.stateBucket.currentGameState.people
|
||||
.filter(p => p.userType === globals.USER_TYPES.SPECTATOR),
|
||||
this.stateBucket.currentGameState.client,
|
||||
this.socket,
|
||||
this.stateBucket.currentGameState),
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,8 +61,14 @@ export class Lobby {
|
||||
|
||||
const spectatorHandler = (e) => {
|
||||
if (e.type === 'click' || e.code === 'Enter') {
|
||||
Confirmation(SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.people
|
||||
.filter(p => p.userType === globals.USER_TYPES.SPECTATOR), this.stateBucket.currentGameState.client), null, true);
|
||||
Confirmation(
|
||||
SharedStateUtil.buildSpectatorList(this.stateBucket.currentGameState.people
|
||||
.filter(p => p.userType === globals.USER_TYPES.SPECTATOR),
|
||||
this.stateBucket.currentGameState.client,
|
||||
this.socket,
|
||||
this.stateBucket.currentGameState),
|
||||
null, true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,7 +101,7 @@ export class Lobby {
|
||||
}
|
||||
);
|
||||
for (const person of sorted.filter(p => p.userType !== globals.USER_TYPES.SPECTATOR)) {
|
||||
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name, person.userType, this.stateBucket.currentGameState.client));
|
||||
lobbyPlayersContainer.appendChild(renderLobbyPerson(person, this.stateBucket.currentGameState, this.socket));
|
||||
}
|
||||
const playerCount = this.stateBucket.currentGameState.people.filter(
|
||||
p => p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR
|
||||
@@ -126,6 +132,32 @@ export class Lobby {
|
||||
document.getElementById('spectator-count')
|
||||
);
|
||||
});
|
||||
|
||||
this.socket.on(globals.EVENT_IDS.KICK_PERSON, (kickedId, gameIsFull) => {
|
||||
if (kickedId === this.stateBucket.currentGameState.client.id) {
|
||||
window.location = '/?message=' + encodeURIComponent('You were kicked by the moderator.');
|
||||
} else {
|
||||
const kickedIndex = this.stateBucket.currentGameState.people.findIndex(person => person.id === kickedId);
|
||||
if (kickedIndex >= 0) {
|
||||
this.stateBucket.currentGameState.people
|
||||
.splice(kickedIndex, 1);
|
||||
}
|
||||
this.stateBucket.currentGameState.isFull = gameIsFull;
|
||||
SharedStateUtil.setNumberOfSpectators(
|
||||
this.stateBucket.currentGameState.people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR).length,
|
||||
document.getElementById('spectator-count')
|
||||
);
|
||||
this.populatePlayers();
|
||||
if ((
|
||||
this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||
|| this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
)
|
||||
) {
|
||||
toast('player kicked.', 'success', true, true, 'short');
|
||||
this.displayStartGamePromptForModerators();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
displayStartGamePromptForModerators () {
|
||||
@@ -192,23 +224,25 @@ function getTimeString (gameState) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderLobbyPerson (name, userType, client) {
|
||||
function renderLobbyPerson (person, gameState, socket) {
|
||||
const el = document.createElement('div');
|
||||
const personNameEl = document.createElement('div');
|
||||
personNameEl.classList.add('lobby-player-name');
|
||||
const personTypeEl = document.createElement('div');
|
||||
personNameEl.innerText = name;
|
||||
personTypeEl.innerText = userType + globals.USER_TYPE_ICONS[userType];
|
||||
personNameEl.innerText = person.name;
|
||||
personTypeEl.innerText = person.userType + globals.USER_TYPE_ICONS[person.userType];
|
||||
el.classList.add('lobby-player');
|
||||
if (userType === globals.USER_TYPES.MODERATOR || userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
if (person.userType === globals.USER_TYPES.MODERATOR || person.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
el.classList.add('moderator');
|
||||
}
|
||||
|
||||
el.appendChild(personNameEl);
|
||||
el.appendChild(personTypeEl);
|
||||
|
||||
if (client.userType === globals.USER_TYPES.MODERATOR || client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
SharedStateUtil.addPlayerOptions(el);
|
||||
if ((gameState.client.userType === globals.USER_TYPES.MODERATOR || gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR)
|
||||
&& person.userType !== globals.USER_TYPES.MODERATOR && person.userType !== globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
SharedStateUtil.addPlayerOptions(el, person, socket, gameState);
|
||||
el.dataset.pointer = person.id;
|
||||
}
|
||||
|
||||
return el;
|
||||
|
||||
@@ -24,7 +24,7 @@ export const SharedStateUtil = {
|
||||
},
|
||||
|
||||
restartHandler: (stateBucket, status = globals.STATUS.IN_PROGRESS) => {
|
||||
console.log("HEY")
|
||||
console.log('HEY');
|
||||
XHRUtility.xhr(
|
||||
'/api/games/' + stateBucket.currentGameState.accessCode + '/restart?status=' + status,
|
||||
'PATCH',
|
||||
@@ -175,17 +175,46 @@ export const SharedStateUtil = {
|
||||
}
|
||||
},
|
||||
|
||||
addPlayerOptions: (personEl) => {
|
||||
const kickButton = document.createElement('img');
|
||||
kickButton.setAttribute('tabIndex', '0');
|
||||
kickButton.setAttribute('className', 'role-remove');
|
||||
kickButton.setAttribute('src', '../images/3-vertical-dots-icon.svg');
|
||||
kickButton.setAttribute('title', 'Kick Player');
|
||||
kickButton.setAttribute('alt', 'Kick Player');
|
||||
personEl.appendChild(kickButton);
|
||||
addPlayerOptions: (personEl, person, socket, gameState) => {
|
||||
const optionsButton = document.createElement('img');
|
||||
const optionsHandler = (e) => {
|
||||
if (e.type === 'click' || e.code === 'Enter') {
|
||||
document.getElementById('player-options-modal-content').innerHTML = '';
|
||||
const kickOption = document.createElement('button');
|
||||
kickOption.setAttribute('class', 'player-option');
|
||||
kickOption.innerText = 'Kick Person';
|
||||
kickOption.addEventListener('click', () => {
|
||||
ModalManager.dispelModal('player-options-modal', 'player-options-modal-background');
|
||||
Confirmation('Kick \'' + person.name + '\'?', () => {
|
||||
socket.emit(
|
||||
globals.SOCKET_EVENTS.IN_GAME_MESSAGE,
|
||||
globals.EVENT_IDS.KICK_PERSON,
|
||||
gameState.accessCode,
|
||||
{ personId: person.id }
|
||||
);
|
||||
});
|
||||
});
|
||||
document.getElementById('player-options-modal-content').appendChild(kickOption);
|
||||
ModalManager.displayModal(
|
||||
'player-options-modal',
|
||||
'player-options-modal-background',
|
||||
'close-player-options-modal-button'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
optionsButton.addEventListener('click', optionsHandler);
|
||||
optionsButton.addEventListener('keyup', optionsHandler);
|
||||
optionsButton.setAttribute('tabIndex', '0');
|
||||
optionsButton.setAttribute('className', 'role-remove');
|
||||
optionsButton.setAttribute('src', '../images/3-vertical-dots-icon.svg');
|
||||
optionsButton.setAttribute('title', 'Player Options');
|
||||
optionsButton.setAttribute('alt', 'Player Options');
|
||||
|
||||
personEl.appendChild(optionsButton);
|
||||
},
|
||||
|
||||
buildSpectatorList (people, client) {
|
||||
buildSpectatorList (people, client, socket, gameState) {
|
||||
const list = document.createElement('div');
|
||||
const spectators = people.filter(p => p.userType === globals.USER_TYPES.SPECTATOR);
|
||||
if (spectators.length === 0) {
|
||||
@@ -200,7 +229,8 @@ export const SharedStateUtil = {
|
||||
list.appendChild(spectatorEl);
|
||||
|
||||
if (client.userType === globals.USER_TYPES.MODERATOR || client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
this.addPlayerOptions(spectatorEl);
|
||||
this.addPlayerOptions(spectatorEl, spectator, socket, gameState);
|
||||
spectatorEl.dataset.pointer = spectator.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,13 +289,12 @@ function processGameState (
|
||||
lobby.populatePlayers();
|
||||
globals.LOBBY_EVENTS().forEach(e => socket.removeAllListeners(e));
|
||||
lobby.setSocketHandlers();
|
||||
if ((
|
||||
currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||
|| currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
)
|
||||
&& refreshPrompt
|
||||
) {
|
||||
lobby.displayStartGamePromptForModerators();
|
||||
if (currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||
|| currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
if (refreshPrompt) {
|
||||
lobby.displayStartGamePromptForModerators();
|
||||
}
|
||||
document.getElementById('player-options-prompt').innerHTML = HTMLFragments.PLAYER_OPTIONS_MODAL;
|
||||
}
|
||||
break;
|
||||
case globals.STATUS.IN_PROGRESS:
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { XHRUtility } from '../modules/utility/XHRUtility.js';
|
||||
import { toast } from '../modules/front_end_components/Toast.js';
|
||||
import { injectNavbar } from '../modules/front_end_components/Navbar.js';
|
||||
import { Confirmation } from '../modules/front_end_components/Confirmation.js';
|
||||
|
||||
const home = () => {
|
||||
injectNavbar();
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const message = urlParams.get('message');
|
||||
if (message && message.length > 0) {
|
||||
Confirmation(message);
|
||||
}
|
||||
document.getElementById('join-form').addEventListener('submit', attemptToJoinGame);
|
||||
};
|
||||
|
||||
|
||||
@@ -273,11 +273,36 @@ h1 {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#role-info-modal .modal-button-container {
|
||||
#role-info-modal .modal-button-container, #player-options-modal .modal-button-container {
|
||||
margin-top: 1em;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#player-options-modal-content {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.player-option {
|
||||
background-color: #4645525c;
|
||||
border: 2px solid #46455299;
|
||||
color: #d7d7d7;
|
||||
display: flex;
|
||||
font-family: 'signika-negative', sans-serif !important;
|
||||
padding: 10px 30px;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.player-option:hover, .player-option:active {
|
||||
border: 2px solid #e7e7e7;
|
||||
background-color: #33343c;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#game-role-info-container .role-info-name {
|
||||
border-radius: 5px;
|
||||
font-size: 20px;
|
||||
|
||||
@@ -76,6 +76,14 @@
|
||||
border: 1px solid #46455299;
|
||||
}
|
||||
|
||||
#player-options-modal {
|
||||
z-index: 200001;
|
||||
}
|
||||
|
||||
#player-options-modal-background {
|
||||
z-index: 200000;
|
||||
}
|
||||
|
||||
#custom-role-info-modal-name {
|
||||
font-family: 'signika-negative', sans-serif;
|
||||
font-size: 23px;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const template =
|
||||
`<div id="role-info-prompt"></div>
|
||||
<div id="transfer-mod-prompt"></div>
|
||||
<div id="player-options-prompt"></div>
|
||||
<div class="spinner-background"></div>
|
||||
<div class="spinner-container">
|
||||
<div class="lds-spinner">
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<link rel="stylesheet" href="./styles/GLOBAL.css">
|
||||
<link rel="stylesheet" href="./styles/home.css">
|
||||
<link rel="stylesheet" href="/styles/hamburgers.css">
|
||||
<link rel="stylesheet" href="./styles/confirmation.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="mobile-menu-background-overlay"></div>
|
||||
|
||||
Reference in New Issue
Block a user