diff --git a/db.js b/db.js index fb5d951..e64303c 100644 --- a/db.js +++ b/db.js @@ -72,7 +72,13 @@ exports.addUserToRoom = (userId, roomId, state, fn=null) => { exports.getRoom = (roomId, fn) => { if (!roomId) return fn({error: "Room ID is required"}); var sql = ` - SELECT token, edition, rotate_czar as rotateCzar, cur_prompt as curPrompt, state + SELECT + token, + edition, + rotate_czar as rotateCzar, + cur_prompt as curPrompt, + state, + selected_response as selectedResponse FROM rooms WHERE id = ?; `; @@ -91,7 +97,8 @@ exports.getRoom = (roomId, fn) => { edition: results[0].edition, rotateCzar: results[0].rotateCzar, curPrompt: results[0].curPrompt, - state: results[0].state + state: results[0].state, + selectedResponse: results[0].selectedResponse }); }); }; @@ -271,12 +278,11 @@ function getCards(roomId, black, count, fn) { FROM room_packs WHERE room_id = ${roomId} ) - ) - AND id NOT IN ( + ) AND id NOT IN ( SELECT card_id FROM room_${color}_cards WHERE room_id = ${roomId} - ) + ) ${black ? "AND pick = 1" : ""} ORDER BY RAND() LIMIT ${count}; `; diff --git a/index.js b/index.js index 53db607..34b18a9 100644 --- a/index.js +++ b/index.js @@ -687,6 +687,52 @@ function initSocket(socket, userId) { }); }); + socket.on("selectResponse", (data, fn) => { + if (data.cardId != null && !helpers.validateUInt(data.cardId)) return fn({error: "Invalid Card ID"}); + var user = getUser(userId, true); + if (user.error) return fn(user); + if (user.state != vars.UserStates.czar) { + console.warn("User #" + userId + " with state '" + user.state + "' tried to reveal a response!"); + return fn({error: "Invalid User State"}); + } + + db.getRoom(user.roomId, room => { + if (room.error) return fn(room); + if (room.state != vars.RoomStates.readingCards) return fn({error: "Invalid Room State"}); + + db.getRoomUsers(user.roomId, response => { + if (response.error) { + console.warn("Failed to get users when revealing card in room #" + user.roomId); + return fn(response); + } else if (response.userIds.length == 0) return fn({error: "Invalid Room"}); + + if (data.cardId != null) { + db.getWhiteCardByID(data.cardId, card => { + if (card.error) return fn(card); + + finishSelectResponse(user, response, data.cardId); + }); + } else finishSelectResponse(user, response, null); + }); + }); + }); + + function finishSelectResponse(user, roomUserInfo, cardId) { + db.query(`UPDATE rooms SET selected_response = ? WHERE id = ?;`, + [cardId, user.roomId], (err, result) => { + if (err) { + console.warn("Failed to update selected card for room #" + user.roomId); + return fn({error: "MySQL Error"}); + } + + roomUserInfo.userIds.forEach(roomUserId => { + if (!users.hasOwnProperty(roomUserId) || roomUserId == userId) return; + + users[roomUserId].socket.emit("selectResponse", {cardId: cardId}); + }); + }); + } + /*************** * Chat System * ***************/ diff --git a/public/inc/main.js b/public/inc/main.js index 1803f12..2935757 100644 --- a/public/inc/main.js +++ b/public/inc/main.js @@ -696,6 +696,28 @@ socket.on("revealResponse", (data) => { cardElement.removeClass("back").addClass("front"); cardElement.children(".card-text").text(data.card.text); cardElement.attr("id", "response-revealed-" + data.card.id); + + if (users[userId].state == UserStates.czar) { + $("#response-revealed-" + data.card.id).off("click").on("click", event => { + if (selectedCard) { + $("#response-revealed-" + selectedCard).removeClass("selected-card"); + } + $("#response-revealed-" + data.card.id).addClass("selected-card"); + selectedCard = data.card.id; + + $("#select-winner").show(); + $("#cur-black-card").addClass("czar-mode"); + + socket.emit("selectResponse", {cardId: data.card.id}, response => { + if (response.error) return console.warn("Failed to select response:", response.error); + }); + }); + } +}); + +socket.on("selectResponse", (data) => { + $(".selected-card").removeClass("selected-card"); + if (data.cardId) $("#response-revealed-" + data.cardId).addClass("selected-card"); }); /******************** @@ -721,7 +743,7 @@ function addResponseCard(id, isCzar) { // Only the czar can reveal answers if (isCzar) { - $("#response-card-" + id).click(event => { + $("#response-card-" + id).on("click", event => { socket.emit("revealResponse", {position: id}, response => { if (response.error) return console.warn("Failed to reveal respose #" + id + ":", response.error); }); @@ -777,10 +799,20 @@ $("#hand").sortable({ }); $("#game-wrapper").click(event => { - if (!submittingCard && selectedCard && ($(event.target).is("#game-wrapper") || $(event.target).is("#hand"))) { + if (!submittingCard && selectedCard && ($(event.target).is("#game-wrapper") || $(event.target).is("#hand") || $(event.target).is("#response-cards"))) { $("#white-card-" + selectedCard).removeClass("selected-card"); + $("#response-revealed-" + selectedCard).removeClass("selected-card"); selectedCard = null; - $("#central-action").hide(); + + if (room.state == RoomStates.readingCards) { + $("#select-winner").hide(); + $("#cur-black-card").removeClass("czar-mode"); + socket.emit("selectResponse", {cardId: null}, response => { + if (response.error) return console.warn("Failed to deselect card:", response.error); + }); + } else { + $("#central-action").hide(); + } } }) diff --git a/public/inc/main.scss b/public/inc/main.scss index 9940723..5003bba 100644 --- a/public/inc/main.scss +++ b/public/inc/main.scss @@ -278,10 +278,17 @@ input[type=text] { margin: 10px; transition: $resizeTransition; - .card-text::after { - bottom: 112px; + &.selected-card { + border: 2px solid $contrastColor; + margin: 9px; + } + .card-text::after { + display: none; + + // TODO: fix jumpy bottom text during transition from hover; + bottom: 112px; @media only screen and (min-width: 1450px) { bottom: 3px; @@ -292,6 +299,7 @@ input[type=text] { } &:hover { + transition: none; .card-text::after { bottom: 0; } @@ -309,6 +317,10 @@ input[type=text] { @media only screen and (max-width: 1550px) { .card { margin: 5px; + + &.selected-card { + margin: 4px; + } } } @@ -358,7 +370,7 @@ input[type=text] { transform: scale(1.15); } - @media only screen and (max-width: 1450px) { + @media only screen and (max-width: 1450px) and (min-width: $firstTransitionWidth) { transform: scale(1.25); left: 28.5%; &.czar-mode { diff --git a/public/index.html b/public/index.html index 056ec6f..c754b47 100644 --- a/public/index.html +++ b/public/index.html @@ -24,7 +24,7 @@