Bingo lobby improvements

- bingo added kicking of player
- bingo added display of admin
- bingo added grid size input
pull/15/head
Trivernis 6 years ago
parent 1a552a0661
commit d566505c3f

@ -23,12 +23,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- css for startpage (wip)
- file for css animations
- pug file for startpage
- bingo lobbys
- kick function for bingo
- grid size input
## Changed
- changed export of `app.js` to the asynchronous init function that returns the app object
- `bin/www` now calls the init function of `app.js`
- graphql api
- graphql bingo api
- bingo frontend
### Removed

@ -19,7 +19,7 @@ type LobbyMutation {
leave: Boolean
"kicks a player from the lobby"
kickPlayer(playerId: ID!): BingoLobby
kickPlayer(pid: ID!): BingoPlayer
"starts a round in a lobby if the user is the admin"
startRound: BingoRound

@ -9,3 +9,5 @@ Angry Koala
Dragonslayer
Goblin Slayer
useless Aqua
theP0wner79
Pr0wn

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

@ -101,6 +101,32 @@ async function leaveLobby() {
}
}
/**
* Kicks a player by id.
* @param playerId
* @returns {Promise<void>}
*/
async function kickPlayer(pid) {
let response = await postGraphqlQuery(`
mutation ($lobbyId: ID!, $playerId:ID!) {
bingo {
mutateLobby(id: $lobbyId) {
kickPlayer(pid: $playerId) {
id
}
}
}
}
`, {lobbyId: getLobbyParam(), playerId: pid});
if (response.status === 200) {
let kickId = response.data.bingo.mutateLobby.kickPlayer.id;
document.querySelector(`.playerEntryContainer[b-pid='${kickId}'`).remove();
} else {
showError('Failed to kick player!');
console.error(response);
}
}
/**
* Sends a message to the chat
* @returns {Promise<void>}
@ -138,11 +164,13 @@ async function sendChatMessage() {
/**
* Sets the words for the lobby
* @param words
* @param gridSize
* @returns {Promise<LobbyWrapper.words|*|properties.words|{default, type}|boolean>}
*/
async function setLobbyWords(words) {
async function setLobbySettings(words, gridSize) {
gridSize = Number(gridSize);
let response = await postGraphqlQuery(`
mutation($lobbyId:ID!, $words:[String!]!){
mutation ($lobbyId: ID!, $words: [String!]!, $gridSize:Int!) {
bingo {
mutateLobby(id: $lobbyId) {
setWords(words: $words) {
@ -150,9 +178,13 @@ async function setLobbyWords(words) {
content
}
}
setGridSize(gridSize: $gridSize) {
gridSize
}
}
}
}
}`, {lobbyId: getLobbyParam(), words: words});
`, {lobbyId: getLobbyParam(), words: words, gridSize: gridSize});
if (response.status === 200) {
return response.data.bingo.mutateLobby.setWords.words;
} else {
@ -168,7 +200,8 @@ async function setLobbyWords(words) {
async function startRound() {
let textinput = document.querySelector('#input-bingo-words');
let words = getLobbyWords();
let resultWords = await setLobbyWords(words);
let gridSize = document.querySelector('#input-grid-size').value || 3;
let resultWords = await setLobbySettings(words, gridSize);
textinput.value = resultWords.map(x => x.content).join('\n');
let response = await postGraphqlQuery(`
mutation($lobbyId:ID!){
@ -351,11 +384,17 @@ function addChatMessage(messageObject) {
* Adds a player to the player view
* @param player
*/
function addPlayer(player) {
function addPlayer(player, options) {
let playerContainer = document.createElement('div');
playerContainer.setAttribute('class', 'playerEntryContainer');
playerContainer.setAttribute('b-pid', player.id);
playerContainer.innerHTML = `<span class="playernameSpan">${player.username}</span>`;
if (options.isAdmin && player.id !== options.admin)
playerContainer.innerHTML = `<button class="kickPlayerButton" onclick="kickPlayer(${player.id})">❌</button>`;
playerContainer.innerHTML += `<span class="playernameSpan">${player.username}</span>`;
if (player.id === options.admin)
playerContainer.innerHTML += "<span class='adminSpan'> 👑</span>";
document.querySelector('#player-list').appendChild(playerContainer);
}
@ -405,20 +444,29 @@ async function refreshPlayers() {
let response = await postGraphqlQuery(`
query ($lobbyId: ID!) {
bingo {
player {
id
}
lobby(id: $lobbyId) {
players {
id
username
wins(lobbyId: $lobbyId)
}
admin {
id
}
}
}
}`, {lobbyId: getLobbyParam()});
}
`, {lobbyId: getLobbyParam()});
if (response.status === 200) {
let players = response.data.bingo.lobby.players;
let adminId = response.data.bingo.lobby.admin.id;
let isAdmin = response.data.bingo.player.id === adminId;
for (let player of players)
if (!document.querySelector(`.playerEntryContainer[b-pid="${player.id}"]`))
addPlayer(player);
addPlayer(player, {admin: adminId, isAdmin: isAdmin});
} else {
showError('Failed to refresh players');
console.error(response);
@ -572,7 +620,9 @@ window.addEventListener("unhandledrejection", function (promiseRejectionEvent) {
window.addEventListener("keydown", async (e) => {
if (e.which === 83 && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)) {
e.preventDefault();
if (document.querySelector('#input-bingo-words'))
await setLobbyWords(getLobbyWords());
if (document.querySelector('#input-bingo-words')) {
let gridSize = document.querySelector('#input-grid-size').value || 3;
await setLobbySettings(getLobbyWords(), gridSize);
}
}
}, false);

@ -82,9 +82,13 @@
#input-bingo-words
width: 100%
height: calc(100% - 7rem)
height: calc(100% - 10rem)
margin: 0
#input-grid-size
height: 3rem
width: 4rem
#button-round-start, #button-leave
height: 3rem
width: 100%
@ -116,6 +120,13 @@
height: calc(100% - 6rem)
overflow-y: auto
.kickPlayerButton
background-color: #0000
border: none
padding: 0
margin: 0 0.5rem 0 0
font-size: 1em
#container-grid
display: table
height: calc(100% - 2em)
@ -183,7 +194,7 @@
#container-bingo-lobby
display: grid
grid-template: 5% 5% 85% 5% / 5% 30% 30% 30% 5%
grid-template: 0 10% 85% 5% / 5% 30% 30% 30% 5%
height: 100%
width: 100%

@ -46,11 +46,20 @@ button:active
background-color: lighten($secondary, 15%)
input
@include default-element
background-color: lighten($primary, 10%)
color: $primarySurface
border: 1px solid $inactive
transition-duration: 0.2s
font-size: 1.2rem
background-color: lighten($primary, 15%)
padding: 0.7rem
input:focus
background-color: lighten($primary, 15%)
border: 1px solid $primarySurface
input[type='number']
text-align: center
textarea
background-color: lighten($primary, 15%)
color: $primarySurface

@ -854,6 +854,15 @@ class LobbyWrapper {
}
}
/**
* Returns if the lobby exists (based on one loaded attribute)
* @returns {Promise<boolean>}
*/
async exists() {
await this._loadLobbyInfo();
return !!this.expire;
}
/**
* returns the players in the lobby
* @returns {Promise<Array>}
@ -1025,6 +1034,18 @@ class LobbyWrapper {
await this._loadLobbyInfo(true);
}
/**
* Removes a player from the lobby
* @param playerId
* @returns {Promise<void>}
*/
async removePlayer(playerId) {
await bdm.removePlayerFromLobby(playerId, this.id);
let username = await new PlayerWrapper(playerId).username();
await bdm.addInfoMessage(this.id, `${username} left.`);
await this._loadLobbyInfo(true);
}
/**
* Returns if the lobby is in an active round
* @returns {Promise<boolean>}
@ -1236,9 +1257,9 @@ router.get('/', async (req, res) => {
let playerId = req.session.bingoPlayerId;
if (!playerId)
req.session.bingoPlayerId = playerId = (await bdm.addPlayer(shuffleArray(playerNames)[0])).id;
if (req.query.g) {
let lobbyWrapper = new LobbyWrapper(req.query.g);
if (req.query.g && await lobbyWrapper.exists()) {
let lobbyId = req.query.g;
let lobbyWrapper = new LobbyWrapper(lobbyId);
if (!(await lobbyWrapper.roundActive())) {
if (!await lobbyWrapper.hasPlayer(playerId))
@ -1249,17 +1270,34 @@ router.get('/', async (req, res) => {
res.render('bingo/bingo-lobby', {
players: playerData,
isAdmin: (playerId === admin.id),
adminId: admin.id,
words: words,
wordString: words.join('\n')});
wordString: words.join('\n'),
gridSize: await lobbyWrapper.gridSize()
});
} else {
if (await lobbyWrapper.hasPlayer(playerId)) {
let playerData = await getPlayerData(lobbyWrapper);
let grid = await getGridData(lobbyId, playerId);
res.render('bingo/bingo-round', {players: playerData, grid: grid});
let admin = await lobbyWrapper.admin();
res.render('bingo/bingo-round', {
players: playerData,
grid: grid,
isAdmin: (playerId === admin.id),
adminId: admin.id
});
} else {
let playerData = await getPlayerData(lobbyWrapper);
let admin = await lobbyWrapper.admin();
res.render('bingo/bingo-lobby', {players: playerData, isAdmin: (playerId === admin.id)});
let words = await getWordsData(lobbyWrapper);
res.render('bingo/bingo-lobby', {
players: playerData,
isAdmin: (playerId === admin.id),
adminId: admin.id,
words: words,
wordString: words.join('\n'),
gridSize: await lobbyWrapper.gridSize()
});
}
}
} else {
@ -1314,15 +1352,15 @@ router.graphqlResolver = async (req, res) => {
return {
join: async () => {
if (playerId) {
let result = await bdm.addPlayerToLobby(playerId, lobbyId);
return new LobbyWrapper(result.lobby_id);
await lobbyWrapper.addPlayer(playerId);
return lobbyWrapper;
} else {
res.status(400);
}
},
leave: async () => {
if (playerId) {
await bdm.removePlayerFromLobby(playerId, lobbyId);
await lobbyWrapper.removePlayer(playerId);
return true;
} else {
res.status(400);
@ -1331,8 +1369,8 @@ router.graphqlResolver = async (req, res) => {
kickPlayer: async ({pid}) => {
let admin = await lobbyWrapper.admin();
if (admin.id === playerId) {
let result = await bdm.removePlayerFromLobby(pid, lobbyId);
return new LobbyWrapper(result.id, result);
await lobbyWrapper.removePlayer(pid);
return new PlayerWrapper(pid);
}
},
startRound: async () => {
@ -1369,7 +1407,7 @@ router.graphqlResolver = async (req, res) => {
submitBingo: async () => {
let isBingo = await (await (new PlayerWrapper(playerId)).grid({lobbyId: lobbyId})).bingo();
let currentRound = await lobbyWrapper.currentRound();
if (isBingo) {
if (isBingo && await lobbyWrapper.hasPlayer(playerId)) {
let result = await currentRound.setWinner(playerId);
if (result)
return currentRound;

@ -7,6 +7,8 @@ block content
div(id='container-lobby-settings')
h1 Words
if isAdmin
span Grid Size:
input(id='input-grid-size' type='number' value=gridSize)
textarea(id='input-bingo-words')= wordString
button(id='button-round-start' onclick='startRound()') Start Round
else

@ -3,4 +3,8 @@ div(id='container-players')
div(id='player-list')
each player in players
div(class='playerEntryContainer', b-pid=`${player.id}`)
if isAdmin && player.id !== adminId
button(class='kickPlayerButton' onclick=`kickPlayer(${player.id})`) ❌
span(class='playerNameSpan')= player.username
if player.id === adminId
span(class='adminSpan') 👑

Loading…
Cancel
Save