diff --git a/web/components/navbar/navbar.js b/web/components/navbar/navbar.js index cf58c25d9a8daff949745745544d7f622ffab4ca..f0e19ae61e6fada509b29abd512710fd2a471384 100644 --- a/web/components/navbar/navbar.js +++ b/web/components/navbar/navbar.js @@ -62,6 +62,9 @@ export async function CreateMenu() { <a class="navbar-item" href="#home" ><i class="navbar-menu-icon fas fa-home"></i>Accueil</a > + <a class="navbar-item" href="#visualization" + ><i class="navbar-menu-icon fas fa-poll"></i>Résultats</a + > ${user.role == "ADMIN" || "CAPTURER" ? /* HTML */ ` <a class="navbar-item" href="#votes" diff --git a/web/components/visualization/results-section.js b/web/components/visualization/results-section.js new file mode 100644 index 0000000000000000000000000000000000000000..cbee50f3b1aef0488a2e739bacef16c9ae8ba59e --- /dev/null +++ b/web/components/visualization/results-section.js @@ -0,0 +1,182 @@ +// Imports + +export async function mount(where, round) { + const resultComponent = new ResultComponent(round); + await resultComponent.mount(where); +} + +class ResultComponent { + constructor(round) { + this.round = round; + } + + async mount(where) { + const mountpoint = where; + document.getElementById(mountpoint).innerHTML = /* HTML */ ` + <div class="tabs is-boxed is-toggle is-fullwidth"> + <ul> + <li id="areas" class="is-active"> + <a> + <span>Circonscriptions</span> + </a> + </li> + <li id="sections"> + <a> + <span>Villes</span> + </a> + </li> + </ul> + </div> + <div class="control filter"> + <label class="radio"> + <input type="radio" name="answer" checked /> + Partiel + </label> + <label class="radio"> + <input type="radio" name="answer" /> + Complété + </label> + <label class="radio"> + <input type="radio" name="answer" /> + Validé + </label> + </div> + <div class="columns"> + <div class="column is-half"> + <div id="map-section" class="card-no-hover"> + <header class="card-header"> + <p class="card-header-title"> + Carte + </p> + <button id="zoom-map" class="button is-success"> + <span class="icon is-small"> + <i class="fas fa-search"></i> + </span> + </button> + </header> + <div class="card-content"> + <div id="round-list" class="content"> + La carte du tour + </div> + </div> + </div> + </div> + <div class="column"> + <div id="news-flow-section" class="card-no-hover"> + <header class="card-header"> + <p class="card-header-title"> + Actualités + </p> + <button id="zoom-news-flow" class="button is-success"> + <span class="icon is-small"> + <i class="fas fa-search"></i> + </span> + </button> + </header> + <div class="card-content"> + <div id="round-list" class="content"> + Flux d'actualité + </div> + </div> + </div> + <div id="results-section" class="card-no-hover" "> + <header class="card-header"> + <p class="card-header-title"> + Résultats + </p> + <button id="zoom-results" class="button is-success"> + <span class="icon is-small"> + <i class="fas fa-search"></i> + </span> + </button> + </header> + <div class="card-content"> + <div id="round-list" class="content"> + Résultats détaillés du tour + </div> + </div> + </div> + </div> + `; + this.handleDom(); + document.getElementById("areas").click(); + } + + handleDom() { + document.getElementById("areas").addEventListener("click", function () { + document.getElementById("sections").setAttribute("class", ""); + document.getElementById("areas").setAttribute("class", "is-active"); + }); + document.getElementById("sections").addEventListener("click", function () { + document.getElementById("areas").setAttribute("class", ""); + document.getElementById("sections").setAttribute("class", "is-active"); + }); + + let resultHandler = this; + document.getElementById("zoom-map").addEventListener("click", function () { + resultHandler.zoomMap(); + }); + document + .getElementById("zoom-news-flow") + .addEventListener("click", function () { + resultHandler.zoomNewsFlow(); + }); + document + .getElementById("zoom-results") + .addEventListener("click", function () { + resultHandler.zoomResults(); + }); + } + + zoomMap() { + let resultHandler = this; + document.getElementById("map-section").parentElement.className = + "column is-full"; + document.getElementById("zoom-map").addEventListener("click", function () { + resultHandler.unZoom(); + }); + } + + zoomNewsFlow() { + let resultHandler = this; + document.getElementById("news-flow-section").parentElement.className = + "column is-full"; + document.getElementById("news-flow-section").style.height = "auto"; + document.getElementById("map-section").parentElement.className = "column"; + document.getElementById("map-section").parentElement.style.display = "none"; + document.getElementById("results-section").style.display = "none"; + document + .getElementById("zoom-news-flow") + .addEventListener("click", function () { + resultHandler.unZoom(); + }); + } + + zoomResults(){ + let resultHandler = this; + document.getElementById("results-section").parentElement.className = + "column is-full"; + document.getElementById("map-section").parentElement.className = "column"; + document.getElementById("map-section").parentElement.style.display = "none"; + document.getElementById("news-flow-section").style.display = "none"; + document + .getElementById("zoom-results") + .addEventListener("click", function () { + resultHandler.unZoom(); + }); + } + + unZoom() { + document.getElementById("map-section").parentElement.className = + "column is-half"; + document.getElementById("news-flow-section").style.height = "45vh"; + document.getElementById("news-flow-section").parentElement.className = + "column is-half"; + document.getElementById("map-section").parentElement.style.display = + "block"; + document.getElementById("results-section").style.display = "block"; + document.getElementById("news-flow-section").style.display = "block"; + + this.handleDom(); + } +} diff --git a/web/components/visualization/round-selection.js b/web/components/visualization/round-selection.js new file mode 100644 index 0000000000000000000000000000000000000000..ee42f0ea63d0455df15d509e5b0e8b2789235df9 --- /dev/null +++ b/web/components/visualization/round-selection.js @@ -0,0 +1,77 @@ +// Imports +import * as Auth from "/services/auth/auth.js"; +import * as ElectionModel from "/services/model/election-model.js"; +import * as RoundModel from "/services/model/round-model.js"; + +export async function mount(where, parent) { + const roundSelectionComponent = new RoundSelectionComponent(parent); + await roundSelectionComponent.mount(where); +} + +class RoundSelectionComponent { + constructor(parent) { + this.parent = parent; + this.ElectionModel = ElectionModel.getElectionModel(); + this.RoundModel = RoundModel.getRoundModel(); + } + + async mount(where) { + this.ElectionModel.current_user = await Auth.GetUser(); + this.RoundModel.current_user = await Auth.GetUser(); + const mountpoint = where; + document.getElementById(mountpoint).innerHTML = /* HTML */ ` + <div class="container"> + <div class="card-no-hover"> + <header class="card-header"> + <p class="card-header-title"> + Tours + </p> + </header> + <div class="card-content"> + <div id="round-list" class="content">Liste des tours</div> + </div> + </div> + </div> + `; + this.displayRounds(); + } + + 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> + </nav> + </div> + </div> + </div>`; + } + + async displayRounds() { + let rounds = await this.RoundModel.getRounds(); + const markup = rounds.map((round) => this.roundTemplate(round)).join(""); + document.getElementById("round-list").innerHTML = markup; + + let roundHandler = this; + rounds.map(async (round) => { + let election = await this.ElectionModel.getElection(round.ElectionID); + document.getElementById(`rounds-round-desc-${round.ID}`).innerHTML = + election.Name + + " " + + document.getElementById(`rounds-round-desc-${round.ID}`).innerHTML; + document + .getElementById(`rounds-round-${round.ID}`) + .addEventListener("click", async function () { + roundHandler.activateRound(round); + }); + }); + } + + async activateRound(round) { + await this.parent.displayRound(round); + } +} diff --git a/web/components/visualization/visualization-page.js b/web/components/visualization/visualization-page.js new file mode 100644 index 0000000000000000000000000000000000000000..2fca33405759b4c6e308e1f60b09ef80a0d2172a --- /dev/null +++ b/web/components/visualization/visualization-page.js @@ -0,0 +1,29 @@ +// Imports +import * as RoundSelection from "/components/visualization/round-selection.js"; +import * as ResultSection from "/components/visualization/results-section.js"; + +export async function mount(where) { + const visualizationPage = new VisualizationPage(); + await visualizationPage.mount(where); +} + +class VisualizationPage { + constructor() {} + + async mount(where) { + const mountpoint = where; + document.getElementById(mountpoint).innerHTML = /* HTML */ ` + <section + id="visualization-section" + style="margin-bottom: 230px;" + ></section> + `; + this.handleDom(); + await RoundSelection.mount("visualization-section", this); + } + + handleDom() {} + async displayRound(round) { + this.resultSection = await ResultSection.mount("visualization-section", round); + } +} diff --git a/web/components/vote/vote-page.js b/web/components/vote/vote-page.js index 29a3e69d4a897b3f07fde76fd4f2acdc8593e300..e46f810bb0fca64ef0ec20b8d4e287af9cf97c8c 100644 --- a/web/components/vote/vote-page.js +++ b/web/components/vote/vote-page.js @@ -25,7 +25,7 @@ class VotePage { } handleDom() {} - async refreshVotes(){ + async refreshVotes() { this.voteHandler = await Vote.mount(this); } } diff --git a/web/main.js b/web/main.js index fe61cd18771f4f63e5157746e6f697ae2f9d6ddb..80c8c44e223a6f928e679ae58ae029517d5b9efb 100644 --- a/web/main.js +++ b/web/main.js @@ -2,6 +2,7 @@ import * as Home from "/components/home/home.js"; import * as Users from "/components/users/users.js"; import * as Management from "/components/management/management.js"; import * as Votes from "/components/vote/vote-page.js"; +import * as Visualization from "/components/visualization/visualization-page.js"; import * as Login from "/components/login/login.js"; import * as Navbar from "/components/navbar/navbar.js"; import { AnimateCSS } from "/services/common/common.js"; @@ -29,6 +30,11 @@ async function navigate() { await Votes.mount("main"); }); break; + case "#visualization": + load(mountPoint, async function () { + await Visualization.mount("main"); + }); + break; case "#users": load(mountPoint, async function () { await Users.mount("main"); diff --git a/web/services/model/election-model.js b/web/services/model/election-model.js index 9f1aaf6ed52873d280c126b8c12158ed141105fb..a69a6c2880c40d52e52e2b83ae9b99169ca5a6df 100644 --- a/web/services/model/election-model.js +++ b/web/services/model/election-model.js @@ -98,6 +98,6 @@ class ElectionModel { async refreshElections() { this.elections = null; - this.getElections(); + await this.getElections(); } } diff --git a/web/style.css b/web/style.css index 1926c071be7304cf6f6b616bccc170f5be96f2f1..a17f16fa97121b3c44ef700af1745a9c8ed98c90 100644 --- a/web/style.css +++ b/web/style.css @@ -149,3 +149,16 @@ select { color: #000; cursor: default; } + +.card-no-hover { + background-color: #fff; +} + +.filter{ + text-align: center; +} + +#news-flow-section { + height: 45vh; + margin-bottom: 15px;; +}