Vote + Results done

This commit is contained in:
2024-09-12 23:36:55 +02:00
parent 20b47856d5
commit 49e2b18e56
17 changed files with 698 additions and 19 deletions

8
static/css/404.css Normal file
View File

@@ -0,0 +1,8 @@
body {
background-color: #11111b;
text-align: center;
}
h1, h3, p, a {
color: white;
}

View File

@@ -9,6 +9,7 @@ body {
position: fixed;
bottom: 0;
width: 100%;
max-height: 50px;
display: flex;
background-color: #b4befe;
justify-content: center;
@@ -21,7 +22,16 @@ body {
border-radius: 5px;
color: #1e1e2e;
font-family: "Segoe UI";
font-size: 20px;
font-size: 14px;
}
.app {
margin:auto;
display: flex;
flex-direction: column;
width: 100%;
max-width: 500px;
height: calc(100vh - 60px);
}
.app > h2 {
@@ -30,4 +40,58 @@ body {
.app > h1 {
color: yellow;
}
.app > select {
width: 100%;
}
.app > input {
width: 100%;
}
.app > textarea {
width: 100%;
height: 100%;
resize: vertical;
}
.buttons > button {
font-size: 16px;
margin: 4px 0 4px 0;
padding: 5px;
background-color: cornflowerblue;
color: white;
border: none;
border-radius: 5px;
}
.buttons {
width: 100%;
display: grid;
gap: 5px;
grid-template-columns: repeat(2, 50% [col-start]);
}
.left {
grid-column-start: 1;
grid-column-end: 2;
}
.right {
grid-column-start: 2;
grid-column-end: 3;
}
.confirm {
margin: auto;
width: fit-content;
text-align: center;
}
.confirm > h1 {
color: yellow;
}
.confirm > h3 {
color: white;
}

77
static/css/results.css Normal file
View File

@@ -0,0 +1,77 @@
body {
background-color: #11111b;
padding:0;
margin:0;
}
.footer {
margin: 0;
position: fixed;
bottom: 0;
width: 100%;
max-height: 50px;
display: flex;
background-color: #b4befe;
justify-content: center;
}
.footer > a {
padding: 10px;
margin: 5px;
background-color: #94e2d5;
border-radius: 5px;
color: #1e1e2e;
font-family: "Segoe UI";
font-size: 14px;
}
.app {
margin: auto;
height: calc(100vh + 60px);
width: 100%;
max-width: 500px;
}
.app > p {
color: white;
line-break: strict;
}
.app > h1 {
color: yellow;
}
.app > h2 {
color:white;
}
.app > h3 {
color: white;
}
.buttons > button {
font-size: 16px;
margin: 4px 0 4px 0;
padding: 5px;
background-color: cornflowerblue;
color: white;
border: none;
border-radius: 5px;
}
.buttons {
width: 100%;
display: grid;
gap: 5px;
grid-template-columns: repeat(2, 50% [col-start]);
}
.left {
grid-column-start: 1;
grid-column-end: 2;
}
.right {
grid-column-start: 2;
grid-column-end: 3;
}

View File

@@ -1 +1,18 @@
<h1>404 NOT FOUND</h1>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<base href="/" target="_top">
<link rel="stylesheet" href="/static/css/404.css">
<title>404 Not Found</title>
</head>
<body>
<h1>404</h1>
<h3>Not Found Error</h3>
<p>The page you are looking for does not exists.</p>
<a href="/">Return to home page.</a>
</body>
</html>

View File

@@ -1,12 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<base href="/" target="_top">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<base href="/" target="_top">
<script src="static/js/index.js" defer="defer"></script>
<title>VOTE!</title>
<link rel="stylesheet" href="static/css/index.css">
<link rel="stylesheet" href="static/css/index.css">
</head>
<body>
<div id="app" class="app"></div>

21
static/html/results.html Normal file
View File

@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<base href="/" target="_top">
<title>Résultats</title>
<link rel="stylesheet" href="static/css/results.css">
<script src="/static/js/results.js" defer="defer"></script>
</head>
<body>
<div id="app" class="app"></div>
<div id="footer" class="footer">
<a href="/">Voter</a>
<a href="/results">Résultats</a>
<a href="/archives">Archives</a>
</div>
</body>
</html>

View File

@@ -1,17 +1,24 @@
Vote = {
vote_plus_id: null,
vote_plus_nickname: null,
vote_plus_reason: null,
vote_plus_nickname: "",
vote_plus_reason: "",
vote_moins_id: null,
vote_moins_nickname: null,
vote_moins_reason: null
vote_moins_nickname: "",
vote_moins_reason: ""
}
load_page(0)
let _ = load_page(0)
async function load_page(id) {
if (get_state()) {
confirm_popup();
return;
}
let players = await fetch("data/players").then(r => r.json());
function load_page(id) {
const header = document.createElement("h1");
const buttons = document.createElement("div");
buttons.className = "buttons";
const vote_id = document.createElement("h2");
vote_id.textContent = "Pour qui votes-tu?"
@@ -20,11 +27,19 @@ function load_page(id) {
vote_nickname.textContent = "As-tu un surnom à lui donner?";
const vote_nickname_input = document.createElement("input");
vote_nickname_input.inputMode = "text";
vote_nickname_input.maxLength = 100;
const vote_reason = document.createElement("h2");
vote_reason.textContent = "Pourquoi votes-tu pour lui?";
const vote_reason_input = document.createElement("textarea");
vote_reason_input.maxLength = 1000;
players.forEach((player) => {
const player_option = document.createElement("option");
player_option.value = player["id"];
player_option.innerText = player["name"];
vote_id_select.appendChild(player_option);
})
if (id) {
vote_id_select.value = Vote.vote_moins_id;
vote_nickname_input.value = Vote.vote_moins_nickname;
@@ -33,12 +48,24 @@ function load_page(id) {
let previous = document.createElement("button");
previous.textContent = "Précédent";
previous.addEventListener("click", () => {
Vote.vote_moins_id = vote_id.value;
Vote.vote_moins_id = vote_id_select.value;
Vote.vote_moins_nickname = vote_nickname_input.value;
Vote.vote_moins_reason = vote_reason_input.value;
load_page(0)});
load_page(0)
});
let submit = document.createElement("button");
submit.textContent = "A Voté";
submit.addEventListener("click", async () => {
Vote.vote_moins_id = vote_id_select.value;
Vote.vote_moins_nickname = vote_nickname_input.value;
Vote.vote_moins_reason = vote_reason_input.value;
if (await send_vote(Vote)) {
confirm_popup();
save_state();
}
})
submit.className = "right";
previous.className = "left";
buttons.append(previous, submit);
} else {
vote_id_select.value = Vote.vote_plus_id;
@@ -48,15 +75,51 @@ function load_page(id) {
let next = document.createElement("button");
next.innerText = "Suivant";
next.addEventListener("click", () => {
Vote.vote_plus_id = vote_id.value;
Vote.vote_plus_id = vote_id_select.value;
Vote.vote_plus_nickname = vote_nickname_input.value;
Vote.vote_plus_reason = vote_reason_input.value;
load_page(1)
});
next.className = "right";
buttons.appendChild(next);
}
const div = document.getElementById("app");
div.innerHTML = "";
div.append(header,vote_id, vote_id_select, vote_nickname, vote_nickname_input, vote_reason, vote_reason_input, buttons);
div.append(header, vote_id, vote_id_select, vote_nickname, vote_nickname_input, vote_reason, vote_reason_input, buttons);
}
function confirm_popup() {
const div = document.getElementById("app");
div.innerText = "";
div.className = "confirm";
let success = document.createElement("h1");
success.textContent = "Merci d'avoir voté!"
let sub = document.createElement("h3");
sub.textContent = "Ton vote a bien été prit en compte!";
div.append(success, sub);
}
function save_state() {
// create cookie with expiration the next day.
let date = new Date(Date.now());
date.setDate(date.getDate() + 1);
date.setHours(0, 0, 0, 0);
document.cookie = "hasvoted=true; expires=" + date.toUTCString()
}
function get_state() {
// get the cookie if exists => already voted.
let cookie = document.cookie;
return cookie.includes("hasvoted=true");
}
async function send_vote(vote) {
if (vote.vote_plus_id === null || vote.vote_moins_id === null) {
return false;
}
vote.vote_plus_id = parseInt(vote.vote_plus_id, 10);
vote.vote_moins_id = parseInt(vote.vote_moins_id, 10);
let body = JSON.stringify(vote);
let result = await fetch(window.location.href + "post", {method: "POST", body: body}).then(r => r.status);
return result === 200;
}

152
static/js/results.js Normal file
View File

@@ -0,0 +1,152 @@
async function run() {
const votes = await fetch("data/votes").then(r => r.json());
const players = await fetch("data/players").then(r => r.json());
let id = 0;
if (votes.length === 0) {
show_no_votes();
} else {
show_plus(id, votes, players);}
}
function show_no_votes() {
const app = document.getElementById("app");
const sorry = document.createElement("h1");
sorry.textContent = "Désolé...";
sorry.style.textAlign = "center";
const expl = document.createElement("h3");
expl.textContent = "Mais il n'y a pas de votes pour le moment.";
expl.style.textAlign = "center";
app.append(sorry, expl);
}
function show_plus(id, votes, players) {
const app = document.getElementById("app");
app.innerHTML = "";
let vote = votes[id];
let player = players[vote["vote_plus_id"] - 1]["name"];
let nickname = vote["vote_plus_nickname"];
let reason = vote["vote_plus_reason"];
let moins = document.createElement("button");
moins.textContent = "Et en moins..."
moins.addEventListener("click", () => {show_moins(id, votes, players)})
moins.className = "right";
const vote_p = document.createElement("h2");
if (nickname === "") {
vote_p.innerHTML = `${player}`;
}
else {
vote_p.innerHTML = `${nickname} (${player})`
}
const vote_r = document.createElement("p");
vote_r.textContent = reason;
const head = document.createElement("h1");
head.innerText = "EN PLUS";
const buttons = document.createElement("div");
buttons.className = "buttons";
buttons.append(moins)
app.append(head, vote_p, vote_r, buttons);
}
function show_moins(id, votes, players) {
const app = document.getElementById("app");
app.innerHTML = "";
let vote = votes[id];
let nickname = vote["vote_moins_nickname"];
let reason = vote["vote_moins_reason"];
let player = players[vote["vote_moins_id"] - 1]["name"];
let next = document.createElement("button");
if (id === votes.length - 1) {
next.textContent = "Résultats";
} else {
next.textContent = "Prochain vote";
}
next.addEventListener("click", () => {
if (id === votes.length - 1) {
let _ = show_results(players)
} else {
show_plus(id+1, votes, players)
}
})
next.className = "right";
const vote_p = document.createElement("h2");
if (nickname === "") {
vote_p.innerHTML = `${player}`;
}
else {
vote_p.innerHTML = `${nickname} (${player})`
}
const vote_r = document.createElement("p");
vote_r.textContent = reason;
const head = document.createElement("h1");
head.innerText = "EN MOINS";
const buttons = document.createElement("div");
buttons.className = "buttons";
buttons.append(next)
app.append(head, vote_p, vote_r, buttons);
}
async function show_results(players) {
const app = document.getElementById("app");
app.innerHTML = ""
const res = document.createElement("h1");
res.textContent = "Résultats";
res.style.textAlign = "center";
app.append(res);
const vp = document.createElement("h1");
vp.textContent = "En plus:";
app.append(vp);
let results = await fetch("data/results").then(r => r.json());
let plus = results[0];
let moins = results[1];
let prev_score = null;
let counter = 0;
for (let i = 0; i < plus.length; i++) {
let p = plus[i];
let player = players[p[0] - 1]["name"];
let score = p[1];
if (prev_score == null || score < prev_score) {
counter += 1;
prev_score = score;
const place = document.createElement("h2");
place.textContent = `En ${counter}${counter === 1 ? "ère" : "ème"} place:`;
app.append(place);
}
const result = document.createElement("h3");
result.textContent = `${player} avec ${p[1]} votes!`;
app.append(result);
}
const sep = document.createElement("hr");
app.append(sep);
const vm = document.createElement("h1");
vm.textContent = "En moins:";
app.append(vm);
prev_score = null;
counter = 0;
for (let i = 0; i < moins.length; i++) {
let p = moins[i];
let player = players[p[0] - 1]["name"];
let score = p[1];
if (prev_score == null || score < prev_score) {
counter += 1;
prev_score = score;
const place = document.createElement("h2");
place.textContent = `En ${counter}${counter === 1 ? "ère" : "ème"} place:`;
app.append(place);
}
const result = document.createElement("h3");
result.textContent = `${player} avec ${score} votes!`;
app.append(result);
}
}
let _ = run();