Skip to content
Snippets Groups Projects
candidate-lists.js 23.6 KiB
Newer Older
// 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
        <a>
          <span class="icon is-large">
            <i class="fas fa-2x fa-caret-down"></i>
      <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 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();
Alexis POYEN's avatar
Alexis POYEN committed
    candidates.sort(function (a, b) {
      return a.Rank > b.Rank;
    });
    const markup = candidates
      .map((candidate) => this.candidateTemplate(candidate))
      .join("");
    document.getElementById("candidates").innerHTML = markup;

Alexis POYEN's avatar
Alexis POYEN committed
    let newRank = 1;
    candidates.forEach((candidate) => {
      if (candidate.Rank >= newRank) newRank = candidate.Rank + 1;
    });

    let newCandidate = {
      ID: 0,
      FullName: "",
Alexis POYEN's avatar
Alexis POYEN committed
      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>
  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("");
Alexis POYEN's avatar
Alexis POYEN committed
    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();
        });
Alexis POYEN's avatar
Alexis POYEN committed

    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 = "";
  }