add vote history

This commit is contained in:
Steffen 2020-12-06 22:27:52 +01:00
parent 7caa0e7a4b
commit 15ced66b42
8 changed files with 157 additions and 4 deletions

View File

@ -26,6 +26,7 @@
<RolesModal /> <RolesModal />
<ReferenceModal /> <ReferenceModal />
<NightOrderModal /> <NightOrderModal />
<VoteHistoryModal />
<Gradients /> <Gradients />
<span id="version">v{{ version }}</span> <span id="version">v{{ version }}</span>
</div> </div>
@ -45,9 +46,11 @@ import Vote from "./components/Vote";
import Gradients from "./components/Gradients"; import Gradients from "./components/Gradients";
import NightOrderModal from "./components/modals/NightOrderModal"; import NightOrderModal from "./components/modals/NightOrderModal";
import FabledModal from "@/components/modals/FabledModal"; import FabledModal from "@/components/modals/FabledModal";
import VoteHistoryModal from "@/components/modals/VoteHistoryModal";
export default { export default {
components: { components: {
VoteHistoryModal,
FabledModal, FabledModal,
NightOrderModal, NightOrderModal,
Vote, Vote,

View File

@ -108,6 +108,13 @@
Copy player link Copy player link
<em><font-awesome-icon icon="copy"/></em> <em><font-awesome-icon icon="copy"/></em>
</li> </li>
<li
v-if="session.voteHistory.length"
@click="toggleModal('voteHistory')"
>
Nomination history
<em><font-awesome-icon icon="hand-paper"/></em>
</li>
<li @click="leaveSession" v-if="session.sessionId"> <li @click="leaveSession" v-if="session.sessionId">
Leave Session Leave Session
<em>{{ session.sessionId }}</em> <em>{{ session.sessionId }}</em>
@ -223,6 +230,7 @@ export default {
Math.round(Math.random() * 10000) Math.round(Math.random() * 10000)
); );
if (sessionId) { if (sessionId) {
this.$store.commit("session/clearHistory");
this.$store.commit("session/setSpectator", false); this.$store.commit("session/setSpectator", false);
this.$store.commit( this.$store.commit(
"session/setSessionId", "session/setSessionId",
@ -251,6 +259,7 @@ export default {
"Enter the channel number / name of the session you want to join" "Enter the channel number / name of the session you want to join"
); );
if (sessionId) { if (sessionId) {
this.$store.commit("session/clearHistory");
this.$store.commit("session/setSpectator", true); this.$store.commit("session/setSpectator", true);
this.$store.commit("toggleGrimoire", false); this.$store.commit("toggleGrimoire", false);
this.$store.commit( this.$store.commit(

View File

@ -206,6 +206,7 @@ export default {
}, },
finish() { finish() {
clearInterval(this.voteTimer); clearInterval(this.voteTimer);
this.$store.commit("session/addHistory", this.players);
this.$store.commit("session/nomination"); this.$store.commit("session/nomination");
}, },
vote(vote) { vote(vote) {

View File

@ -53,6 +53,11 @@ export default {
max-width: 80%; max-width: 80%;
overflow-y: auto; overflow-y: auto;
} }
.vote-history & {
max-height: 80%;
max-width: 80%;
overflow-y: auto;
}
ul { ul {
list-style-type: none; list-style-type: none;

View File

@ -0,0 +1,103 @@
<template>
<Modal
class="vote-history"
v-show="modals.voteHistory"
@close="toggleModal('voteHistory')"
v-if="session.voteHistory"
>
<font-awesome-icon
@click="clearHistory"
icon="trash-alt"
class="clear"
title="Clear history"
/>
<h3>Nomination history</h3>
<table>
<thead>
<tr>
<td>Nominator</td>
<td>Nominee</td>
<td>Type</td>
<td>Majority</td>
<td><font-awesome-icon icon="hand-paper" /> Hand up</td>
</tr>
</thead>
<tbody>
<tr v-for="(vote, index) in session.voteHistory" :key="index">
<td>{{ vote.nominator }}</td>
<td>{{ vote.nominee }}</td>
<td>{{ vote.type }}</td>
<td>{{ vote.majority }}</td>
<td>
{{ vote.votes.length }}
<font-awesome-icon icon="user-friends" />
{{ vote.votes.join(", ") }}
</td>
</tr>
</tbody>
</table>
</Modal>
</template>
<script>
import Modal from "./Modal";
import { mapMutations, mapState } from "vuex";
export default {
components: {
Modal
},
computed: {
...mapState(["session", "modals"])
},
methods: {
...mapMutations(["toggleModal"]),
...mapMutations("session", ["clearHistory"])
}
};
</script>
<style lang="scss" scoped>
@import "../../vars.scss";
.clear {
position: absolute;
left: 20px;
top: 20px;
cursor: pointer;
&:hover {
color: red;
}
}
h3 {
margin: 0 40px;
svg {
vertical-align: middle;
}
}
table {
border-spacing: 10px 0;
}
thead td {
font-weight: bold;
border-bottom: 1px solid white;
text-align: center;
padding: 0 3px;
}
tbody {
td:nth-child(1) {
color: $townsfolk;
}
td:nth-child(2) {
color: $demon;
}
td:nth-child(4) {
text-align: center;
}
}
</style>

View File

@ -66,7 +66,8 @@ export default new Vuex.Store({
reference: false, reference: false,
reminder: false, reminder: false,
role: false, role: false,
roles: false roles: false,
voteHistory: false
}, },
edition: "tb", edition: "tb",
roles: getRolesByEdition(), roles: getRolesByEdition(),

View File

@ -9,7 +9,6 @@ const set = key => (state, val) => {
* @param state session state * @param state session state
* @param index seat of the player in the circle * @param index seat of the player in the circle
* @param vote true or false * @param vote true or false
* @param indexAdjusted seat of the player counted from the nominated player
*/ */
const handleVote = (state, [index, vote]) => { const handleVote = (state, [index, vote]) => {
if (!state.nomination) return; if (!state.nomination) return;
@ -29,7 +28,8 @@ const state = () => ({
votes: [], votes: [],
lockedVote: 0, lockedVote: 0,
votingSpeed: 3000, votingSpeed: 3000,
isVoteInProgress: false isVoteInProgress: false,
voteHistory: []
}); });
const getters = {}; const getters = {};
@ -56,6 +56,30 @@ const mutations = {
state.lockedVote = lockedVote || 0; state.lockedVote = lockedVote || 0;
state.isVoteInProgress = isVoteInProgress || false; state.isVoteInProgress = isVoteInProgress || false;
}, },
/**
* Create an entry in the vote history log. Requires current player array because it might change later in the game.
* Only stores votes that were completed.
* @param state
* @param players
*/
addHistory(state, players) {
if (!state.nomination || state.lockedVote <= players.length) return;
const isBanishment = players[state.nomination[1]].team === "traveler";
state.voteHistory.push({
nominator: players[state.nomination[0]].name,
nominee: players[state.nomination[1]].name,
type: isBanishment ? "Banishment" : "Execution",
majority: Math.ceil(
players.filter(player => !player.isDead || isBanishment).length / 2
),
votes: players
.filter((player, index) => state.votes[index])
.map(({ name }) => name)
});
},
clearHistory(state) {
state.voteHistory = [];
},
/** /**
* Store a vote with and without syncing it to the live session. * Store a vote with and without syncing it to the live session.
* This is necessary in order to prevent infinite voting loops. * This is necessary in order to prevent infinite voting loops.

View File

@ -128,6 +128,13 @@ class LiveSession {
break; break;
case "nomination": case "nomination":
if (!this._isSpectator) return; if (!this._isSpectator) return;
if (!params) {
// create vote history record
this._store.commit(
"session/addHistory",
this._store.state.players.players
);
}
this._store.commit("session/nomination", { nomination: params }); this._store.commit("session/nomination", { nomination: params });
break; break;
case "swap": case "swap":
@ -245,7 +252,7 @@ class LiveSession {
isVoteInProgress, isVoteInProgress,
fabled fabled
} = data; } = data;
this._store.commit("toggleNight", isNight); this._store.commit("toggleNight", !!isNight);
this._store.commit("session/nomination", { this._store.commit("session/nomination", {
nomination, nomination,
votes, votes,