diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 51de9c678..611ecc546 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -73,6 +73,7 @@ //= require map //= require polls //= require sortable +//= require table_sortable var initialize_modules = function() { App.Comments.initialize(); @@ -113,6 +114,7 @@ var initialize_modules = function() { App.Map.initialize(); App.Polls.initialize(); App.Sortable.initialize(); + App.TableSortable.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/table_sortable.js.coffee b/app/assets/javascripts/table_sortable.js.coffee new file mode 100644 index 000000000..331f794a4 --- /dev/null +++ b/app/assets/javascripts/table_sortable.js.coffee @@ -0,0 +1,23 @@ +App.TableSortable = + getCellValue: (row, index) -> + $(row).children('td').eq(index).text() + + comparer: (index) -> + (a, b) -> + valA = App.TableSortable.getCellValue(a, index) + valB = App.TableSortable.getCellValue(b, index) + return if $.isNumeric(valA) and $.isNumeric(valB) then valA - valB else valA.localeCompare(valB) + + initialize: -> + $('table.sortable th').click -> + table = $(this).parents('table').eq(0) + rows = table.find('tr:gt(0)').not('tfoot tr').toArray().sort(App.TableSortable.comparer($(this).index())) + @asc = !@asc + if !@asc + rows = rows.reverse() + i = 0 + while i < rows.length + table.append rows[i] + i++ + return + \ No newline at end of file diff --git a/app/assets/stylesheets/custom.scss b/app/assets/stylesheets/custom.scss index 090eb0342..06b4d91ce 100644 --- a/app/assets/stylesheets/custom.scss +++ b/app/assets/stylesheets/custom.scss @@ -3,3 +3,8 @@ // * English: https://github.com/consul/consul/blob/master/CUSTOMIZE_EN.md#css // * Spanish: https://github.com/consul/consul/blob/master/CUSTOMIZE_ES.md#css // + +table.sortable thead th:hover { + text-decoration: underline; + cursor: pointer; +} \ No newline at end of file diff --git a/app/controllers/admin/stats_controller.rb b/app/controllers/admin/stats_controller.rb index 5a50d03b4..91e266b77 100644 --- a/app/controllers/admin/stats_controller.rb +++ b/app/controllers/admin/stats_controller.rb @@ -36,4 +36,9 @@ class Admin::StatsController < Admin::BaseController @users_who_have_sent_message = DirectMessage.select(:sender_id).distinct.count end -end \ No newline at end of file + def polls + @polls = ::Poll.current + @participants = ::Poll::Voter.where(poll: @polls) + end + +end diff --git a/app/views/admin/stats/polls.html.erb b/app/views/admin/stats/polls.html.erb new file mode 100644 index 000000000..c2b0b8481 --- /dev/null +++ b/app/views/admin/stats/polls.html.erb @@ -0,0 +1,87 @@ +<%= back_link_to %> + +

<%= t("admin.stats.polls.title")%>

+ +
+
+
+ +
+ +
+ +
+
+
+ +

<%= t("admin.stats.polls.all") %>

+ + + + + + + + + <% @polls.each do |poll| %> + + + + + + <% end %> +
<%= t("admin.stats.polls.table.poll_name") %><%= t("admin.stats.polls.total_participants") %><%= t("admin.stats.polls.table.origin_web") %>
+ <%= poll.name %> + + <%= poll.voters.select(:user_id).distinct.count %> + + <%= poll.voters.web.select(:user_id).distinct.count %> +
+ +<% @polls.each do |poll| %> +

+ <%= t("admin.stats.polls.poll_questions", poll: poll.name) %> +

+ + + + + + + + <% poll.questions.each do |question| %> + + + + + <% end %> + + + + + + +
<%= t("admin.stats.polls.table.question_name") %> + <%= t("admin.stats.polls.table.origin_web") %> +
+ <%= question.title %> + + <%= ::Poll::Answer.by_question(question).count %> +
+ + <%= t("admin.stats.polls.table.origin_total") %>: + <%= ::Poll::Answer.where(question: poll.questions) + .select(:author_id).distinct.count %> + +
+<% end %> \ No newline at end of file diff --git a/app/views/admin/stats/show.html.erb b/app/views/admin/stats/show.html.erb index 5df7b5df2..330a69b01 100644 --- a/app/views/admin/stats/show.html.erb +++ b/app/views/admin/stats/show.html.erb @@ -7,6 +7,8 @@

