Skip to content
Snippets Groups Projects
Commit 9d810354 authored by Alexis POYEN's avatar Alexis POYEN
Browse files

Resolve "Display news flow"

parent 47c633a6
No related branches found
No related tags found
No related merge requests found
...@@ -239,6 +239,7 @@ func (d *DataHandler) deleteVote(w http.ResponseWriter, r *http.Request, id int) ...@@ -239,6 +239,7 @@ func (d *DataHandler) deleteVote(w http.ResponseWriter, r *http.Request, id int)
return return
} }
deskRound.Completed = false deskRound.Completed = false
deskRound.DateCompletion = time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)
d.db.Save(&deskRound) d.db.Save(&deskRound)
d.db.Delete(&o) d.db.Delete(&o)
......
...@@ -131,10 +131,10 @@ func appTests(t *testing.T) { ...@@ -131,10 +131,10 @@ func appTests(t *testing.T) {
// //Check that on Vote deletion, deskRound is updated // //Check that on Vote deletion, deskRound is updated
do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":false}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}],"Completed":true,"DateCompletion":"20`) do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":false}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}],"Completed":true,"DateCompletion":"20`)
do("DELETE", "/api/Vote/1", xsrfHeader, ``, 200, ``) do("DELETE", "/api/Vote/1", xsrfHeader, ``, 200, ``)
do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}],"Completed":false,"DateCompletion":"20`) do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[{"ID":3,"DeskRoundID":1,"CandidateListID":0,"VoiceNumber":158,"Blank":true,"NullVote":false},{"ID":4,"DeskRoundID":1,"CandidateListID":0,"VoiceNumber":158,"Blank":false,"NullVote":true}]}`)
// Verify that on Desk deletion deskRounds are deleted // Verify that on Desk deletion deskRounds are deleted
do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"20`) do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
do("DELETE", "/api/Desk/1", xsrfHeader, ``, 200, ``) do("DELETE", "/api/Desk/1", xsrfHeader, ``, 200, ``)
do("GET", "/api/DeskRound/1", xsrfHeader, ``, 404, `id is missing`) do("GET", "/api/DeskRound/1", xsrfHeader, ``, 404, `id is missing`)
......
// Imports // Imports
import * as Auth from "/services/auth/auth.js";
import * as results from "/services/election/calculate-election-generic.js"; import * as results from "/services/election/calculate-election-generic.js";
import * as PartyModel from "/services/model/party-model.js";
import * as Scroller from "/services/common/scroller.js";
export async function mount(where, round) { export async function mount(where, round) {
const resultComponent = new ResultComponent(round); const resultComponent = new ResultComponent(round);
await resultComponent.mount(where); await resultComponent.mount(where);
await resultComponent.calculateResults(); await resultComponent.calculateResults();
resultComponent.displayResults();
} }
class ResultComponent { class ResultComponent {
constructor(round) { constructor(round) {
this.round = round; this.round = round;
this.PartyModel = PartyModel.getPartyModel();
} }
async mount(where) { async mount(where) {
this.PartyModel.current_user = await Auth.GetUser();
const mountpoint = where; const mountpoint = where;
document.getElementById(mountpoint).innerHTML = /* HTML */ ` document.getElementById(mountpoint).innerHTML = /* HTML */ `
<div class="tabs is-boxed is-toggle is-fullwidth"> <div class="tabs is-boxed is-toggle is-fullwidth">
...@@ -76,7 +82,7 @@ class ResultComponent { ...@@ -76,7 +82,7 @@ class ResultComponent {
</button> </button>
</header> </header>
<div class="card-content"> <div class="card-content">
<div id="round-list" class="content"> <div id="news-flow" class="content">
Flux d'actualité Flux d'actualité
</div> </div>
</div> </div>
...@@ -100,22 +106,55 @@ class ResultComponent { ...@@ -100,22 +106,55 @@ class ResultComponent {
</div> </div>
</div> </div>
`; `;
this.calculator = await results.mountCalculator(this.round);
this.handleDom(); this.handleDom();
document.getElementById("areas").click(); document.getElementById("areas").click();
this.calculator = await results.mountCalculator(this.round); }
resultFlowTemplate(zone) {
return /* HTML */ `<div class="card-list card-no-hover">
<div class="card-content">
<div id="flow-content-${zone.ID}" class="content">
<h5 class="title is-5">${zone.Name}</h5>
</div>
</div>
</div>`;
}
async progressBarTemplate(candidateList) {
let party = await this.PartyModel.getParty(candidateList.PartyID);
return /* HTML */ `<div class="progressBar">
<div
class="progressBarValue"
style="background-color : ${party.Color}; width : ${candidateList.Percentage}%"
>
${candidateList.Name +
" (" +
candidateList.VoiceNumber +
" voix soit : " +
candidateList.Percentage +
"%)"}
</div>
</div>`;
} }
handleDom() { handleDom() {
let resultHandler = this;
document.getElementById("areas").addEventListener("click", function () { document.getElementById("areas").addEventListener("click", function () {
resultHandler.zone = "areas";
resultHandler.calculateResults();
resultHandler.displayResults();
document.getElementById("sections").setAttribute("class", ""); document.getElementById("sections").setAttribute("class", "");
document.getElementById("areas").setAttribute("class", "is-active"); document.getElementById("areas").setAttribute("class", "is-active");
}); });
document.getElementById("sections").addEventListener("click", function () { document.getElementById("sections").addEventListener("click", function () {
resultHandler.zone = "sections";
resultHandler.calculateResults();
resultHandler.displayResults();
document.getElementById("areas").setAttribute("class", ""); document.getElementById("areas").setAttribute("class", "");
document.getElementById("sections").setAttribute("class", "is-active"); document.getElementById("sections").setAttribute("class", "is-active");
}); });
let resultHandler = this;
document.getElementById("zoom-map").addEventListener("click", function () { document.getElementById("zoom-map").addEventListener("click", function () {
resultHandler.zoomMap(); resultHandler.zoomMap();
}); });
...@@ -132,8 +171,9 @@ class ResultComponent { ...@@ -132,8 +171,9 @@ class ResultComponent {
let radioButtons = document.getElementsByName("filter"); let radioButtons = document.getElementsByName("filter");
for (var i = 0; i < radioButtons.length; i++) { for (var i = 0; i < radioButtons.length; i++) {
radioButtons[i].addEventListener("click", (e) => { radioButtons[i].addEventListener("click", async (e) => {
this.calculateResults(); await this.calculateResults();
this.displayResults();
}); });
} }
} }
...@@ -151,7 +191,7 @@ class ResultComponent { ...@@ -151,7 +191,7 @@ class ResultComponent {
let resultHandler = this; let resultHandler = this;
document.getElementById("news-flow-section").parentElement.className = document.getElementById("news-flow-section").parentElement.className =
"column is-full"; "column is-full";
document.getElementById("news-flow-section").style.height = "auto"; document.getElementById("news-flow-section").style.height = "70vh";
document.getElementById("map-section").parentElement.className = "column"; document.getElementById("map-section").parentElement.className = "column";
document.getElementById("map-section").parentElement.style.display = "none"; document.getElementById("map-section").parentElement.style.display = "none";
document.getElementById("results-section").style.display = "none"; document.getElementById("results-section").style.display = "none";
...@@ -191,7 +231,69 @@ class ResultComponent { ...@@ -191,7 +231,69 @@ class ResultComponent {
} }
async calculateResults() { async calculateResults() {
let filter = document.querySelector('input[name="filter"]:checked').value; this.filter = document.querySelector('input[name="filter"]:checked').value;
await this.calculator.calculateResults(filter); this.results = await this.calculator.calculateResults(this.filter);
}
displayResults() {
console.log(this.results);
document.getElementById("news-flow").innerHTML = "";
if (this.zone === "areas") {
this.displayFlowAreas();
} else if (this.zone === "sections") {
this.displayFlowSections();
}
let scroller = Scroller.scrollInit("news-flow");
}
async displayFlowAreas() {
let resultHandler = this;
this.results.areasResults.sort(function (a, b) {
return b.DateCompletion - a.DateCompletion;
});
for (let j in this.results.areasResults) {
let area = this.results.areasResults[j];
if (area.status === resultHandler.filter) {
document.getElementById(
"news-flow"
).innerHTML += this.resultFlowTemplate(area);
for (let i in area.candidateLists) {
document.getElementById(
"flow-content-" + area.ID
).innerHTML += await resultHandler.progressBarTemplate(
area.candidateLists[i]
);
}
}
}
}
async displayFlowSections() {
let resultHandler = this;
let sections = [];
this.results.areasResults.forEach((area) => {
sections = sections.concat(area.Sections);
});
sections.sort(function (a, b) {
return b.DateCompletion - a.DateCompletion;
});
for (let j in sections) {
let section = sections[j];
if (section.status === resultHandler.filter) {
document.getElementById(
"news-flow"
).innerHTML += this.resultFlowTemplate(section);
for (let i in section.candidateLists) {
document.getElementById(
"flow-content-" + section.ID
).innerHTML += await resultHandler.progressBarTemplate(
section.candidateLists[i]
);
}
}
}
} }
} }
export function scrollInit(divName) {
let scroller = new Scroller(divName);
}
class Scroller {
constructor(divName) {
this.elmnt = document.getElementById(divName);
this.reachedMaxScroll = false;
this.elmnt.scrollTop = 0;
this.previousScrollTop = 0;
this.scrollDiv();
this.elmnt.addEventListener("mouseover", () => {
this.pauseScroll();
});
this.elmnt.addEventListener("mouseout", () => {
this.resumeScroll();
});
}
scrollDiv() {
if (!this.reachedMaxScroll) {
this.elmnt.scrollBy({ top: 5, left: 0, behavior: "smooth" });
this.reachedMaxScroll =
this.elmnt.scrollTop >=
this.elmnt.scrollHeight - this.elmnt.offsetHeight;
this.scrollTimeout = setTimeout(() => {
this.scrollDiv();
}, 100);
} else {
this.reachedMaxScroll = this.elmnt.scrollTop == 0 ? false : true;
this.elmnt.scrollBy({ top: -5, left: 0, behavior: "smooth" });
this.scrollTimeout = setTimeout(() => {
this.scrollDiv();
}, 100);
}
}
pauseScroll() {
clearInterval(this.scrollTimeout);
}
resumeScroll() {
this.scrollDiv();
}
}
...@@ -98,7 +98,7 @@ class DirectMetropolitanCalculator { ...@@ -98,7 +98,7 @@ class DirectMetropolitanCalculator {
} }
this.areasResults = await this.calculateAreasResults(); this.areasResults = await this.calculateAreasResults();
console.log(this); return this;
} }
async calculateRoundResults() { async calculateRoundResults() {
...@@ -176,6 +176,13 @@ class DirectMetropolitanCalculator { ...@@ -176,6 +176,13 @@ class DirectMetropolitanCalculator {
} }
area.Sections = sections; area.Sections = sections;
let lastDate = new Date(area.Sections[0].DateCompletion);
area.Sections.forEach((section) => {
if (lastDate - new Date(section.DateCompletion) < 0)
lastDate = new Date(section.DateCompletion);
});
area.DateCompletion = lastDate;
area.stats = await this.calculateStats(deskRounds); area.stats = await this.calculateStats(deskRounds);
let flag = true; let flag = true;
...@@ -183,7 +190,7 @@ class DirectMetropolitanCalculator { ...@@ -183,7 +190,7 @@ class DirectMetropolitanCalculator {
case "partial": case "partial":
if (area.stats.VotesExpressed === 0) { if (area.stats.VotesExpressed === 0) {
area.status = "no_results"; area.status = "no_results";
return; return area;
} }
area.status = "partial"; area.status = "partial";
break; break;
...@@ -196,7 +203,7 @@ class DirectMetropolitanCalculator { ...@@ -196,7 +203,7 @@ class DirectMetropolitanCalculator {
area.status = "completed"; area.status = "completed";
} else { } else {
area.status = "incompleted"; area.status = "incompleted";
return; return area;
} }
break; break;
case "validated": case "validated":
...@@ -208,7 +215,7 @@ class DirectMetropolitanCalculator { ...@@ -208,7 +215,7 @@ class DirectMetropolitanCalculator {
area.status = "validated"; area.status = "validated";
} else { } else {
area.status = "not validated"; area.status = "not validated";
return; return area;
} }
} }
...@@ -220,7 +227,7 @@ class DirectMetropolitanCalculator { ...@@ -220,7 +227,7 @@ class DirectMetropolitanCalculator {
0 0
); );
candidateList.Percentage = candidateList.Percentage =
(candidateList.VoiceNumber / area.stats.VotesExpressed) * 100; Number((candidateList.VoiceNumber / area.stats.VotesExpressed) * 100).toFixed(2);
}); });
area.candidateLists = candidateListToKeep; area.candidateLists = candidateListToKeep;
area.candidateLists.sort((a, b) => { area.candidateLists.sort((a, b) => {
...@@ -246,13 +253,20 @@ class DirectMetropolitanCalculator { ...@@ -246,13 +253,20 @@ class DirectMetropolitanCalculator {
} }
} }
let lastDate = new Date(deskRounds[0].DateCompletion);
deskRounds.forEach((desk) => {
if (lastDate - new Date(desk.DateCompletion) < 0)
lastDate = new Date(desk.DateCompletion);
});
section.DateCompletion = lastDate;
section.stats = await this.calculateStats(deskRounds); section.stats = await this.calculateStats(deskRounds);
let flag = true; let flag = true;
switch (this.filter) { switch (this.filter) {
case "partial": case "partial":
if (section.stats.VotesExpressed === 0) { if (section.stats.VotesExpressed === 0) {
section.status = "no_results"; section.status = "no_results";
return; return section;
} }
section.status = "partial"; section.status = "partial";
break; break;
...@@ -265,7 +279,7 @@ class DirectMetropolitanCalculator { ...@@ -265,7 +279,7 @@ class DirectMetropolitanCalculator {
section.status = "completed"; section.status = "completed";
} else { } else {
section.status = "incompleted"; section.status = "incompleted";
return; return section;
} }
break; break;
case "validated": case "validated":
...@@ -277,7 +291,7 @@ class DirectMetropolitanCalculator { ...@@ -277,7 +291,7 @@ class DirectMetropolitanCalculator {
section.status = "validated"; section.status = "validated";
} else { } else {
section.status = "not validated"; section.status = "not validated";
return; return section ;
} }
} }
...@@ -294,7 +308,7 @@ class DirectMetropolitanCalculator { ...@@ -294,7 +308,7 @@ class DirectMetropolitanCalculator {
0 0
); );
candidateList.Percentage = candidateList.Percentage =
(candidateList.VoiceNumber / section.stats.VotesExpressed) * 100; Number((candidateList.VoiceNumber / section.stats.VotesExpressed) * 100).toFixed(2);
}); });
section.candidateLists = candidateLists; section.candidateLists = candidateLists;
section.candidateLists.sort((a, b) => { section.candidateLists.sort((a, b) => {
......
...@@ -120,13 +120,21 @@ select { ...@@ -120,13 +120,21 @@ select {
} }
#round-desks .column, #round-desks .column,
#candidate-lists .column { #candidate-lists .column,
#news-flow {
overflow-y: auto; overflow-y: auto;
} }
#news-flow,
#news-flow .content {
flex: 1;
}
#round-desks .columns, #round-desks .columns,
#candidate-lists .columns { #candidate-lists .columns,
#news-flow-section .card-content {
max-height: 90%; max-height: 90%;
display: flex;
} }
.card-header-success { .card-header-success {
...@@ -154,11 +162,25 @@ select { ...@@ -154,11 +162,25 @@ select {
background-color: #fff; background-color: #fff;
} }
.filter{ .filter {
text-align: center; text-align: center;
} }
#news-flow-section { #news-flow-section {
height: 45vh; height: 45vh;
margin-bottom: 15px;; margin-bottom: 15px;
}
.progressBar {
width: 99%;
margin: 3px;
background-color: lightgray;
border-radius: 5px;
}
.progressBarValue {
height: 30px;
white-space: nowrap;
padding: 4px;
border-radius: 5px;
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment