From b09210b1c7426db62dd9291c5deaf3652e060359 Mon Sep 17 00:00:00 2001 From: Alexis POYEN <apoyen@grandlyon.com> Date: Thu, 11 Jun 2020 17:05:08 +0200 Subject: [PATCH] Resolve "Handle candidates" --- web/components/management/candidate-lists.js | 233 +++++++++++++++++-- web/components/management/rounds-card.js | 4 + web/services/model/candidate-model.js | 115 +++++++++ 3 files changed, 331 insertions(+), 21 deletions(-) create mode 100644 web/services/model/candidate-model.js diff --git a/web/components/management/candidate-lists.js b/web/components/management/candidate-lists.js index c58460c..1b0dd46 100644 --- a/web/components/management/candidate-lists.js +++ b/web/components/management/candidate-lists.js @@ -5,13 +5,11 @@ import * as Messages from "/services/messages/messages.js"; import * as AreaModel from "/services/model/area-model.js"; import * as PartyModel from "/services/model/party-model.js"; import * as CandidateListModel from "/services/model/candidateList-model.js"; +import * as CandidateModel from "/services/model/candidate-model.js"; import { Delete } from "/services/common/delete.js"; // DOM elements -// local variables -let current_user; - export async function mount(where, parent) { const candidateListComponent = new CandidateList(parent); await candidateListComponent.mount(where); @@ -25,12 +23,14 @@ class CandidateList { this.AreaModel = AreaModel.getAreaModel(); this.PartyModel = PartyModel.getPartyModel(); this.CandidateListModel = CandidateListModel.getCandidateListModel(); + this.CandidateModel = CandidateModel.getCandidateModel(); } async mount(where) { this.AreaModel.current_user = await Auth.GetUser(); this.PartyModel.current_user = await Auth.GetUser(); this.CandidateListModel.current_user = await Auth.GetUser(); + this.CandidateModel.current_user = await Auth.GetUser(); const mountpoint = where; document.getElementById(mountpoint).innerHTML = /* HTML */ ` <header class="card-header"> @@ -50,15 +50,11 @@ class CandidateList { <div class="column"> <div id="candidate-lists-list"></div> </div> - <div class="column"> - <div id="active-capturer" class="card"></div> - </div> - <div class="column"> - <div id="available-capturer" class="card"></div> + <div class="column is-two-thirds"> + <div id="candidate-list" class="card"></div> </div> </div> `; - current_user = await Auth.GetUser(); this.mountModal("candidateList-modal"); this.handleDom(); } @@ -167,6 +163,161 @@ class CandidateList { `; } + async displayCandidates() { + document.getElementById("candidate-list").innerHTML = /* HTML */ `<div + class="table-container" + > + <table class="table is-bordered is-narrow is-hoverable is-fullwidth"> + <thead> + <tr class="is-selected"> + <th hidden>Id</th> + <th>Nom complet</th> + <th>Rang</th> + <th>Conseiller communautaire</th> + <th>Date de naissance</th> + <th>Incompatibilité potentielle</th> + <th>Refusé</th> + <th>Supprimé</th> + <th>Actions</th> + </tr> + </thead> + <tbody id="candidates"></tbody> + </table> + </div> `; + + let candidates = await this.updateCandidates(); + const markup = candidates + .map((candidate) => this.candidateTemplate(candidate)) + .join(""); + document.getElementById("candidates").innerHTML = markup; + + let candidate = { + ID: 0, + FullName: "", + Rank: 0, + CommunityCounseller: false, + Birthdate: "2000-01-01", + PotentialIncompatibility: false, + Refused: false, + Removed: false, + }; + document.getElementById("candidates").innerHTML += this.candidateTemplate( + candidate + ); + document + .getElementById(`candidates-candidate-edit-0`) + .addEventListener("click", function () { + candidateListHandler.method = "POST"; + candidateListHandler.saveCandidate(candidate.ID); + }); + document.getElementById(`candidates-candidate-delete-0`).remove(); + + let candidateListHandler = this; + candidates.map((candidate) => { + document + .getElementById(`candidates-candidate-edit-${candidate.ID}`) + .addEventListener("click", function () { + candidateListHandler.method = "PUT"; + candidateListHandler.saveCandidate(candidate.ID); + }); + document + .getElementById(`candidates-candidate-delete-${candidate.ID}`) + .addEventListener("click", function () { + new Delete(() => { + candidateListHandler.deleteCandidate(candidate); + }); + }); + }); + } + + candidateTemplate(candidate) { + return /* HTML */ ` + <tr id="candidates-candidate-${candidate.ID}"> + <td hidden> + <input + class="input" + type="number" + id="${candidate.ID}-candidate-id" + value="${candidate.ID}" + disabled + /> + </td> + <td> + <input + class="input" + type="text" + id="${candidate.ID}-candidate-fullname" + value="${candidate.FullName}" + /> + </td> + <td> + <input + class="input" + type="number" + id="${candidate.ID}-candidate-rank" + value="${candidate.Rank}" + /> + </td> + <td> + <input + type="checkbox" + id="${candidate.ID}-candidate-community-counseller" + ${candidate.CommunityCounseller ? "checked" : ""} + /> + </td> + <td> + <input + class="input" + type="date" + id="${candidate.ID}-candidate-birthdate" + value="${candidate.Birthdate}" + /> + </td> + <td> + <input + type="checkbox" + id="${candidate.ID}-candidate-potential-incompatibility" + ${candidate.PotentialIncompatibility ? "checked" : ""} + /> + </td> + <td> + <input + type="checkbox" + id="${candidate.ID}-candidate-refused" + ${candidate.Refused ? "checked" : ""} + /> + </td> + <td> + <input + type="checkbox" + id="${candidate.ID}-candidate-removed" + ${candidate.Removed ? "checked" : ""} + /> + </td> + <td> + <a + id="candidates-candidate-edit-${candidate.ID}" + class="button is-success is-small" + > + <span>Valider</span> + <span class="icon is-small"> + <i class="fas fa-check"></i> + </span> + </a> + <a + id="candidates-candidate-delete-${candidate.ID}" + class="button is-danger is-small" + > + <span>Supprimer</span> + <span class="icon is-small"> + <i class="fas fa-times"></i> + </span> + </a> + </td> + </tr> + `; + } + handleDom() { let candidateListHandler = this; document @@ -236,7 +387,18 @@ class CandidateList { document.getElementById("candidate-list-new").removeAttribute("disabled"); } - async activateCandidateList() {} + async activateCandidateList(candidateListToActivate) { + this.candidateList = candidateListToActivate; + let candidateLists = await this.updateCandidateLists(); + candidateLists.forEach((candidateList) => { + document + .getElementById(`candidateLists-candidateList-${candidateList.ID}`) + .classList.remove("active-card"); + }); + document + .getElementById(`candidateLists-candidateList-${candidateListToActivate.ID}`) + .classList.add("active-card"); + } async displayCandidateLists() { let candidateListHandler = this; @@ -265,13 +427,12 @@ class CandidateList { candidateListHandler.deleteCandidateList(candidateList); }); }); - // document - // .getElementById(`areas-area-${candidateList.ID}`) - // .addEventListener("click", async function () { - // await candidateListHandler.activateArea(candidateList); - // candidateListHandler.area = candidateList; - // await candidateListHandler.displayCandidateLists(); - // }); + document + .getElementById(`candidateLists-candidateList-${candidateList.ID}`) + .addEventListener("click", async function () { + await candidateListHandler.activateCandidateList(candidateList); + await candidateListHandler.displayCandidates(); + }); }); } @@ -283,6 +444,14 @@ class CandidateList { }); } + async updateCandidates() { + let candidateListHandler = this; + let candidates = await this.CandidateModel.getCandidates(); + return candidates.filter(function (candidate) { + return candidate.CandidateListID == candidateListHandler.candidateList.ID; + }); + } + async newCandidateList() { this.method = "POST"; await this.refreshParties(); @@ -337,15 +506,37 @@ class CandidateList { await this.displayCandidateLists(); Common.toggleModal("candidateList-modal", "candidateList-modal-card"); this.activateCandidateList(candidateList); - // TODO open desks - // TODO open candidateLists return candidateList; } async deleteCandidateList(candidateList) { await this.CandidateListModel.deleteCandidateList(candidateList.ID); await this.displayCandidateLists(); - // TODO empty desks - // TODO empty candidateLists + // TODO empty Candidates + } + + async saveCandidate(candidateID) { + let candidate = await this.CandidateModel.saveCandidate( + this.method, + candidateID, + this.candidateList.ID, + document.getElementById(candidateID + "-candidate-fullname").value, + parseInt(document.getElementById(candidateID + "-candidate-rank").value), + document.getElementById(candidateID + "-candidate-community-counseller") + .checked, + document.getElementById(candidateID + "-candidate-birthdate").value, + document.getElementById( + candidateID + "-candidate-potential-incompatibility" + ).checked, + document.getElementById(candidateID + "-candidate-refused").checked, + document.getElementById(candidateID + "-candidate-removed").checked + ); + await this.displayCandidates(); + return candidate; + } + + async deleteCandidate(candidate) { + await this.CandidateModel.deleteCandidate(candidate.ID); + await this.displayCandidates(); } } diff --git a/web/components/management/rounds-card.js b/web/components/management/rounds-card.js index 1dfb0e2..7793cca 100644 --- a/web/components/management/rounds-card.js +++ b/web/components/management/rounds-card.js @@ -226,6 +226,10 @@ class Round { .getElementById(`rounds-round-${roundToActivate.ID}`) .classList.add("active-card"); // TODO unselect candidateLists + document.getElementById("rounds-list").setAttribute("hidden", "true"); + document.getElementById("rounds-list").parentElement.className = "column"; + document.getElementById("candidate-lists").parentElement.className = + "column is-full"; } async newRound() { diff --git a/web/services/model/candidate-model.js b/web/services/model/candidate-model.js new file mode 100644 index 0000000..a415342 --- /dev/null +++ b/web/services/model/candidate-model.js @@ -0,0 +1,115 @@ +import * as Messages from "/services/messages/messages.js"; + +let candidateModel; + +export function getCandidateModel() { + if (candidateModel == null) { + candidateModel = new CandidateModel(); + } + return candidateModel; +} + +class CandidateModel { + constructor() {} + + async getCandidate(id) { + if (this.candidates == null) await this.refreshCandidates(); + let candidateToGet; + this.candidates.forEach((candidate) => { + if (candidate.ID == id) candidateToGet = candidate; + }); + return candidateToGet; + } + + async getCandidates() { + if (this.candidates == null) { + try { + const response = await fetch("/api/Candidate/", { + method: "GET", + headers: new Headers({ + "XSRF-Token": this.current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Candidates could not be fetched (status ${response.status})` + ); + } + this.candidates = await response.json(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } + } + return this.candidates; + } + + async saveCandidate( + method, + ID, + CandidateListID, + FullName, + Rank, + CommunityCounseller, + Birthdate, + PotentialIncompatibility, + Refused, + Removed + ) { + try { + const response = await fetch("/api/Candidate/" + ID, { + method: method, + headers: new Headers({ + "XSRF-Token": this.current_user.xsrftoken, + }), + body: JSON.stringify({ + ID: ID, + CandidateListID: CandidateListID, + FullName: FullName, + Rank: Rank, + CommunityCounseller: CommunityCounseller, + Birthdate: Birthdate, + PotentialIncompatibility: PotentialIncompatibility, + Refused: Refused, + Removed: Removed, + }), + }); + if (response.status !== 200) { + throw new Error( + `Candidate could not be updated or created (status ${response.status})` + ); + } + this.refreshCandidates(); + return await response.json(); + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + return; + } + } + + async deleteCandidate(ID) { + try { + const response = await fetch("/api/Candidate/" + ID, { + method: "delete", + headers: new Headers({ + "XSRF-Token": this.current_user.xsrftoken, + }), + }); + if (response.status !== 200) { + throw new Error( + `Candidate could not be deleted (status ${response.status})` + ); + } + } catch (e) { + Messages.Show("is-warning", e.message); + console.error(e); + } + await this.refreshCandidates(); + } + + async refreshCandidates() { + this.candidates = null; + await this.getCandidates(); + } +} -- GitLab