Merge remote-tracking branch 'consul/master' into iagirre-admin-poll-stats
This commit is contained in:
@@ -214,6 +214,8 @@ a {
|
||||
margin-bottom: $line-height / 2;
|
||||
|
||||
li {
|
||||
font-size: $base-font-size;
|
||||
margin-bottom: 0;
|
||||
margin-right: $line-height / 2;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
@@ -316,13 +318,16 @@ a {
|
||||
}
|
||||
|
||||
.tabs {
|
||||
border: {
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
};
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
margin-bottom: $line-height;
|
||||
|
||||
.tabs-title {
|
||||
font-size: $base-font-size;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tabs-title > a {
|
||||
color: $text-medium;
|
||||
margin-bottom: rem-calc(-1);
|
||||
@@ -376,6 +381,10 @@ a {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
// 02. Header
|
||||
// ----------
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// 06. Budget
|
||||
// 07. Proposals successful
|
||||
// 08. Polls
|
||||
// 09. Polls results and stats
|
||||
//
|
||||
|
||||
// 01. Votes and supports
|
||||
@@ -1799,3 +1800,59 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 09. Polls results and stats
|
||||
// ---------------------------
|
||||
|
||||
.polls-results-stats {
|
||||
|
||||
.sidebar {
|
||||
border-bottom: 1px solid $border;
|
||||
margin-bottom: $line-height;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
border-bottom: 0;
|
||||
border-right: 1px solid $border;
|
||||
}
|
||||
|
||||
.menu {
|
||||
padding: 0;
|
||||
|
||||
li a {
|
||||
color: $link;
|
||||
line-height: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
|
||||
caption {
|
||||
padding: $line-height / 2 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
|
||||
&.win {
|
||||
background: #009fde;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
|
||||
&.win {
|
||||
background: #ccedf8;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
font-size: rem-calc(60);
|
||||
font-weight: bold;
|
||||
line-height: rem-calc(60);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,9 +58,10 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController
|
||||
end
|
||||
|
||||
def poll_params
|
||||
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted, :summary, :description,
|
||||
geozone_ids: [],
|
||||
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
|
||||
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted,
|
||||
:summary, :description, :results_enabled, :stats_enabled,
|
||||
geozone_ids: [],
|
||||
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
|
||||
end
|
||||
|
||||
def search_params
|
||||
|
||||
@@ -6,6 +6,8 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
|
||||
def new
|
||||
load_shifts
|
||||
@shift = ::Poll::Shift.new
|
||||
@voting_polls = @booth.polls.current_or_incoming
|
||||
@recount_polls = @booth.polls.current_or_recounting_or_incoming
|
||||
end
|
||||
|
||||
def create
|
||||
|
||||
@@ -13,6 +13,9 @@ class Polls::QuestionsController < ApplicationController
|
||||
answer.touch if answer.persisted?
|
||||
answer.save!
|
||||
answer.record_voter_participation(token)
|
||||
@question.question_answers.where(question_id: @question).each do |answer|
|
||||
answer.set_most_voted
|
||||
end
|
||||
|
||||
@answers_by_question_id = { @question.id => params[:answer] }
|
||||
end
|
||||
|
||||
@@ -25,8 +25,13 @@ class PollsController < ApplicationController
|
||||
|
||||
@commentable = @poll
|
||||
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
|
||||
|
||||
end
|
||||
|
||||
def stats
|
||||
@stats = Poll::Stats.new(@poll).generate
|
||||
end
|
||||
|
||||
def results
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
module ShiftsHelper
|
||||
|
||||
def shift_vote_collection_dates(booth, polls)
|
||||
return [] if polls.blank?
|
||||
date_options((start_date(polls)..end_date(polls)), Poll::Shift.tasks[:vote_collection], booth)
|
||||
end
|
||||
|
||||
def shift_recount_scrutiny_dates(booth, polls)
|
||||
return [] if polls.blank?
|
||||
dates = polls.map(&:ends_at).map(&:to_date).sort.inject([]) do |total, date|
|
||||
initial_date = date < Date.current ? Date.current : date
|
||||
total << (initial_date..date + Poll::RECOUNT_DURATION).to_a
|
||||
|
||||
@@ -56,7 +56,7 @@ module Abilities
|
||||
|
||||
can [:index, :create, :edit, :update, :destroy], Geozone
|
||||
|
||||
can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers, :booth_assignments], Poll
|
||||
can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers, :booth_assignments, :results, :stats], Poll
|
||||
can [:read, :create, :update, :destroy, :available], Poll::Booth
|
||||
can [:search, :create, :index, :destroy], ::Poll::Officer
|
||||
can [:create, :destroy, :manage], ::Poll::BoothAssignment
|
||||
|
||||
@@ -7,6 +7,12 @@ module Abilities
|
||||
can [:read, :map, :summary, :share], Proposal
|
||||
can :read, Comment
|
||||
can :read, Poll
|
||||
can :results, Poll do |poll|
|
||||
poll.expired? && poll.results_enabled?
|
||||
end
|
||||
can :stats, Poll do |poll|
|
||||
poll.expired? && poll.stats_enabled?
|
||||
end
|
||||
can :read, Poll::Question
|
||||
can [:read, :welcome], Budget
|
||||
can :read, SpendingProposal
|
||||
@@ -23,7 +29,6 @@ module Abilities
|
||||
can [:read], Legislation::Question
|
||||
can [:create], Legislation::Answer
|
||||
can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation
|
||||
can :read_stats, Poll
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ class Poll
|
||||
end
|
||||
|
||||
def self.available
|
||||
where(polls: { id: Poll.current_or_incoming }).includes(:polls)
|
||||
where(polls: { id: Poll.current_or_recounting_or_incoming }).includes(:polls)
|
||||
end
|
||||
|
||||
def assignment_on_poll(poll)
|
||||
|
||||
@@ -55,4 +55,8 @@ class Poll::Question < ActiveRecord::Base
|
||||
where(poll_id: Poll.answerable_by(user).pluck(:id))
|
||||
end
|
||||
|
||||
def answers_total_votes
|
||||
question_answers.map { |a| Poll::Answer.where(question_id: self, answer: a.title).count }.sum
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -31,4 +31,24 @@ class Poll::Question::Answer < ActiveRecord::Base
|
||||
def self.last_position(question_id)
|
||||
where(question_id: question_id).maximum('given_order') || 0
|
||||
end
|
||||
|
||||
def total_votes
|
||||
Poll::Answer.where(question_id: question, answer: title).count
|
||||
end
|
||||
|
||||
def most_voted?
|
||||
self.most_voted
|
||||
end
|
||||
|
||||
def total_votes_percentage
|
||||
question.answers_total_votes == 0 ? 0 : (total_votes * 100) / question.answers_total_votes
|
||||
end
|
||||
|
||||
def set_most_voted
|
||||
answers = question.question_answers
|
||||
.map { |a| Poll::Answer.where(question_id: a.question, answer: a.title).count }
|
||||
is_most_voted = !answers.any?{ |a| a > self.total_votes }
|
||||
|
||||
self.update(most_voted: is_most_voted)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,110 +16,128 @@ class Poll
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
def total_participants
|
||||
total_participants_web + total_participants_booth
|
||||
stats_cache('total_participants') { total_participants_web + total_participants_booth }
|
||||
end
|
||||
|
||||
def total_participants_web
|
||||
total_web_valid + total_web_white + total_web_null
|
||||
stats_cache('total_participants_web') { total_web_valid + total_web_white + total_web_null }
|
||||
end
|
||||
|
||||
|
||||
def total_participants_web_percentage
|
||||
(total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants
|
||||
stats_cache('total_participants_web_percentage') {
|
||||
(total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants
|
||||
}
|
||||
end
|
||||
|
||||
def total_participants_booth
|
||||
voters.where(origin: 'booth').count
|
||||
stats_cache('total_participants_booth') { voters.where(origin: 'booth').count }
|
||||
end
|
||||
|
||||
|
||||
def total_participants_booth_percentage
|
||||
(total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f
|
||||
stats_cache('total_participants_booth_percentage') {
|
||||
(total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_web_valid
|
||||
voters.where(origin: 'web').count
|
||||
stats_cache('total_web_valid') { voters.where(origin: 'web').count }
|
||||
end
|
||||
|
||||
|
||||
def valid_percentage_web
|
||||
(total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f
|
||||
stats_cache('valid_percentage_web') {
|
||||
(total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_web_white
|
||||
0
|
||||
stats_cache('total_web_white') { 0 }
|
||||
end
|
||||
|
||||
|
||||
def white_percentage_web
|
||||
0
|
||||
stats_cache('white_percentage_web') { 0 }
|
||||
end
|
||||
|
||||
|
||||
def total_web_null
|
||||
0
|
||||
stats_cache('total_web_null') { 0 }
|
||||
end
|
||||
|
||||
|
||||
def null_percentage_web
|
||||
0
|
||||
stats_cache('null_percentage_web') { 0 }
|
||||
end
|
||||
|
||||
|
||||
def total_booth_valid
|
||||
recounts.sum(:total_amount)
|
||||
stats_cache('total_booth_valid') { recounts.sum(:total_amount) }
|
||||
end
|
||||
|
||||
|
||||
def valid_percentage_booth
|
||||
(total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f
|
||||
stats_cache('valid_percentage_booth') {
|
||||
(total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f
|
||||
}
|
||||
end
|
||||
|
||||
def total_booth_white
|
||||
recounts.sum(:white_amount)
|
||||
|
||||
def total_booth_white
|
||||
stats_cache('total_booth_white') { recounts.sum(:white_amount) }
|
||||
end
|
||||
|
||||
|
||||
def white_percentage_booth
|
||||
(total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f
|
||||
stats_cache('white_percentage_booth') {
|
||||
(total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_booth_null
|
||||
recounts.sum(:null_amount)
|
||||
stats_cache('total_booth_null') { recounts.sum(:null_amount) }
|
||||
end
|
||||
|
||||
|
||||
def null_percentage_booth
|
||||
(total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f
|
||||
stats_cache('null_percentage_booth') {
|
||||
(total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_valid_votes
|
||||
total_web_valid + total_booth_valid
|
||||
stats_cache('total_valid_votes') { total_web_valid + total_booth_valid }
|
||||
end
|
||||
|
||||
|
||||
def total_valid_percentage
|
||||
(total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f
|
||||
stats_cache('total_valid_percentage'){
|
||||
(total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_white_votes
|
||||
total_web_white + total_booth_white
|
||||
stats_cache('total_white_votes') { total_web_white + total_booth_white }
|
||||
end
|
||||
|
||||
|
||||
def total_white_percentage
|
||||
(total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f
|
||||
stats_cache('total_white_percentage') {
|
||||
(total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def total_null_votes
|
||||
total_web_null + total_booth_null
|
||||
stats_cache('total_null_votes') { total_web_null + total_booth_null }
|
||||
end
|
||||
|
||||
|
||||
def total_null_percentage
|
||||
(total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f
|
||||
stats_cache('total_null_percentage') {
|
||||
(total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f
|
||||
}
|
||||
end
|
||||
|
||||
def voters
|
||||
@poll.voters
|
||||
stats_cache('voters') { @poll.voters }
|
||||
end
|
||||
|
||||
|
||||
def recounts
|
||||
@poll.recounts
|
||||
stats_cache('recounts') { @poll.recounts }
|
||||
end
|
||||
|
||||
def stats_cache(key, &block)
|
||||
Rails.cache.fetch("polls_stats/#{@poll.id}/#{key}/v7", &block)
|
||||
Rails.cache.fetch("polls_stats/#{@poll.id}/#{key}", &block)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,6 +53,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if controller_name == "polls" && action_name == "edit" %>
|
||||
<div class="row">
|
||||
<fieldset class="fieldset">
|
||||
<legend><%= t('admin.polls.new.show_results_and_stats') %></legend>
|
||||
<%= f.check_box :results_enabled, checked: @poll.results_enabled?, label: t('admin.polls.new.show_results') %>
|
||||
<%= f.check_box :stats_enabled, checked: @poll.stats_enabled?, label: t('admin.polls.new.show_stats') %>
|
||||
<p class="small"><%= t('admin.polls.new.results_and_stats_reminder') %></p>
|
||||
</fieldset>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>
|
||||
<%= t("admin.poll_shifts.new.new_shift") %>
|
||||
<%= t("admin.poll_shifts.new.new_shift") %>
|
||||
</legend>
|
||||
|
||||
<div class="small-12 medium-3 column highlight padding">
|
||||
@@ -24,12 +24,12 @@
|
||||
<div class="small-12 medium-3 column">
|
||||
<label><%= t("admin.poll_shifts.new.date") %></label>
|
||||
<%= select 'shift[date]', 'vote_collection_date',
|
||||
options_for_select(shift_vote_collection_dates(@booth, @booth.polls.current_or_incoming)),
|
||||
{ prompt: t("admin.poll_shifts.new.select_date"),
|
||||
options_for_select(shift_vote_collection_dates(@booth, @voting_polls)),
|
||||
{ prompt: @voting_polls.present? ? t("admin.poll_shifts.new.select_date") : t("admin.poll_shifts.new.no_voting_days"),
|
||||
label: false },
|
||||
class: 'js-shift-vote-collection-dates' %>
|
||||
<%= select 'shift[date]', 'recount_scrutiny_date',
|
||||
options_for_select(shift_recount_scrutiny_dates(@booth, @booth.polls.current_or_recounting_or_incoming)),
|
||||
options_for_select(shift_recount_scrutiny_dates(@booth, @recount_polls)),
|
||||
{ prompt: t("admin.poll_shifts.new.select_date"),
|
||||
label: false },
|
||||
class: 'js-shift-recount-scrutiny-dates',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="row">
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 column">
|
||||
<ul class="tabs" data-tabs id="polls-tabs">
|
||||
<ul class="tabs" data-tabs id="polls_tabs">
|
||||
<li class="tabs-title is-active">
|
||||
<%= link_to "#tab-comments" do %>
|
||||
<h3>
|
||||
|
||||
@@ -19,11 +19,27 @@
|
||||
<div class="dates"></div>
|
||||
<% if poll.questions.count == 1 %>
|
||||
<% poll.questions.each do |question| %>
|
||||
<h4><%= link_to question.title, poll %></h4>
|
||||
<h4>
|
||||
<% if poll.results_enabled? %>
|
||||
<%= link_to question.title, results_poll_path(poll) %>
|
||||
<% elsif poll.stats_enabled? %>
|
||||
<%= link_to question.title, stats_poll_path(poll) %>
|
||||
<% else %>
|
||||
<%= link_to question.title, poll %>
|
||||
<% end %>
|
||||
</h4>
|
||||
<%= poll_dates(poll) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<h4><%= link_to poll.name, poll %></h4>
|
||||
<h4>
|
||||
<% if poll.results_enabled? %>
|
||||
<%= link_to poll.name, results_poll_path(poll) %>
|
||||
<% elsif poll.stats_enabled? %>
|
||||
<%= link_to poll.name, stats_poll_path(poll) %>
|
||||
<% else %>
|
||||
<%= link_to poll.name, poll %>
|
||||
<% end %>
|
||||
</h4>
|
||||
<%= poll_dates(poll) %>
|
||||
<ul class="margin-top">
|
||||
<% poll.questions.each do |question| %>
|
||||
|
||||
27
app/views/polls/_poll_header.html.erb
Normal file
27
app/views/polls/_poll_header.html.erb
Normal file
@@ -0,0 +1,27 @@
|
||||
<div class="expanded no-margin-top polls-show-header">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column padding">
|
||||
<%= back_link_to polls_path, t("polls.show.back") %>
|
||||
|
||||
<h2><%= @poll.name %></h2>
|
||||
|
||||
<%= safe_html_with_links simple_format(@poll.summary) %>
|
||||
|
||||
<% if @poll.geozones.any? %>
|
||||
<ul class="no-bullet margin-top tags">
|
||||
<% @poll.geozones.each do |g| %>
|
||||
<li class="inline-block"><span><%= g.name %></span></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<aside class="small-12 medium-3 column margin-top">
|
||||
<%= render partial: 'shared/social_share', locals: {
|
||||
share_title: t("shared.share"),
|
||||
title: @poll.name,
|
||||
url: poll_url(@poll)
|
||||
} %>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
36
app/views/polls/_poll_subnav.html.erb
Normal file
36
app/views/polls/_poll_subnav.html.erb
Normal file
@@ -0,0 +1,36 @@
|
||||
<% if current_user && current_user.administrator? ||
|
||||
(@poll.expired? && (@poll.results_enabled? || @poll.stats_enabled?)) %>
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 column">
|
||||
<ul class="menu simple clear">
|
||||
<% if current_user && current_user.administrator? || @poll.results_enabled? %>
|
||||
<% if controller_name == "polls" && action_name == "results" %>
|
||||
<li class="active">
|
||||
<h2><%= t("polls.show.results_menu") %></h2>
|
||||
</li>
|
||||
<% else %>
|
||||
<li><%= link_to t("polls.show.results_menu"), results_poll_path(@poll) %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if current_user && current_user.administrator? || @poll.stats_enabled? %>
|
||||
<% if controller_name == "polls" && action_name == "stats" %>
|
||||
<li class="active">
|
||||
<h2><%= t("polls.show.stats_menu") %></h2>
|
||||
</li>
|
||||
<% else %>
|
||||
<li><%= link_to t("polls.show.stats_menu"), stats_poll_path(@poll) %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "polls" && action_name == "show" %>
|
||||
<li class="active">
|
||||
<h2><%= t("polls.show.info_menu") %></h2>
|
||||
</li>
|
||||
<% else %>
|
||||
<li><%= link_to t("polls.show.info_menu"), poll_path(@poll) %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -1,20 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<ul class="tabs" data-tabs id="polls-tabs">
|
||||
<li class="tabs-title">
|
||||
<%= link_to "#tab-stats" do %>
|
||||
<h3>
|
||||
<%= t("polls.show.stats_menu") %> <!-- t("polls.show.comments_tab") -->
|
||||
</h3>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="tabs-title is-active">
|
||||
<%= link_to "#tab-information" do %>
|
||||
<h3>
|
||||
<%= t("polls.show.info_menu") %>
|
||||
</h3>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,126 +0,0 @@
|
||||
<div class="row margin">
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= render "callout" %>
|
||||
|
||||
<% if @poll.voted_in_booth?(current_user) %>
|
||||
<div class="callout warning">
|
||||
<%= t("polls.show.already_voted_in_booth") %>
|
||||
</div>
|
||||
<% else %>
|
||||
|
||||
<% if current_user && @poll.voted_in_web?(current_user) %>
|
||||
<div class="callout warning">
|
||||
<%= t("polls.show.already_voted_in_web") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% @questions.each do |question| %>
|
||||
<%= render 'polls/questions/question', question: question, token: @token %>
|
||||
<% end %>
|
||||
|
||||
<% if poll_voter_token(@poll, current_user).empty? %>
|
||||
<div class="callout token-message js-token-message" style="display: none">
|
||||
<%= t('poll_questions.show.voted_token') %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t("polls.show.participate_in_other_polls"), polls_path, class: "button hollow" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="expanded poll-more-info">
|
||||
<div class="row margin">
|
||||
<div class="small-12 medium-9 column">
|
||||
<h3><%= t("polls.show.more_info_title") %></h3>
|
||||
<%= safe_html_with_links simple_format(@poll.description) %>
|
||||
</div>
|
||||
|
||||
<% if false %>
|
||||
<aside class="small-12 medium-3 column">
|
||||
<div class="sidebar-divider"></div>
|
||||
<h2><%= t("polls.show.documents") %></h2>
|
||||
</aside>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="expanded poll-more-info-answers">
|
||||
<div class="row padding">
|
||||
|
||||
<% @poll_questions_answers.each do |answer| %>
|
||||
<div class="small-12 medium-6 column end answer <%= cycle('first', '') %>" id="answer_<%= answer.id %>">
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<h3><%= answer.title %></h3>
|
||||
<% end %>
|
||||
|
||||
<% if answer.images.any? %>
|
||||
<%= render "gallery", answer: answer %>
|
||||
<% end %>
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<div class="margin-top">
|
||||
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
|
||||
<%= safe_html_with_links simple_format(answer.description) %>
|
||||
</div>
|
||||
<div class="margin">
|
||||
<a id="read_more_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide">
|
||||
<%= t("polls.show.read_more", answer: answer.title) %>
|
||||
</a>
|
||||
<a id="read_less_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide"
|
||||
class="hide">
|
||||
<%= t("polls.show.read_less", answer: answer.title) %>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.documents.present? %>
|
||||
<div class="document-link">
|
||||
<p>
|
||||
<span class="icon-document"></span>
|
||||
<strong><%= t("polls.show.documents") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.documents.each do |document| %>
|
||||
<%= link_to document.title,
|
||||
document.attachment.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.videos.present? %>
|
||||
<div class="video-link">
|
||||
<p>
|
||||
<span class="icon-video"></span>
|
||||
<strong><%= t("polls.show.videos") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.videos.each do |video| %>
|
||||
<%= link_to video.title,
|
||||
video.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="proposals-tabs" role="tablist">
|
||||
<%= render "filter_subnav" %>
|
||||
|
||||
<div class="tabs-panel is-active" id="tab-comments">
|
||||
<%= render "comments" %>
|
||||
</div>
|
||||
</div>
|
||||
49
app/views/polls/results.html.erb
Normal file
49
app/views/polls/results.html.erb
Normal file
@@ -0,0 +1,49 @@
|
||||
<% provide :title do %><%= @poll.name %><% end %>
|
||||
|
||||
<div class="polls-results-stats">
|
||||
<%= render "poll_header" %>
|
||||
|
||||
<%= render "poll_subnav" %>
|
||||
|
||||
<div class="row margin" data-equalizer data-equalize-on="medium">
|
||||
<div class="small-12 medium-3 column sidebar" data-equalizer-watch>
|
||||
<p><strong><%= t("polls.show.results.title") %></strong></p>
|
||||
<ul class="menu vertical">
|
||||
<%- @poll.questions.each do |question| %>
|
||||
<li><%=link_to question.title, "##{question.title.parameterize}" %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-9 column" data-equalizer-watch>
|
||||
<%- @poll.questions.each do |question| %>
|
||||
<table id="question_<%= question.id %>_results_table">
|
||||
<h3 id="<%= question.title.parameterize %>"><%= question.title %></h3>
|
||||
<thead>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<th scope="col" <%= answer.most_voted? ? "class=win" : "" %>>
|
||||
<% if answer.most_voted %>
|
||||
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
|
||||
<% end %>
|
||||
<%= answer.title %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<td id="answer_<%= answer.id %>_result" <%= answer.most_voted? ? "class=win" : "" %>>
|
||||
<%= answer.total_votes %>
|
||||
(<%= answer.total_votes_percentage.round(2) %>%)
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,44 +1,134 @@
|
||||
<% provide :title do %><%= @poll.name %><% end %>
|
||||
|
||||
<div class="polls-show">
|
||||
<div class="expanded no-margin-top polls-show-header">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column padding">
|
||||
<%= back_link_to polls_path, t("polls.show.back") %>
|
||||
<%= render "poll_header" %>
|
||||
|
||||
<h2><%= @poll.name %></h2>
|
||||
<%= render "poll_subnav" %>
|
||||
|
||||
<%= safe_html_with_links simple_format(@poll.summary) %>
|
||||
<div class="row margin">
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= render "callout" %>
|
||||
|
||||
<% if @poll.geozones.any? %>
|
||||
<ul class="no-bullet margin-top tags">
|
||||
<% @poll.geozones.each do |g| %>
|
||||
<li class="inline-block"><span><%= g.name %></span></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% if @poll.voted_in_booth?(current_user) %>
|
||||
<div class="callout warning">
|
||||
<%= t("polls.show.already_voted_in_booth") %>
|
||||
</div>
|
||||
<% else %>
|
||||
|
||||
<% if current_user && @poll.voted_in_web?(current_user) && !@poll.expired? %>
|
||||
<div class="callout warning">
|
||||
<%= t("polls.show.already_voted_in_web") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% @questions.each do |question| %>
|
||||
<%= render 'polls/questions/question', question: question, token: @token %>
|
||||
<% end %>
|
||||
|
||||
<% if poll_voter_token(@poll, current_user).empty? %>
|
||||
<div class="callout token-message js-token-message" style="display: none">
|
||||
<%= t('poll_questions.show.voted_token') %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t("polls.show.participate_in_other_polls"), polls_path, class: "button hollow" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="expanded poll-more-info">
|
||||
<div class="row margin">
|
||||
<div class="small-12 medium-9 column">
|
||||
<h3><%= t("polls.show.more_info_title") %></h3>
|
||||
<%= safe_html_with_links simple_format(@poll.description) %>
|
||||
</div>
|
||||
|
||||
<aside class="small-12 medium-3 column margin-top">
|
||||
<%= render partial: 'shared/social_share', locals: {
|
||||
share_title: t("shared.share"),
|
||||
title: @poll.name,
|
||||
url: poll_url
|
||||
} %>
|
||||
</aside>
|
||||
<% if false %>
|
||||
<aside class="small-12 medium-3 column">
|
||||
<div class="sidebar-divider"></div>
|
||||
<h2><%= t("polls.show.documents") %></h2>
|
||||
</aside>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="polls-tabs" role="tablist">
|
||||
<%= render "results_subnavigation" %>
|
||||
|
||||
<div id="tab-stats" class="tabs-panel">
|
||||
<%= render "polls/stats/show" %>
|
||||
<div class="expanded poll-more-info-answers">
|
||||
<div class="row padding">
|
||||
|
||||
<% @poll_questions_answers.each do |answer| %>
|
||||
<div class="small-12 medium-6 column end answer <%= cycle('first', '') %>" id="answer_<%= answer.id %>">
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<h3><%= answer.title %></h3>
|
||||
<% end %>
|
||||
|
||||
<% if answer.images.any? %>
|
||||
<%= render "gallery", answer: answer %>
|
||||
<% end %>
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<div class="margin-top">
|
||||
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
|
||||
<%= safe_html_with_links simple_format(answer.description) %>
|
||||
</div>
|
||||
<div class="margin">
|
||||
<a id="read_more_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide">
|
||||
<%= t("polls.show.read_more", answer: answer.title) %>
|
||||
</a>
|
||||
<a id="read_less_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide"
|
||||
class="hide">
|
||||
<%= t("polls.show.read_less", answer: answer.title) %>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.documents.present? %>
|
||||
<div class="document-link">
|
||||
<p>
|
||||
<span class="icon-document"></span>
|
||||
<strong><%= t("polls.show.documents") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.documents.each do |document| %>
|
||||
<%= link_to document.title,
|
||||
document.attachment.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.videos.present? %>
|
||||
<div class="video-link">
|
||||
<p>
|
||||
<span class="icon-video"></span>
|
||||
<strong><%= t("polls.show.videos") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.videos.each do |video| %>
|
||||
<%= link_to video.title,
|
||||
video.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="polls_tabs" role="tablist">
|
||||
<%= render "filter_subnav" %>
|
||||
|
||||
<div class="tabs-panel is-active" id="tab-comments">
|
||||
<%= render "comments" %>
|
||||
</div>
|
||||
|
||||
<div id="tab-information" class="tabs-panel is-active">
|
||||
<%= render "show" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
96
app/views/polls/stats.html.erb
Normal file
96
app/views/polls/stats.html.erb
Normal file
@@ -0,0 +1,96 @@
|
||||
<% provide :title do %><%= @poll.name %><% end %>
|
||||
|
||||
<div class="polls-results-stats">
|
||||
<%= render "poll_header" %>
|
||||
|
||||
<%= render "poll_subnav" %>
|
||||
|
||||
<div class="row margin" data-equalizer data-equalize-on="medium">
|
||||
<div class="small-12 medium-3 column sidebar" data-equalizer-watch>
|
||||
<p><strong><%= t("polls.show.stats.title") %></strong></p>
|
||||
|
||||
<ul class="menu vertical margin-top">
|
||||
<li><a href="#total"><%= t("polls.show.stats.total_participation") %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-9 column" data-equalizer-watch>
|
||||
<h3 id="total"><%= t("polls.show.stats.total_participation") %></h3>
|
||||
|
||||
<p class="margin-top uppercase">
|
||||
<%= t("polls.show.stats.total_votes") %><br>
|
||||
<span class="number"><%= @stats[:total_participants] %></span>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><%= t("polls.show.stats.votes") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.web") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.booth") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.total") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row"><%= t("polls.show.stats.valid") %></th>
|
||||
<td>
|
||||
<%= @stats[:total_web_valid] %>
|
||||
<small><em>(<%= @stats[:valid_percentage_web].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_booth_valid] %>
|
||||
<small><em>(<%= @stats[:valid_percentage_booth].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_valid_votes] %>
|
||||
<small><em>(<%= @stats[:total_valid_percentage].round(2) %>%)</em></small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><%= t("polls.show.stats.white") %></th>
|
||||
<td>
|
||||
<%= @stats[:total_web_white] %>
|
||||
<small><em>(<%= @stats[:white_percentage_web].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_booth_white] %>
|
||||
<small><em>(<%= @stats[:white_percentage_booth].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td><%= @stats[:total_white_votes] %>
|
||||
<small><em>(<%= @stats[:total_white_percentage].round(2) %>%)</em></small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><%= t("polls.show.stats.null_votes") %></th>
|
||||
<td>
|
||||
<%= @stats[:total_web_null] %>
|
||||
<small><em>(<%= @stats[:null_percentage_web].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_booth_null] %>
|
||||
<small><em>(<%= @stats[:null_percentage_booth].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_null_votes] %>
|
||||
<small><em>(<%= @stats[:total_null_percentage].round(2) %>%)</em></small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><%= t("polls.show.stats.total") %></th>
|
||||
<td>
|
||||
<%= @stats[:total_participants_web] %>
|
||||
<small><em>(<%= @stats[:total_participants_web_percentage].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= @stats[:total_participants_booth] %>
|
||||
<small><em>(<%= @stats[:total_participants_booth_percentage].round(2) %>%)</em></small>
|
||||
</td>
|
||||
<td><%= @stats[:total_participants_web] + @stats[:total_participants_booth] %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,85 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="small-12 medium-3 column sidebar">
|
||||
<p><%= t("polls.show.stats.title") %></p>
|
||||
<ul class="menu vertical margin-top">
|
||||
<li><a href="#total"><%= t("polls.show.stats.total_participation") %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="small-12 medium-9 column">
|
||||
<h3 id="total"><%= t("polls.show.stats.total_participation") %></h3>
|
||||
|
||||
<p class="stat-number margin-top">
|
||||
<%= t("polls.show.stats.total_votes") %><br>
|
||||
<span><%= @stats[:total_participants] %></span>
|
||||
</p>
|
||||
<table class="polls-total-stats">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><%= t("polls.show.stats.votes") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.web") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.booth") %></th>
|
||||
<th scope="col"><%= t("polls.show.stats.total") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><%= t("polls.show.stats.valid") %></th>
|
||||
<td><%= @stats[:total_web_valid] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:valid_percentage_web],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_booth_valid] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:valid_percentage_booth],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_valid_votes] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:total_valid_percentage],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><%= t("polls.show.stats.white") %></th>
|
||||
<td><%= @stats[:total_web_white] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:white_percentage_web],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_booth_white] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:white_percentage_booth],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_white_votes] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:total_white_percentage],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><%= t("polls.show.stats.null_votes") %></th>
|
||||
<td><%= @stats[:total_web_null] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:null_percentage_web],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_booth_null] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:null_percentage_booth],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_null_votes] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:total_null_percentage],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><%= t("polls.show.stats.total") %></th>
|
||||
<td><%= @stats[:total_participants_web] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:total_participants_web_percentage],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_participants_booth] %> <small><em>
|
||||
(<%= number_to_percentage(@stats[:total_participants_booth_percentage],
|
||||
strip_insignificant_zeros: true,
|
||||
precision: 2) %>)</em></small></td>
|
||||
<td><%= @stats[:total_participants_web] + @stats[:total_participants_booth] %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -515,6 +515,7 @@ en:
|
||||
search_officer_placeholder: Search officer
|
||||
search_officer_text: Search for an officer to assign a new shift
|
||||
select_date: "Select day"
|
||||
no_voting_days: "Los dias de votación terminaron"
|
||||
select_task: "Select task"
|
||||
table_shift: "Shift"
|
||||
table_email: "Email"
|
||||
@@ -569,6 +570,10 @@ en:
|
||||
geozone_restricted: "Restricted to districts"
|
||||
new:
|
||||
title: "New poll"
|
||||
show_results_and_stats: "Show results and stats"
|
||||
show_results: "Show results"
|
||||
show_stats: "Show stats"
|
||||
results_and_stats_reminder: "Marking these checkboxes the results and/or stats of this poll will be publicly available and every user will see them."
|
||||
submit_button: "Create poll"
|
||||
edit:
|
||||
title: "Edit poll"
|
||||
|
||||
@@ -501,6 +501,7 @@ en:
|
||||
videos: "External video"
|
||||
info_menu: "Information"
|
||||
stats_menu: "Participation statistics"
|
||||
results_menu: "Poll results"
|
||||
stats:
|
||||
title: "Participation data"
|
||||
total_participation: "Total participation"
|
||||
@@ -512,6 +513,9 @@ en:
|
||||
valid: "Valid"
|
||||
white: "White votes"
|
||||
null_votes: "Invalid"
|
||||
results:
|
||||
title: "Questions"
|
||||
most_voted_answer: "Most voted answer: "
|
||||
poll_questions:
|
||||
create_question: "Create question"
|
||||
show:
|
||||
|
||||
@@ -515,6 +515,7 @@ es:
|
||||
search_officer_placeholder: Buscar presidentes de mesa
|
||||
search_officer_text: Busca al presidente de mesa para asignar un turno
|
||||
select_date: "Seleccionar día"
|
||||
no_voting_days: "Voting days ended"
|
||||
select_task: "Seleccionar tarea"
|
||||
table_shift: "Turno"
|
||||
table_email: "Email"
|
||||
@@ -569,6 +570,10 @@ es:
|
||||
geozone_restricted: "Restringida a los distritos"
|
||||
new:
|
||||
title: "Nueva votación"
|
||||
show_results_and_stats: "Mostrar resultados y estadísticas"
|
||||
show_results: "Mostrar resultados"
|
||||
show_stats: "Mostrar estadísticas"
|
||||
results_and_stats_reminder: "Si marcas estas casillas los resultados y/o estadísticas de esta votación serán públicos y podrán verlos todos los usuarios."
|
||||
submit_button: "Crear votación"
|
||||
edit:
|
||||
title: "Editar votación"
|
||||
|
||||
@@ -501,6 +501,7 @@ es:
|
||||
videos: "Vídeo externo"
|
||||
info_menu: "Información"
|
||||
stats_menu: "Estadísticas de participación"
|
||||
results_menu: "Resultados de la votación"
|
||||
stats:
|
||||
title: "Datos de participación"
|
||||
total_participation: "Participación total"
|
||||
@@ -512,6 +513,9 @@ es:
|
||||
valid: "Válidos"
|
||||
white: "En blanco"
|
||||
null_votes: "Nulos"
|
||||
results:
|
||||
title: "Preguntas"
|
||||
most_voted_answer: "Respuesta más votada: "
|
||||
poll_questions:
|
||||
create_question: "Crear pregunta para votación"
|
||||
show:
|
||||
|
||||
@@ -113,6 +113,10 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resources :polls, only: [:show, :index] do
|
||||
member do
|
||||
get :stats
|
||||
get :results
|
||||
end
|
||||
resources :questions, controller: 'polls/questions', shallow: true do
|
||||
post :answer, on: :member
|
||||
end
|
||||
|
||||
@@ -546,6 +546,13 @@ poll = Poll.create(name: "Upcoming Poll",
|
||||
starts_at: 1.month.from_now,
|
||||
ends_at: 2.months.from_now)
|
||||
|
||||
puts " ✅"
|
||||
print "Recounting Poll"
|
||||
poll = Poll.create(name: "Recounting Poll",
|
||||
# slug: "recounting-poll",
|
||||
starts_at: 1.months.ago,
|
||||
ends_at: 5.days.ago)
|
||||
|
||||
puts " ✅"
|
||||
print "Expired Poll"
|
||||
poll = Poll.create(name: "Expired Poll",
|
||||
@@ -553,6 +560,15 @@ poll = Poll.create(name: "Expired Poll",
|
||||
starts_at: 2.months.ago,
|
||||
ends_at: 1.month.ago)
|
||||
|
||||
puts " ✅"
|
||||
print "Expired Poll with Stats & Results"
|
||||
poll = Poll.create(name: "Expired Poll with Stats & Results",
|
||||
# slug: "expired-poll-with-stats-and-results",
|
||||
starts_at: 2.months.ago,
|
||||
ends_at: 1.month.ago,
|
||||
results_enabled: true,
|
||||
stats_enabled: true)
|
||||
|
||||
puts " ✅"
|
||||
print "Creating Poll Questions"
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddMostVotedToPollQuestionAnswer < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :poll_question_answers, :most_voted, :boolean, default: false
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddResultsAndStatsToPolls < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :polls, :results_enabled, :boolean, default: false
|
||||
add_column :polls, :stats_enabled, :boolean, default: false
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20171017221546) do
|
||||
ActiveRecord::Schema.define(version: 20171020163240) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -666,6 +666,7 @@ ActiveRecord::Schema.define(version: 20171017221546) do
|
||||
t.text "description"
|
||||
t.integer "question_id"
|
||||
t.integer "given_order", default: 1
|
||||
t.boolean "most_voted", default: false
|
||||
end
|
||||
|
||||
add_index "poll_question_answers", ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree
|
||||
@@ -759,6 +760,8 @@ ActiveRecord::Schema.define(version: 20171017221546) do
|
||||
t.integer "comments_count", default: 0
|
||||
t.integer "author_id"
|
||||
t.datetime "hidden_at"
|
||||
t.boolean "results_enabled", default: false
|
||||
t.boolean "stats_enabled", default: false
|
||||
end
|
||||
|
||||
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree
|
||||
|
||||
@@ -60,6 +60,10 @@ feature 'Admin polls' do
|
||||
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
|
||||
fill_in 'poll_summary', with: "Upcoming poll's summary. This poll..."
|
||||
fill_in 'poll_description', with: "Upcomming poll's description. This poll..."
|
||||
|
||||
expect(page).to_not have_css("#poll_results_enabled")
|
||||
expect(page).to_not have_css("#poll_stats_enabled")
|
||||
|
||||
click_button "Create poll"
|
||||
|
||||
expect(page).to have_content "Poll created successfully"
|
||||
@@ -79,14 +83,25 @@ feature 'Admin polls' do
|
||||
|
||||
expect(page).to have_css("img[alt='#{poll.image.title}']")
|
||||
|
||||
expect(page).to have_css("#poll_results_enabled")
|
||||
expect(page).to have_css("#poll_stats_enabled")
|
||||
|
||||
fill_in "poll_name", with: "Next Poll"
|
||||
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
|
||||
check 'poll_results_enabled'
|
||||
check 'poll_stats_enabled'
|
||||
|
||||
click_button "Update poll"
|
||||
|
||||
expect(page).to have_content "Poll updated successfully"
|
||||
expect(page).to have_content "Next Poll"
|
||||
expect(page).to have_content I18n.l(end_date.to_date)
|
||||
|
||||
click_link "Edit poll"
|
||||
|
||||
expect(page).to have_field('poll_results_enabled', checked: true)
|
||||
expect(page).to have_field('poll_stats_enabled', checked: true)
|
||||
|
||||
end
|
||||
|
||||
scenario 'Edit from index' do
|
||||
|
||||
@@ -59,6 +59,22 @@ feature 'Polls' do
|
||||
expect(page).to have_link('Incoming')
|
||||
expect(page).to_not have_link('Expired')
|
||||
end
|
||||
|
||||
scenario "Poll title link to stats if enabled" do
|
||||
poll = create(:poll, name: "Poll with stats", stats_enabled: true)
|
||||
|
||||
visit polls_path
|
||||
|
||||
expect(page).to have_link("Poll with stats", href: stats_poll_path(poll))
|
||||
end
|
||||
|
||||
scenario "Poll title link to results if enabled" do
|
||||
poll = create(:poll, name: "Poll with results", stats_enabled: true, results_enabled: true)
|
||||
|
||||
visit polls_path
|
||||
|
||||
expect(page).to have_link("Poll with results", href: results_poll_path(poll))
|
||||
end
|
||||
end
|
||||
|
||||
context 'Show' do
|
||||
@@ -367,17 +383,74 @@ feature 'Polls' do
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
context "Results and stats" do
|
||||
scenario "See polls statistics", :js do
|
||||
scenario "Show poll results and stats if enabled and poll expired" do
|
||||
poll = create(:poll, :expired, results_enabled: true, stats_enabled: true)
|
||||
user = create(:user)
|
||||
poll = create(:poll, summary: "Summary", description: "Description")
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
click_link "Participation statistics"
|
||||
|
||||
expect(page).to have_content("Total participation")
|
||||
|
||||
expect(page).to have_content("Poll results")
|
||||
expect(page).to have_content("Participation statistics")
|
||||
|
||||
visit results_poll_path(poll)
|
||||
expect(page).to have_content("Questions")
|
||||
|
||||
visit stats_poll_path(poll)
|
||||
expect(page).to have_content("Participation data")
|
||||
end
|
||||
|
||||
scenario "Don't show poll results and stats if not enabled" do
|
||||
poll = create(:poll, :expired, results_enabled: false, stats_enabled: false)
|
||||
user = create(:user)
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to_not have_content("Poll results")
|
||||
expect(page).to_not have_content("Participation statistics")
|
||||
|
||||
visit results_poll_path(poll)
|
||||
expect(page).to have_content("You do not have permission to carry out the action 'results' on poll.")
|
||||
|
||||
visit stats_poll_path(poll)
|
||||
expect(page).to have_content("You do not have permission to carry out the action 'stats' on poll.")
|
||||
end
|
||||
|
||||
scenario "Don't show poll results and stats if is not expired" do
|
||||
poll = create(:poll, :current, results_enabled: true, stats_enabled: true)
|
||||
user = create(:user)
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to_not have_content("Poll results")
|
||||
expect(page).to_not have_content("Participation statistics")
|
||||
|
||||
visit results_poll_path(poll)
|
||||
expect(page).to have_content("You do not have permission to carry out the action 'results' on poll.")
|
||||
|
||||
visit stats_poll_path(poll)
|
||||
expect(page).to have_content("You do not have permission to carry out the action 'stats' on poll.")
|
||||
end
|
||||
|
||||
scenario "Show poll results and stats if user is administrator" do
|
||||
poll = create(:poll, :current, results_enabled: false, stats_enabled: false)
|
||||
user = create(:administrator).user
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to have_content("Poll results")
|
||||
expect(page).to have_content("Participation statistics")
|
||||
|
||||
visit results_poll_path(poll)
|
||||
expect(page).to have_content("Questions")
|
||||
|
||||
visit stats_poll_path(poll)
|
||||
expect(page).to have_content("Participation data")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
55
spec/features/polls/results_spec.rb
Normal file
55
spec/features/polls/results_spec.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Poll Results' do
|
||||
scenario 'List each Poll question', :js do
|
||||
user1 = create(:user, :level_two)
|
||||
user2 = create(:user, :level_two)
|
||||
user3 = create(:user, :level_two)
|
||||
|
||||
poll = create(:poll, results_enabled: true)
|
||||
question1 = create(:poll_question, poll: poll)
|
||||
answer1 = create(:poll_question_answer, question: question1, title: 'Yes')
|
||||
answer2 = create(:poll_question_answer, question: question1, title: 'No')
|
||||
|
||||
question2 = create(:poll_question, poll: poll)
|
||||
answer3 = create(:poll_question_answer, question: question2, title: 'Blue')
|
||||
answer4 = create(:poll_question_answer, question: question2, title: 'Green')
|
||||
answer5 = create(:poll_question_answer, question: question2, title: 'Yellow')
|
||||
|
||||
login_as user1
|
||||
vote_for_poll_via_web(poll, question1, 'Yes')
|
||||
vote_for_poll_via_web(poll, question2, 'Blue')
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
logout
|
||||
|
||||
login_as user2
|
||||
vote_for_poll_via_web(poll, question1, 'Yes')
|
||||
vote_for_poll_via_web(poll, question2, 'Green')
|
||||
expect(Poll::Voter.count).to eq(2)
|
||||
logout
|
||||
|
||||
login_as user3
|
||||
vote_for_poll_via_web(poll, question1, 'No')
|
||||
vote_for_poll_via_web(poll, question2, 'Yellow')
|
||||
expect(Poll::Voter.count).to eq(3)
|
||||
logout
|
||||
|
||||
poll.update(ends_at: 1.day.ago)
|
||||
|
||||
visit results_poll_path(poll)
|
||||
|
||||
expect(page).to have_content(question1.title)
|
||||
expect(page).to have_content(question2.title)
|
||||
|
||||
within("#question_#{question1.id}_results_table") do
|
||||
expect(find("#answer_#{answer1.id}_result")).to have_content("2 (66.0%)")
|
||||
expect(find("#answer_#{answer2.id}_result")).to have_content("1 (33.0%)")
|
||||
end
|
||||
|
||||
within("#question_#{question2.id}_results_table") do
|
||||
expect(find("#answer_#{answer3.id}_result")).to have_content("1 (33.0%)")
|
||||
expect(find("#answer_#{answer4.id}_result")).to have_content("1 (33.0%)")
|
||||
expect(find("#answer_#{answer5.id}_result")).to have_content("1 (33.0%)")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -95,7 +95,8 @@ feature "Voter" do
|
||||
|
||||
scenario "Trying to vote in web and then in booth", :js do
|
||||
login_as user
|
||||
vote_for_poll_via_web(poll, question)
|
||||
vote_for_poll_via_web(poll, question, 'Yes')
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
|
||||
click_link "Sign out"
|
||||
|
||||
@@ -127,7 +128,8 @@ feature "Voter" do
|
||||
|
||||
scenario "Trying to vote in web again", :js do
|
||||
login_as user
|
||||
vote_for_poll_via_web(poll, question)
|
||||
vote_for_poll_via_web(poll, question, 'Yes')
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
|
||||
visit poll_path(poll)
|
||||
|
||||
|
||||
@@ -299,15 +299,13 @@ module CommonActions
|
||||
end
|
||||
end
|
||||
|
||||
def vote_for_poll_via_web(poll, question)
|
||||
def vote_for_poll_via_web(poll, question, answer)
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link 'Yes'
|
||||
expect(page).to_not have_link('Yes')
|
||||
click_link "#{answer}"
|
||||
expect(page).to_not have_link("#{answer}")
|
||||
end
|
||||
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
end
|
||||
|
||||
def vote_for_poll_via_booth
|
||||
|
||||
Reference in New Issue
Block a user