Skip to content

Commit

Permalink
✨ Election turnout overview / graph for election managers (#418)
Browse files Browse the repository at this point in the history
Parent issue: sequentech/meta#206
  • Loading branch information
Findeton committed Apr 12, 2024
1 parent e22b971 commit 26f2706
Show file tree
Hide file tree
Showing 13 changed files with 558 additions and 5 deletions.
4 changes: 3 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ module.exports = function (grunt) {
{src: ['node_modules/common-ui/dist/img/flags.png'], dest: 'dist/img/flags.png'},
{src: ['node_modules/common-ui/dist/utils.js'], dest: 'dist/utils.js'},
{src: ['node_modules/common-ui/dist/intlTelInput.css'], dest: 'dist/intlTelInput.css'},
{src: ['node_modules/angular-moment-picker/dist/angular-moment-picker.min.css'], dest: 'dist/angular-moment-picker.min.css'},
{
expand: true,
cwd:'node_modules/common-ui/themes',
Expand Down Expand Up @@ -335,7 +336,8 @@ module.exports = function (grunt) {
{selector:'head',html:'<link rel="stylesheet" id="theme" data-base="/admin/" href="/admin/themes/default/app.min.css">'},
{selector:'head',html:'<link rel="stylesheet" id="plugins" data-base="/admin/" href="/admin/plugins.css">'},
{selector:'head',html:'<link rel="stylesheet" id="vendor-css" data-base="/admin/" href="/admin/vendor.min.css">'},
{selector:'head',html:'<link rel="stylesheet" href="/admin/intlTelInput.css" />'}
{selector:'head',html:'<link rel="stylesheet" href="/admin/intlTelInput.css" />'},
{selector:'head',html:'<link rel="stylesheet" href="/admin/angular-moment-picker.min.css" />'}
]
},
src:'index.html',
Expand Down
4 changes: 3 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ angular.module(
'angularLoad',
'ng-autofocus',
'LocalStorageModule',
'common-ui'
'common-ui',
'chart.js',
'moment-picker'
]);

/**
Expand Down
1 change: 1 addition & 0 deletions app.less
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
@import "avAdmin/admin-directives/social-networks/social-item-directive.less";
@import "avAdmin/admin-directives/social-networks/social-networks.less";
@import "avAdmin/admin-directives/social-networks/change-social-modal.less";
@import "avAdmin/admin-directives/dashboard/turnout-graph.less";
@import "avAdmin/admin-directives/dashboard/dashboard.less";
@import "avAdmin/admin-directives/question/question.less";
@import "avAdmin/admin-directives/elauth/elauth.less";
Expand Down
1 change: 1 addition & 0 deletions avAdmin/admin-directives/dashboard/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ <h4>
</div>
</div>
<!-- end of general -->
<div av-turnout-graph></div>

<!-- allows to choose which children election to show -->
<div class="row general">
Expand Down
53 changes: 53 additions & 0 deletions avAdmin/admin-directives/dashboard/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,47 @@ angular.module('avAdmin')
);
}

function downloadTurnout() {
var turnoutData;
Authmethod.getTurnout(scope.election.id)
.then(function (response){
if (200 !== response.status) {
console.log("Error fetching turnout: ");
console.log(response);
scope.error = response.data;
return;
}

turnoutData = response.data;
var electionIds = Object.keys(response.data);

return $q.all(electionIds.map(function (electionId) {
return ElectionsApi.getElection(electionId);
}));
})
.then(function (electionsData) {
console.log(turnoutData);
console.log(electionsData);
var csvFile = "ID,Name,Participation,Census,Participation quota\n";
csvFile += Object.keys(turnoutData)
.map(function (electionId) {

var ballotBoxElection = electionsData.find(function (el) { return String(el.id) === String(electionId); });
return [
"" + electionId,
ballotBoxElection.title,
"" + turnoutData[electionId].total_votes,
"" + turnoutData[electionId].users,
"" + (turnoutData[electionId].total_votes / Math.max(1, turnoutData[electionId].users))
].join(",");
})
.join("\n");

var blob = new $window.Blob([csvFile], {type: "text/csv"});
$window.saveAs(blob, "turnout_" + scope.election.id + ".csv");
});
}

function setAutoreload(electionId)
{
ElectionsApi.autoreloadStats(
Expand Down Expand Up @@ -1390,6 +1431,17 @@ angular.module('avAdmin')
return scope.hasPerms(["schedule-events", "edit"]);
}
},
{
i18nString: 'downloadTurnout',
iconClass: 'fa fa-clock',
actionFunc: function() { return scope.downloadTurnout(); },
enableFunc: function() {
return true;
},
permsFunc: function() {
return scope.hasPerms(["view"]);
}
},
];

scope.permittedActions = function () {
Expand Down Expand Up @@ -1480,6 +1532,7 @@ angular.module('avAdmin')
launchKeyDistributionCeremony: launchKeyDistributionCeremony,
launchOpeningCeremony: launchOpeningCeremony,
configureScheduledEvents: configureScheduledEvents,
downloadTurnout: downloadTurnout
});

// initialize
Expand Down
45 changes: 45 additions & 0 deletions avAdmin/admin-directives/dashboard/turnout-graph.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<div ng-if="show" class="chart">
<div class="chart-title text-center" ng-i18next>avAdmin.turnoutChart.title</div>
<canvas class="chart chart-bar" chart-data="data" chart-labels="labels"
chart-series="series" chart-click="onClick" chart-options="options" chart-colors="colors"></canvas>
<div class="legend-container">
<div class="row-container">
<div class="checkbox-container" ng-repeat="title in seriesBase track by $index">
<input
type="checkbox"
id="enable-election-graph-{{$index}}"
class="checkbox-series"
ng-model="selectedSeries[$index]" />
<div class="color" ng-style="{'background-color': colors[$index]}"></div>
<label for="enable-election-graph-{{$index}}">
{{seriesBase[$index]}}
</label>
</div>
<div class="time-selector-container">
<label for="time-basis" ng-i18next>avAdmin.turnoutChart.timeResolution</label>
<select name="time-basis" id="time-basis" ng-model="timeBasis.value">
<option value="auto" ng-i18next>avAdmin.turnoutChart.auto</option>
<option value="hour" ng-i18next>avAdmin.turnoutChart.hour</option>
<option value="day" ng-i18next>avAdmin.turnoutChart.day</option>
<option value="week" ng-i18next>avAdmin.turnoutChart.week</option>
<option value="month" ng-i18next>avAdmin.turnoutChart.month</option>
</select>
</div>
</div>
<div class="row-container">
<div class="start-date-container">
<span ng-i18next>avAdmin.turnoutChart.startDate</span>
<div moment-picker="selectedDates.minDate" max-view="hour" class="date-edit">
<span>{{ selectedDates.minDate }}</span>
<i class="fa fa-pencil"></i><br/>
</div>
</div>
<div class="end-date-container">
<span ng-i18next>avAdmin.turnoutChart.endDate</span>
<div moment-picker="selectedDates.maxDate" max-view="hour" class="date-edit">
<span>{{ selectedDates.maxDate }}</span>
<i class="fa fa-pencil"></i><br/> </div>
</div>
</div>
</div>
</div>
Loading

0 comments on commit 26f2706

Please sign in to comment.