From 54af653b69f20e2ac52cab5c0e022fec72bec591 Mon Sep 17 00:00:00 2001 From: Alexis POYEN <apoyen@grandlyon.com> Date: Wed, 3 Jun 2020 13:55:51 +0200 Subject: [PATCH] Feat : manage a round creation, updating, deletion, view --- data/test.db | Bin 65536 -> 69632 bytes web/components/management/candidate-lists.js | 2 +- web/components/management/election.js | 48 +-- web/components/management/round.js | 2 + web/components/management/rounds-card.js | 292 ++++++++++++++++++- web/services/common/getters.js | 39 +++ 6 files changed, 338 insertions(+), 45 deletions(-) create mode 100644 web/services/common/getters.js diff --git a/data/test.db b/data/test.db index f0fc7e7d6d6501152a1221e211ccefa82a4ddc90..04150ffcc3b3ba1f7d353fbfafed5b5e9bf1005a 100644 GIT binary patch delta 1818 zcma)+yKmD#9LH_v;lz1df<RG(3U1mZG^x&SrxGe{RjMKeO3MHeiqghHPC_EpZY9Lv zwB-+IWziL=SQ#K<WMHF6ES<_r45$NQX@wB#fW+B-#YvoE**EyU_xt>Qzx&?R>)!fP z@9O!ugke}5eMirkwG5Y)u)*Pv5%eoYY+;~3x)*&Cc_021+M)I-BJeA4i4=Vwi7j8h z_p9gI%eAWnwM<3GL~k#?k~bya&b17knyW2T_55t5P%Y;R)ndN7P^qNo*;=iVUV0cK z6Nv=Aa!W7FR+Pn>u4wiUAG<j|GBZxkjEr6%r&HEHvlmp0MMW#;=TX37UM;3*wW=%k zl=)0*4h2?=1zpKkR84ozE!NaI1yS$MD)UWC?1T>T$fQnkqSNLda>9J%dEMyo-^I<G z_qRC_ct<UVgJhzw&#EgK+`EA4vU6$5BE6&s$V4)UuZ)@JsLydEu`@kpHg>6fkDnp@ ziSdi(Uy?R|f{6Je`sG!OpwE85NU)BBJ@6fDg9dmD*1<+2PS?RG<@Y3UJCa5K($j~Z zG(n@nUQZ9MDRa77t7^WW&y%pHHPYI~Q1D<`V|zGrB|v~l3_J&uDC%Wk+$Jb&Y6=Tt zy%^3y7G|NCg&fUrLjp6z34;t2a<afN1CSkpX#Rf{tW4a&DQtS$4jpV;$ihKh<oOvv zW*OEc_@SnQgk>x<QlU)@JO=6Lo9I+zC-NW?4L=Kuq0L4-_9A4IDI1Rmh69}|lXy<b z$rA5Ew~BX42nZpQwO<-S)DH9x*dwV1?KU>SjFvu%a!z2O&;{mDxU>A_z$t}^tSE>E z!*zvOnq!GO&8L#Bm9-Qmu%g8CVryYWlZPA<cb2#0Kd!9ZG1h+Y0taP@?Y3n{65}8t zcUsAJV9$>JK-Lo&5%MgQ-C*q!hdm63KT6(HU{HhtBS~Cq8xOl^!JHBYteNF6c`TNJ z1>Gv+a||nSImyi**12;^Tw%Tvx<9N#-o`Sl3&e^f^Nb`5u-hSbN?c)H_3%bPuy%h~ gED4!IWb7>)Mm_0x>ojSQ#1*ztzp=3!+gOeL1E;!?Z~y=R delta 270 zcmZozz|zpbGC^8Uoq>Tt0El6LZ=#N|wmO5J{Y_r>Dh7V$76!hT{73nw^B&^4#C@0R zBNsO(KZhHOC7Ud(E^`a}_sxO=znCVgux_1f#{QKvmzP~!QIWA(b@Cmir<-rE#xZhn z*fG?KYilz$c}{j<FP?mt#hruy2LlJlzR6k~C%GCcIoZXPl^L5YC;#R6$gSC!%)u@$ zDaqKZIGKm*_U0d4Kba@1@ZXvIk<S>U39NCG0F#2i83tDV%?$h>`5*J&;NQ%DaI>Jo zLVi^q7G_z-;?(4l%>2A!R!&xCamJL?;_PB}pk5wMsKn+Q_BsxmSr+{9U$jAC(FXwl D(>F=; diff --git a/web/components/management/candidate-lists.js b/web/components/management/candidate-lists.js index ad1a49e..533831d 100644 --- a/web/components/management/candidate-lists.js +++ b/web/components/management/candidate-lists.js @@ -25,7 +25,7 @@ class CandidateList { <p class="card-header-title"> Liste des candidats </p> - <button id="round-new" class="button is-success" disabled> + <button id="candidate-list-new" class="button is-success" disabled> <span class="icon is-small"> <i class="fas fa-plus"></i> </span> diff --git a/web/components/management/election.js b/web/components/management/election.js index 6a33f95..95fc3ec 100644 --- a/web/components/management/election.js +++ b/web/components/management/election.js @@ -1,6 +1,7 @@ // Imports import * as Auth from "/services/auth/auth.js"; import * as Common from "/services/common/common.js"; +import * as Getters from "/services/common/getters.js"; import * as Messages from "/services/messages/messages.js"; import { Delete } from "/services/common/delete.js"; @@ -207,7 +208,7 @@ class Election { } async displayElections() { - let elections = await this.updateElections(); + let elections = await Getters.getElections(current_user); const markup = elections .map((election) => this.electionTemplate(election)) .join(""); @@ -294,7 +295,7 @@ class Election { this.parent.areaHandler.emptyAreas(); this.parent.sectionHandler.emptySections(); this.parent.deskHandler.emptyDesks(); - let elections = await this.updateElections(); + let elections = await Getters.getElections(current_user); elections.forEach((election) => { document .getElementById(`elections-election-${election.ID}`) @@ -367,26 +368,6 @@ class Election { return election; } - async updateElections() { - try { - const response = await fetch("/api/Election/", { - method: "GET", - headers: new Headers({ - "XSRF-Token": current_user.xsrftoken, - }), - }); - if (response.status !== 200) { - throw new Error( - `Elections could not be fetched (status ${response.status})` - ); - } - return await response.json(); - } catch (e) { - Messages.Show("is-warning", e.message); - console.error(e); - } - } - async deleteElection(election) { try { const response = await fetch("/api/Election/" + election.ID, { @@ -424,7 +405,8 @@ class Election { async saveCloneElection() { let electionCloned; - let electionToClone = await this.getElection( + let electionToClone = await getters.getElection( + current_user, document.getElementById("election-modal-id-clone").value ); @@ -465,24 +447,4 @@ class Election { this.parent.areaHandler.election = electionCloned; await this.parent.areaHandler.displayAreas(); } - - async getElection(id) { - try { - const response = await fetch("/api/Election/" + id, { - method: "GET", - headers: new Headers({ - "XSRF-Token": current_user.xsrftoken, - }), - }); - if (response.status !== 200) { - throw new Error( - `Election could not be fetched (status ${response.status})` - ); - } - return await response.json(); - } catch (e) { - Messages.Show("is-warning", e.message); - console.error(e); - } - } } diff --git a/web/components/management/round.js b/web/components/management/round.js index 4c89228..864b26b 100644 --- a/web/components/management/round.js +++ b/web/components/management/round.js @@ -35,6 +35,8 @@ class Round { </div> </div> </div> + + <div class="modal" id="round-modal"></div> `; current_user = await Auth.GetUser(); this.roundsHandler = RoundsCard.mount("rounds-list", this) diff --git a/web/components/management/rounds-card.js b/web/components/management/rounds-card.js index b6c94b0..f1bbb7f 100644 --- a/web/components/management/rounds-card.js +++ b/web/components/management/rounds-card.js @@ -1,5 +1,9 @@ // Imports import * as Auth from "/services/auth/auth.js"; +import * as Common from "/services/common/common.js"; +import * as Getters from "/services/common/getters.js"; +import * as Messages from "/services/messages/messages.js"; +import { Delete } from "/services/common/delete.js"; // DOM elements @@ -32,9 +36,295 @@ class Round { </button> </header> <div class="card-content"> - <div id="rounds-list" class="content">Liste des tours</div> + <div id="round-list" class="content">Liste des tours</div> </div> `; current_user = await Auth.GetUser(); + this.mountModal("round-modal"); + this.handleDom(); + this.displayRounds(); + this.refreshElections(); + } + + handleDom() { + let roundHandler = this; + document.getElementById(`round-new`).addEventListener("click", function () { + roundHandler.newRound(); + }); + + document + .getElementById(`round-modal-close`) + .addEventListener("click", function () { + Common.toggleModal("round-modal", "round-modal-card"); + }); + document + .getElementById(`round-modal-cancel`) + .addEventListener("click", function () { + Common.toggleModal("round-modal", "round-modal-card"); + }); + document + .getElementById(`round-modal-save`) + .addEventListener("click", async function () { + if (document.getElementById("round-modal-election-id").value === "0") { + Messages.Show("is-danger", "Veuillez sélectionner une élection."); + return; + } + await roundHandler.saveRound(); + }); + } + + async refreshElections() { + let selectElection = document.getElementById("round-modal-election-id"); + let elections = await Getters.getElections(current_user); + elections.forEach((election) => {}); + for (let i = selectElection.options.length - 1; i >= 0; i--) { + selectElection.remove(i); + } + + let el = document.createElement("option"); + el.textContent = "Veuillez sélectionner une élection"; + el.value = 0; + selectElection.appendChild(el); + elections.forEach((election) => { + el = document.createElement("option"); + el.textContent = election.Name; + el.value = election.ID; + selectElection.appendChild(el); + }); + } + + mountModal(where) { + const mountpoint = where; + document.getElementById(mountpoint).innerHTML = /* HTML */ ` + <div class="modal-background"></div> + <div class="modal-card" id="round-modal-card"> + <header class="modal-card-head"> + <p class="modal-card-title">Ajout/modification d'un tour</p> + <button + class="delete" + aria-label="close" + id="round-modal-close" + ></button> + </header> + <section class="modal-card-body"> + <div class="field"> + <label>Id</label> + <div class="control"> + <input class="input" type="number" id="round-modal-id" disabled /> + </div> + </div> + <div class="field"> + <label>Tour de l'élection</label><br /> + <div class="control select"> + <select name="ballot-type" id="round-modal-election-id"></select> + </div> + </div> + <div class="field"> + <label>Date</label> + <div class="control"> + <input class="input" type="date" id="round-modal-date" /> + </div> + </div> + <div class="field"> + <label>Tour n°</label> + <div class="control"> + <input class="input" type="number" id="round-modal-round" /> + </div> + </div> + </section> + <footer class="modal-card-foot"> + <button id="round-modal-save" class="button is-success"> + Sauvegarder + </button> + <button id="round-modal-cancel" class="button">Annuler</button> + </footer> + </div> + `; + } + + async displayRounds() { + let rounds = await this.updateRounds(); + const markup = rounds.map((round) => this.roundTemplate(round)).join(""); + document.getElementById("round-list").innerHTML = markup; + + let roundHandler = this; + rounds.map(async (round) => { + document + .getElementById(`rounds-round-edit-${round.ID}`) + .addEventListener("click", function () { + roundHandler.editRound(round); + }); + let election = await Getters.getElection(current_user, round.ElectionID); + let html = document.getElementById(`rounds-round-desc-${round.ID}`).innerHTML + document.getElementById(`rounds-round-desc-${round.ID}`).innerHTML = + election.Name + + " " + + document.getElementById(`rounds-round-desc-${round.ID}`).innerHTML; + document + .getElementById(`rounds-round-delete-${round.ID}`) + .addEventListener("click", function () { + new Delete(() => { + roundHandler.deleteRound(round); + }); + }); + document + .getElementById(`rounds-round-${round.ID}`) + .addEventListener("click", function () { + // TODO open desk rounds + // TODO open candidate list + }); + }); + } + + roundTemplate(round) { + return /* HTML */ `<div class="card card-list"> + <div id="rounds-round-${round.ID}" class="card-content"> + <div class="content"> + <nav class="level"> + <div id="rounds-round-desc-${round.ID}" class="level-left"> + (tour : ${round.Round}, date : + ${new Date(round.Date).toLocaleDateString()}) + </div> + <div class="level-right"> + <a + id="rounds-round-edit-${round.ID}" + class="button is-link is-small" + title="Modifier" + > + <span class="icon is-small"> + <i class="fas fa-pen"></i> + </span> + </a> + <a + id="rounds-round-delete-${round.ID}" + class="button is-danger is-small" + title="Supprimer" + > + <span class="icon is-small"> + <i class="fas fa-times"></i> + </span> + </a> + </div> + </nav> + </div> + </div> + </div>`; + } + + async activateRound(round) { + // TODO unselect desks and candidateLists + let rounds = await this.updateRounds(); + rounds.forEach((round) => { + document + .getElementById(`rounds-round-${round.ID}`) + .classList.remove("active-card"); + }); + document + .getElementById(`rounds-round-${round.ID}`) + .classList.add("active-card"); + } + + newRound() { + this.method = "POST"; + document.getElementById("round-modal-id").value = null; + document.getElementById("round-modal-date").value = null; + document.getElementById("round-modal-round").value = null; + Common.toggleModal("round-modal", "round-modal-card"); + } + + editRound(round) { + this.method = "PUT"; + document.getElementById("round-modal-id").value = round.ID; + document.getElementById("round-modal-election-id").value = round.ElectionID; + document.getElementById("round-modal-date").value = new Date(round.Date).toISOString().split('T')[0]; + document.getElementById("round-modal-round").value = round.Round; + Common.toggleModal("round-modal", "round-modal-card"); + } + + async saveRound() { + let round; + if (this.method == "POST") + document.getElementById("round-modal-id").value = null; + + try { + const response = await fetch( + "/api/Round/" + document.getElementById("round-modal-id").value, + { + method: this.method, + headers: new Headers({ + "XSRF-Token": current_user.xsrftoken, + }), + body: JSON.stringify({ + ID: parseInt(document.getElementById("round-modal-id").value), + ElectionID: parseInt( + document.getElementById("round-modal-election-id").value + ), + Date: document.getElementById("round-modal-date").value, + Round: parseInt(document.getElementById("round-modal-round").value), + }), + } + ); + if (response.status !== 200) { + throw new Error( + `Area could not be updated or created (status ${response.status})` + ); + } + round = await response.json(); + this.displayRounds(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + return; + } + Common.toggleModal("round-modal", "round-modal-card"); + this.activateRound(round); + // TODO open desks + // TODO open candidateLists + return round; + } + + async updateRounds() { + try { + const response = await fetch("/api/Round/", { + method: "GET", + headers: new Headers({ + "XSRF-Token": current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Rounds could not be fetched (status ${response.status})` + ); + } + return await response.json(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } + } + + async deleteRound(round) { + try { + const response = await fetch("/api/Round/" + round.ID, { + method: "delete", + headers: new Headers({ + "XSRF-Token": current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Round could not be deleted (status ${response.status})` + ); + } + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } + this.displayRounds(); + // TODO empty desks + // TODO empty candidateLists + document + .getElementById("candidate-list-new") + .setAttribute("disabled", "true"); } } diff --git a/web/services/common/getters.js b/web/services/common/getters.js new file mode 100644 index 0000000..4691a74 --- /dev/null +++ b/web/services/common/getters.js @@ -0,0 +1,39 @@ +export async function getElections(current_user) { + try { + const response = await fetch("/api/Election/", { + method: "GET", + headers: new Headers({ + "XSRF-Token": current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Elections could not be fetched (status ${response.status})` + ); + } + return await response.json(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } +} + +export async function getElection(current_user, id) { + try { + const response = await fetch("/api/Election/" + id, { + method: "GET", + headers: new Headers({ + "XSRF-Token": current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Election could not be fetched (status ${response.status})` + ); + } + return await response.json(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } +} \ No newline at end of file -- GitLab