// Imports import * as Auth from "/services/auth/auth.js"; import * as Common from "/services/common/common.js"; 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 * as ElectionModel from "/services/model/election-model.js"; import * as RoundModel from "/services/model/round-model.js"; import { Delete } from "/services/common/delete.js"; // DOM elements export async function mount(where, parent) { const candidateListComponent = new CandidateList(parent); await candidateListComponent.mount(where); return candidateListComponent; } class CandidateList { constructor(parent) { this.method = null; this.parent = parent; this.AreaModel = AreaModel.getAreaModel(); this.PartyModel = PartyModel.getPartyModel(); this.CandidateListModel = CandidateListModel.getCandidateListModel(); this.CandidateModel = CandidateModel.getCandidateModel(); this.ElectionModel = ElectionModel.getElectionModel(); this.RoundModel = RoundModel.getRoundModel(); } 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(); this.ElectionModel.current_user = await Auth.GetUser(); this.RoundModel.current_user = await Auth.GetUser(); const mountpoint = where; document.getElementById(mountpoint).innerHTML = /* HTML */ ` <header id="dropdown-candidate-lists" class="card-header clickable"> <p id="candidate-list-title" class="card-header-title"> Liste des candidats par circonscription </p> <a> <span class="icon is-large"> <i class="fas fa-2x fa-caret-down"></i> </span> </a> </header> <div id="candidate-lists-dropdown-content" class="columns card-content"> <div class="column"> <h5 class="title is-5"> Circonscriptions </h5> <div id="areas-round"></div> </div> <div class="column"> <nav class="level"> <div class="level-left"> <h5 class="title is-5"> Listes </h5> </div> <div class="level-right"> <button id="candidate-list-clone" class="button large-button is-primary" title="Importer une liste" > <span class="icon is-small"> <i class="fas fa-download"></i> </span> </button> <button id="candidate-list-new" class="button large-button is-success" title="Ajouter une liste" > <span class="icon is-small"> <i class="fas fa-plus"></i> </span> </button> </div> </nav> <div id="candidate-lists-list"></div> </div> <div class="column is-two-thirds"> <div id="candidate-list" class="card-no-hover"></div> </div> </div> `; this.mountModal("candidateList-modal"); this.mountModalClone("candidateList-clone-modal"); this.handleDom(); } areaTemplate(area) { return /* HTML */ `<div class="card card-list"> <div id="areas-area-${area.ID}" class="card-content clickable"> <div class="content"> <nav class="level"> <div class="level-left"> ${area.Name} (Nombre de siège : ${area.SeatNumber}) </div> </nav> </div> </div> </div>`; } candidateListTemplate(candidateList) { return /* HTML */ `<div class="card card-list"> <div id="candidateLists-candidateList-${candidateList.ID}" class="card-content clickable" > <div class="content"> <nav class="level"> <div id="candidateLists-candidateList-desc-${candidateList.ID}" class="level-left" > ${candidateList.Name} </div> <div class="level-right"> <a id="candidateLists-candidateList-edit-${candidateList.ID}" class="button is-link is-small" title="Modifier" > <span class="icon is-small"> <i class="fas fa-pen"></i> </span> </a> <a id="candidateLists-candidateList-delete-${candidateList.ID}" class="button is-danger is-small" title="Supprimer" > <span class="icon is-small"> <i class="fas fa-trash"></i> </span> </a> </div> </nav> </div> </div> </div>`; } candidateListToCloneTemplate(candidateList) { return /* HTML */ `<div class="card card-list"> <div id="candidateLists-candidateListToClone-${candidateList.ID}" class="card-content clickable" > <div class="content"> <nav class="level"> <div id="candidateLists-candidateList-desc-${candidateList.ID}" class="level-left" > ${candidateList.Name} </div> </nav> </div> </div> </div>`; } mountModal(where) { const mountpoint = where; document.getElementById(mountpoint).innerHTML = /* HTML */ ` <div class="modal-background"></div> <div class="modal-card" id="candidateList-modal-card"> <header class="modal-card-head"> <p class="modal-card-title">Ajout/modification d'une liste</p> <button class="delete" aria-label="close" id="candidateList-modal-close" ></button> </header> <section class="modal-card-body"> <div class="field"> <div class="control"> <input class="input" type="hidden" id="candidateList-modal-id" disabled /> </div> </div> <div class="field"> <label>Name</label> <div class="control"> <input class="input" type="text" id="candidateList-modal-name" /> </div> </div> <div class="field"> <label>Parti</label><br /> <div class="control select"> <select name="party" id="candidateList-modal-party"></select> </div> </div> </section> <footer class="modal-card-foot"> <button id="candidateList-modal-save" class="button is-success"> Sauvegarder </button> <button id="candidateList-modal-cancel" class="button"> Annuler </button> </footer> </div> `; } mountModalClone(where) { const mountpoint = where; document.getElementById(mountpoint).innerHTML = /* HTML */ ` <div class="modal-background"></div> <div class="modal-card" id="candidateList-clone-modal-card"> <header class="modal-card-head"> <p class="modal-card-title">Importer une liste</p> <button class="delete" aria-label="close" id="candidateList-clone-modal-close" ></button> </header> <section id="candidateLists-toclone" class="modal-card-body"></section> </div> `; } async displayCandidates() { document.getElementById("candidate-list").innerHTML = /* HTML */ `<div class="table-container" > <table class="table is-bordered is-narrow 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(); candidates.sort(function (a, b) { return a.Rank > b.Rank; }); const markup = candidates .map((candidate) => this.candidateTemplate(candidate)) .join(""); document.getElementById("candidates").innerHTML = markup; let newRank = 1; candidates.forEach((candidate) => { if (candidate.Rank >= newRank) newRank = candidate.Rank + 1; }); let newCandidate = { ID: 0, FullName: "", Rank: newRank, CommunityCounseller: false, Birthdate: "2000-01-01", PotentialIncompatibility: false, Refused: false, Removed: false, }; document.getElementById("candidates").innerHTML += this.candidateTemplate( newCandidate ); document .getElementById(`candidates-candidate-edit-0`) .addEventListener("click", function () { candidateListHandler.method = "POST"; candidateListHandler.saveCandidate(newCandidate.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" title="Valider" > <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" title="Supprimer" > <span class="icon is-small"> <i class="fas fa-trash"></i> </span> </a> </td> </tr> `; } handleDom() { let candidateListHandler = this; document .getElementById(`candidateList-modal-close`) .addEventListener("click", function () { Common.toggleModal("candidateList-modal", "candidateList-modal-card"); }); document .getElementById(`candidateList-modal-cancel`) .addEventListener("click", function () { Common.toggleModal("candidateList-modal", "candidateList-modal-card"); }); document .getElementById(`candidateList-clone-modal-close`) .addEventListener("click", function () { Common.toggleModal( "candidateList-clone-modal", "candidateList-clone-modal-card" ); }); document .getElementById(`candidateList-modal-save`) .addEventListener("click", async function () { if ( document.getElementById("candidateList-modal-party").value === "0" ) { Messages.Show("is-danger", "Veuillez sélectionner un parti."); return; } await candidateListHandler.saveCandidateList(); }); } async displayAreas() { document.getElementById("areas-round").innerHTML = /* HTML */ ``; let candidateListHandler = this; let areas = await this.updateAreas(); const markup = areas.map((area) => this.areaTemplate(area)).join(""); document.getElementById("areas-round").innerHTML += markup; areas.map((area) => { document .getElementById(`areas-area-${area.ID}`) .addEventListener("click", async function () { candidateListHandler.emptyCandidateList(); await candidateListHandler.activateArea(area); await candidateListHandler.displayCandidateLists(); }); }); this.emptyCandidateList(); } async updateAreas() { let candidateListHandler = this; let areas = await this.AreaModel.getAreas(); return areas.filter(function (area) { return area.ElectionID == candidateListHandler.round.ElectionID; }); } async activateArea(areaToActivate) { this.area = areaToActivate; let areas = await this.updateAreas(); areas.forEach((area) => { document .getElementById(`areas-area-${area.ID}`) .classList.remove("active-card"); }); document .getElementById(`areas-area-${areaToActivate.ID}`) .classList.add("active-card"); } 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"); this.displayCandidates(); } async displayCandidateLists() { let candidateListHandler = this; let candidateLists = await this.updateCandidateLists(); document.getElementById("candidate-lists-list").innerHTML = /* HTML */ ``; const markup = candidateLists .map((candidateList) => this.candidateListTemplate(candidateList)) .join(""); document.getElementById("candidate-lists-list").innerHTML += markup; candidateLists.map(async (candidateList) => { let party = await this.PartyModel.getParty(candidateList.PartyID); document.getElementById( `candidateLists-candidateList-desc-${candidateList.ID}` ).innerHTML += "(" + party.Name + ")"; document .getElementById(`candidateLists-candidateList-edit-${candidateList.ID}`) .addEventListener("click", function () { candidateListHandler.editCandidateList(candidateList); }); document .getElementById( `candidateLists-candidateList-delete-${candidateList.ID}` ) .addEventListener("click", function () { new Delete(() => { candidateListHandler.deleteCandidateList(candidateList); }); }); document .getElementById(`candidateLists-candidateList-${candidateList.ID}`) .addEventListener("click", async function () { await candidateListHandler.activateCandidateList(candidateList); await candidateListHandler.displayCandidates(); }); }); document .getElementById(`candidate-list-new`) .addEventListener("click", function () { candidateListHandler.newCandidateList(); }); document .getElementById(`candidate-list-clone`) .addEventListener("click", function () { candidateListHandler.cloneCandidateListModal(); }); } async updateCandidateLists() { let candidateListHandler = this; let candidateLists = await this.CandidateListModel.getCandidateLists(); return candidateLists.filter(function (candidateList) { return ( candidateList.AreaID == candidateListHandler.area.ID && candidateList.RoundID == candidateListHandler.round.ID ); }); } 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(); document.getElementById("candidateList-modal-id").value = null; document.getElementById("candidateList-modal-party").value = null; document.getElementById("candidateList-modal-name").value = null; Common.toggleModal("candidateList-modal", "candidateList-modal-card"); } async cloneCandidateListModal() { let election = await this.ElectionModel.getElection(this.area.ID); let rounds = await this.RoundModel.getRounds(); rounds = rounds.filter((round) => round.ElectionID == election.ID); let roundsID = []; rounds.forEach((round) => { if (this.round.ID !== round.ID) roundsID.push(round.ID); }); let candidateLists = await this.CandidateListModel.getCandidateLists(); candidateLists = candidateLists.filter( (candidateList) => candidateList.AreaID == this.area.ID && roundsID.includes(candidateList.RoundID) ); Common.toggleModal( "candidateList-clone-modal", "candidateList-clone-modal-card" ); const markup = candidateLists .map((candidateList) => this.candidateListToCloneTemplate(candidateList)) .join(""); document.getElementById("candidateLists-toclone").innerHTML = markup; candidateLists.map((candidateList) => { document .getElementById( `candidateLists-candidateListToClone-${candidateList.ID}` ) .addEventListener("click", async () => { this.cloneCandidateList(candidateList); Common.toggleModal( "candidateList-clone-modal", "candidateList-clone-modal-card" ); }); }); } async editCandidateList(candidateList) { this.method = "PUT"; await this.refreshParties(); document.getElementById("candidateList-modal-id").value = candidateList.ID; document.getElementById("candidateList-modal-party").value = candidateList.PartyID; document.getElementById("candidateList-modal-name").value = candidateList.Name; Common.toggleModal("candidateList-modal", "candidateList-modal-card"); } async refreshParties() { let selectParties = document.getElementById("candidateList-modal-party"); let parties = await this.PartyModel.getParties(); for (let i = selectParties.options.length - 1; i >= 0; i--) { selectParties.remove(i); } let el = document.createElement("option"); el.textContent = "Veuillez sélectionner un parti"; el.value = 0; selectParties.appendChild(el); parties.forEach((party) => { el = document.createElement("option"); el.textContent = party.Name; el.value = party.ID; selectParties.appendChild(el); }); } async saveCandidateList() { if (this.method == "POST") document.getElementById("candidateList-modal-id").value = null; if ( this.CandidateListModel.checkInputs( this.method, parseInt(document.getElementById("candidateList-modal-id").value), document.getElementById("candidateList-modal-name").value, parseInt(document.getElementById("candidateList-modal-party").value) ) ) { let candidateList = await this.CandidateListModel.saveCandidateList( this.method, parseInt(document.getElementById("candidateList-modal-id").value), document.getElementById("candidateList-modal-name").value, parseInt(document.getElementById("candidateList-modal-party").value), this.round.ID, this.area.ID ); await this.displayCandidateLists(); Common.toggleModal("candidateList-modal", "candidateList-modal-card"); this.activateCandidateList(candidateList); return candidateList; } } async deleteCandidateList(candidateList) { await this.CandidateListModel.deleteCandidateList(candidateList.ID); await this.displayCandidateLists(); this.emptyCandidate(); this.displayCandidateLists(); } 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(); } async cloneCandidateList(candidateList) { console.log(candidateList); let candidateListCloned = await this.CandidateListModel.saveCandidateList( "POST", null, candidateList.Name, candidateList.PartyID, this.round.ID, this.area.ID ); for (let i in candidateList.Candidates) { await this.CandidateModel.saveCandidate( "POST", null, candidateListCloned.ID, candidateList.Candidates[i].FullName, candidateList.Candidates[i].Rank, candidateList.Candidates[i].CommunityCounseller, candidateList.Candidates[i].Birthdate, candidateList.Candidates[i].PotentialIncompatibility, candidateList.Candidates[i].Refused, candidateList.Candidates[i].Removed ); } await this.displayCandidateLists(); this.activateCandidateList(candidateListCloned); return candidateListCloned; } emptyCandidateList() { this.area = null; document.getElementById("candidate-lists-list").innerHTML = ""; this.emptyCandidate(); } emptyCandidate() { this.candidateList = null; document.getElementById("candidate-list").innerHTML = ""; } }