<%= t "admin.stats.show.stats_title" %>

+ <%= link_to t("admin.stats.show.polls"), + polls_admin_stats_path, class: "button hollow" %> <%= link_to t("admin.stats.show.direct_messages"), direct_messages_admin_stats_path, class: "button hollow" %> <%= link_to t("admin.stats.show.proposal_notifications"), diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 2633724ac..62dc77d19 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -958,6 +958,7 @@ en: direct_messages: Direct messages proposal_notifications: Proposal notifications incomplete_verifications: Incomplete verifications + polls: Polls direct_messages: title: Direct messages total: Total @@ -966,6 +967,17 @@ en: title: Proposal notifications total: Total proposals_with_notifications: Proposals with notifications + polls: + title: Poll Stats + all: Polls + web_participants: Web participants + total_participants: Total Participants + poll_questions: "Questions from poll: %{poll}" + table: + poll_name: Poll + question_name: Question + origin_web: Web participants + origin_total: Total participants tags: create: Create topic destroy: Destroy topic diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 067684df9..03a138435 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -958,6 +958,7 @@ es: direct_messages: Mensajes directos proposal_notifications: Notificaciones de propuestas incomplete_verifications: Verificaciones incompletas + polls: Votaciones direct_messages: title: Mensajes directos total: Total @@ -966,6 +967,17 @@ es: title: Notificaciones de propuestas total: Total proposals_with_notifications: Propuestas con notificaciones + polls: + title: Estadísticas de votaciones + all: Votaciones + web_participants: Participantes en Web + total_participants: Participantes totales + poll_questions: "Preguntas de votación: %{poll}" + table: + poll_name: Votación + question_name: Pregunta + origin_web: Participantes Web + origin_total: Participantes Totales tags: create: Crear tema destroy: Eliminar tema diff --git a/config/routes.rb b/config/routes.rb index 9ce97f45b..df7e03a4f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -339,6 +339,7 @@ Rails.application.routes.draw do resource :stats, only: :show do get :proposal_notifications, on: :collection get :direct_messages, on: :collection + get :polls, on: :collection end namespace :legislation do diff --git a/spec/features/admin/stats_spec.rb b/spec/features/admin/stats_spec.rb index c0aefe4e5..60dae016b 100644 --- a/spec/features/admin/stats_spec.rb +++ b/spec/features/admin/stats_spec.rb @@ -162,4 +162,99 @@ feature 'Stats' do end + context "Polls" do + + scenario "Total participants by origin" do + oa = create(:poll_officer_assignment) + 3.times { create(:poll_voter, origin: "web") } + + visit admin_stats_path + + within(".stats") do + click_link "Polls" + end + + within("#web_participants") do + expect(page).to have_content "3" + end + end + + scenario "Total participants" do + user = create(:user, :level_two) + 3.times { create(:poll_voter, user: user) } + create(:poll_voter) + + visit admin_stats_path + + within(".stats") do + click_link "Polls" + end + + within("#participants") do + expect(page).to have_content "2" + end + end + + scenario "Participants by poll" do + oa = create(:poll_officer_assignment) + + poll1 = create(:poll) + poll2 = create(:poll) + + 1.times { create(:poll_voter, poll: poll1, origin: "web") } + 2.times { create(:poll_voter, poll: poll2, origin: "web") } + + visit admin_stats_path + + within(".stats") do + click_link "Polls" + end + + within("#polls") do + + within("#poll_#{poll1.id}") do + expect(page).to have_content "1" + end + + within("#poll_#{poll2.id}") do + expect(page).to have_content "2" + end + + end + end + + scenario "Participants by poll question" do + user1 = create(:user, :level_two) + user2 = create(:user, :level_two) + + poll = create(:poll) + + question1 = create(:poll_question, :with_answers, poll: poll) + question2 = create(:poll_question, :with_answers, poll: poll) + + create(:poll_answer, question: question1, author: user1) + create(:poll_answer, question: question2, author: user1) + create(:poll_answer, question: question2, author: user2) + + visit admin_stats_path + + within(".stats") do + click_link "Polls" + end + + within("#poll_question_#{question1.id}") do + expect(page).to have_content "1" + end + + within("#poll_question_#{question2.id}") do + expect(page).to have_content "2" + end + + within("#poll_#{poll.id}_questions_total") do + expect(page).to have_content "2" + end + end + + end + end