From 105d8ee442245bd5d05c322a433cf5adcb147517 Mon Sep 17 00:00:00 2001 From: Robert Guthrie Date: Wed, 4 May 2022 21:55:34 +1200 Subject: [PATCH 1/2] add score frequency chart.. works well in app. email is being weird dues to css inlining. --- app/assets/stylesheets/vtfy/components.scss | 18 +++--- app/helpers/dev/fake_data_helper.rb | 11 +--- app/models/poll.rb | 2 + app/models/poll_option.rb | 9 +++ app/serializers/poll_serializer.rb | 4 +- app/services/poll_service.rb | 2 + .../poll/results/_simple.html.haml | 43 +++++++++----- vue/src/components/poll/common/chart/bar.vue | 28 --------- .../components/poll/common/chart/count.vue | 59 ------------------- .../components/poll/common/chart/table.vue | 52 ++++++++++++---- vue/src/components/poll/common/icon/panel.vue | 4 +- .../poll/common/icon/score_counts.vue | 42 +++++++++++++ 12 files changed, 137 insertions(+), 137 deletions(-) delete mode 100644 vue/src/components/poll/common/chart/bar.vue delete mode 100644 vue/src/components/poll/common/chart/count.vue create mode 100644 vue/src/components/poll/common/icon/score_counts.vue diff --git a/app/assets/stylesheets/vtfy/components.scss b/app/assets/stylesheets/vtfy/components.scss index d24d78eb4e1..83921d868cc 100644 --- a/app/assets/stylesheets/vtfy/components.scss +++ b/app/assets/stylesheets/vtfy/components.scss @@ -118,22 +118,18 @@ height: 36px; } -.v-table { +table.v-table { border-radius: 4px; border-spacing: 0; line-height: 1.5; max-width: 800px; margin-bottom: 16px; - td, th { - font-size: .8rem; - // height: 32px; - padding: 0 4px; - border-bottom: thin solid rgba(0,0,0,.12); - } - td.no-border { - border-bottom: none; - border: 0; - } +} +td.v-table, th.v-table { + font-size: .8rem; + // height: 32px; + padding: 0 4px; + border-bottom: thin solid rgba(0,0,0,.12); } .v-layout-table { diff --git a/app/helpers/dev/fake_data_helper.rb b/app/helpers/dev/fake_data_helper.rb index 06e69ed66fe..2747e71c6e7 100644 --- a/app/helpers/dev/fake_data_helper.rb +++ b/app/helpers/dev/fake_data_helper.rb @@ -191,8 +191,8 @@ def fake_poll(args = {}) when 'ranked_choice' options[:custom_fields][:minimum_stance_choices] = 3 when 'score' - options[:custom_fields][:max_score] = 9 - options[:custom_fields][:min_score] = -9 + options[:custom_fields][:max_score] = 5 + options[:custom_fields][:min_score] = -5 end Poll.new(options) @@ -218,12 +218,7 @@ def fake_score(poll) def fake_stance(args = {}) poll = args[:poll] || saved(fake_poll) - - choice = if poll.minimum_stance_choices > 1 - poll.poll_options.sample(poll.minimum_stance_choices).map do |option| - [option.name, fake_score(poll)] - end.to_h - elsif poll.require_all_choices + choice = if poll.has_variable_score poll.poll_options.map do |option| [option.name, fake_score(poll)] end.to_h diff --git a/app/models/poll.rb b/app/models/poll.rb index fd983496b8b..aa8435c0bd8 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -149,6 +149,7 @@ def chart_type case poll_type when 'proposal' then 'pie' when 'meeting' then 'grid' + when 'score' then 'score_counts' else 'bar' end @@ -159,6 +160,7 @@ def icon_type when 'proposal' then 'pie' when 'meeting' then 'grid' when 'count' then 'count' + when 'score' then 'score_counts' else 'bar' end diff --git a/app/models/poll_option.rb b/app/models/poll_option.rb index 39e924e45e2..6f5ce24fc72 100644 --- a/app/models/poll_option.rb +++ b/app/models/poll_option.rb @@ -7,14 +7,23 @@ class PollOption < ApplicationRecord scope :dangling, -> { joins('left join polls on polls.id = poll_id').where('polls.id is null') } + def update_counts! update_columns( + score_counts: calculate_score_counts, voter_scores: poll.anonymous ? {} : stance_choices.latest.where('stances.participant_id is not null').includes(:stance).map { |c| [c.stance.participant_id, c.score] }.to_h, total_score: stance_choices.latest.sum(:score), voter_count: stances.latest.count ) end + # what is the frequency of each of the scores chosen for this option? + def calculate_score_counts + h = {} + stance_choices.each { |c| h[c.score] = h.fetch(c.score, 0) + 1 } + h + end + def color if poll.poll_type == 'proposal' { diff --git a/app/serializers/poll_serializer.rb b/app/serializers/poll_serializer.rb index d12af167bb7..6d1c6baa0c3 100644 --- a/app/serializers/poll_serializer.rb +++ b/app/serializers/poll_serializer.rb @@ -44,7 +44,9 @@ class PollSerializer < ApplicationSerializer :undecided_voters_count, :voter_can_add_options, :voters_count, - :versions_count + :versions_count, + :min_score, + :max_score has_one :discussion, serializer: DiscussionSerializer, root: :discussions has_one :created_event, serializer: EventSerializer, root: :events diff --git a/app/services/poll_service.rb b/app/services/poll_service.rb index 5b36fc2674f..fb9b5c70f27 100644 --- a/app/services/poll_service.rb +++ b/app/services/poll_service.rb @@ -275,6 +275,7 @@ def self.calculate_results(poll, poll_options) max_score_percent: poll.total_score > 0 ? ((option.total_score.to_f / poll.stance_counts.max.to_f) * 100) : 0, voter_percent: poll.voters_count > 0 ? ((option.voter_count.to_f / poll.voters_count.to_f) * 100) : 0, average: option.average_score, + score_counts: option.score_counts, voter_scores: option.voter_scores, voter_ids: option.voter_ids.take(500), voter_count: option.voter_count, @@ -294,6 +295,7 @@ def self.calculate_results(poll, poll_options) voter_percent: poll.voters_count > 0 ? (poll.undecided_voters_count.to_f / poll.voters_count.to_f * 100) : 0, average: 0, voter_scores: {}, + score_counts: {}, voter_ids: poll.undecided_voters.map(&:id).take(500), voter_count: poll.undecided_voters_count, color: '#BBBBBB' diff --git a/app/views/event_mailer/poll/results/_simple.html.haml b/app/views/event_mailer/poll/results/_simple.html.haml index 85c79b39293..8eddadb8625 100644 --- a/app/views/event_mailer/poll/results/_simple.html.haml +++ b/app/views/event_mailer/poll/results/_simple.html.haml @@ -3,7 +3,7 @@ .poll-mailer-common-results %table.v-table{style: 'min-width: 600px', cellspacing: 0} %thead - %tr + %tr.v-table - poll.result_columns.each do |col| - case col - when 'pie', 'bar', 'grid' @@ -26,29 +26,40 @@ - when 'voters' %th.text-left.text-subtitle-2 %tbody + - max_count = (poll.results.map {|o| o[:score_counts].values.max}.compact).max - results.each_with_index do |option, index| - %tr + %tr.v-table - poll.result_columns.each do |col| - case col - when 'pie' - if (index == 0) - %td.pr-2.py-2{rowspan: results.size} + %td.pr-2.py-2.v-table{rowspan: results.size} .poll-mailer-proposal__chart.poll-mailer__results-chart.d-flex.align-center.justify-center %img.poll-mailer-proposal__chart-image{style: "height: 128px; width: 128px", src: google_pie_chart_url(poll), width: 128, height: 128} - when 'bar' - %td.pr-2.py-2{style: 'width: 128px'} - - if option[poll.chart_column] > 0 - + - if poll.chart_type == 'score_counts' + %td.pr-2.py-2.v-table{style: 'width: 128px'} %table{cellspacing: 0, cellpadding: 0, width: '100%', height: '100%'} %tr - %td.no-border.rounded{style: "background-color: #{option[:color]}; height: 24px", height: 24, width: "#{option[poll.chart_column]}%"} - %td.no-border + - (poll.min_score..poll.max_score).to_a.each do |score| + - count = option[:score_counts].fetch(score.to_s, 0) + - pct = count.to_f / max_count.to_f + - hex = (pct*100).round.to_s(16) + %td{bgcolor:"#001199#{hex}", style: "border:0; height: 24px)"}= count + - else + %td.pr-2.py-2.v-table{style: 'width: 128px'} + - if option[poll.chart_column] > 0 + + %table{cellspacing: 0, cellpadding: 0, width: '100%', height: '100%'} + %tr + %td.no-border.rounded{style: "background-color: #{option[:color]}; height: 24px", height: 24, width: "#{option[poll.chart_column]}%"} + %td.no-border - when 'grid' / - if (index == 0) / %td.pr-2.py-2{rowspan: results.size} / %img.poll-mailer-proposal__chart-image{style: "height: 128px; width: 128px", src: google_pie_chart_url(poll)} - when 'name' - %td{style: (poll.chart_type == 'pie') ? "border-left: solid 4px px #{option[:color]}" : ''} + %td.v-table{style: (poll.chart_type == 'pie') ? "border-left: solid 4px px #{option[:color]}" : ''} - case option[:name_format] - when 'i18n' = t(option[:name]) @@ -57,19 +68,19 @@ - else = option[:name] - when 'rank' - %td.text-right= option[:rank] + %td.v-table.text-right= option[:rank] - when 'score' - %td.text-right= option[:score] + %td.v-table.text-right= option[:score] - when 'voter_count' - %td.text-right= option[:voter_count] + %td.v-table.text-right= option[:voter_count] - when 'average' - %td.text-right= option[:average].round(1) + %td.v-table.text-right= option[:average].round(1) - when 'voter_percent' - %td.text-right #{option[:voter_percent].round}% + %td.v-table.text-right #{option[:voter_percent].round}% - when 'score_percent' - %td.text-right #{option[:score_percent].round(1)}% + %td.v-table.text-right #{option[:score_percent].round(1)}% - when 'voters' - %td.text-left + %td.v-table.text-left - User.where(id: option[:voter_ids]).each do |user| =render 'base_mailer/avatar', user: user, size: 24 - if option[:voter_ids].length == 0 diff --git a/vue/src/components/poll/common/chart/bar.vue b/vue/src/components/poll/common/chart/bar.vue deleted file mode 100644 index 1fb019b9b4a..00000000000 --- a/vue/src/components/poll/common/chart/bar.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/vue/src/components/poll/common/chart/count.vue b/vue/src/components/poll/common/chart/count.vue deleted file mode 100644 index 3d0c5afcb86..00000000000 --- a/vue/src/components/poll/common/chart/count.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - diff --git a/vue/src/components/poll/common/chart/table.vue b/vue/src/components/poll/common/chart/table.vue index ddc6b9efad3..99d9afd10bb 100644 --- a/vue/src/components/poll/common/chart/table.vue +++ b/vue/src/components/poll/common/chart/table.vue @@ -1,21 +1,23 @@ + + + + From 079f8ef7d8b62267f661794eeb3b0e20ce415762 Mon Sep 17 00:00:00 2001 From: Robert Guthrie Date: Wed, 4 May 2022 23:12:28 +1200 Subject: [PATCH 2/2] fixed score_counts in emails! --- .../poll/results/_simple.html.haml | 29 +++++++++---------- config/initializers/premailer_rails.rb | 1 + 2 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 config/initializers/premailer_rails.rb diff --git a/app/views/event_mailer/poll/results/_simple.html.haml b/app/views/event_mailer/poll/results/_simple.html.haml index 8eddadb8625..25d1b08e84d 100644 --- a/app/views/event_mailer/poll/results/_simple.html.haml +++ b/app/views/event_mailer/poll/results/_simple.html.haml @@ -3,7 +3,7 @@ .poll-mailer-common-results %table.v-table{style: 'min-width: 600px', cellspacing: 0} %thead - %tr.v-table + %tr - poll.result_columns.each do |col| - case col - when 'pie', 'bar', 'grid' @@ -28,26 +28,25 @@ %tbody - max_count = (poll.results.map {|o| o[:score_counts].values.max}.compact).max - results.each_with_index do |option, index| - %tr.v-table + %tr - poll.result_columns.each do |col| - case col - when 'pie' - if (index == 0) - %td.pr-2.py-2.v-table{rowspan: results.size} + %td.pr-2.py-2{rowspan: results.size} .poll-mailer-proposal__chart.poll-mailer__results-chart.d-flex.align-center.justify-center %img.poll-mailer-proposal__chart-image{style: "height: 128px; width: 128px", src: google_pie_chart_url(poll), width: 128, height: 128} - when 'bar' - if poll.chart_type == 'score_counts' - %td.pr-2.py-2.v-table{style: 'width: 128px'} + %td.pr-2.py-2{style: 'width: 128px'} %table{cellspacing: 0, cellpadding: 0, width: '100%', height: '100%'} %tr - (poll.min_score..poll.max_score).to_a.each do |score| - count = option[:score_counts].fetch(score.to_s, 0) - pct = count.to_f / max_count.to_f - - hex = (pct*100).round.to_s(16) - %td{bgcolor:"#001199#{hex}", style: "border:0; height: 24px)"}= count + %td.nostyles{style: "border:0; height: 24px; background-color: rgba(0,90,250,#{pct})"}=raw " " - else - %td.pr-2.py-2.v-table{style: 'width: 128px'} + %td.pr-2.py-2{style: 'width: 128px'} - if option[poll.chart_column] > 0 %table{cellspacing: 0, cellpadding: 0, width: '100%', height: '100%'} @@ -59,7 +58,7 @@ / %td.pr-2.py-2{rowspan: results.size} / %img.poll-mailer-proposal__chart-image{style: "height: 128px; width: 128px", src: google_pie_chart_url(poll)} - when 'name' - %td.v-table{style: (poll.chart_type == 'pie') ? "border-left: solid 4px px #{option[:color]}" : ''} + %td{style: (poll.chart_type == 'pie') ? "border-left: solid 4px px #{option[:color]}" : ''} - case option[:name_format] - when 'i18n' = t(option[:name]) @@ -68,19 +67,19 @@ - else = option[:name] - when 'rank' - %td.v-table.text-right= option[:rank] + %td.text-right= option[:rank] - when 'score' - %td.v-table.text-right= option[:score] + %td.text-right= option[:score] - when 'voter_count' - %td.v-table.text-right= option[:voter_count] + %td.text-right= option[:voter_count] - when 'average' - %td.v-table.text-right= option[:average].round(1) + %td.text-right= option[:average].round(1) - when 'voter_percent' - %td.v-table.text-right #{option[:voter_percent].round}% + %td.text-right #{option[:voter_percent].round}% - when 'score_percent' - %td.v-table.text-right #{option[:score_percent].round(1)}% + %td.text-right #{option[:score_percent].round(1)}% - when 'voters' - %td.v-table.text-left + %td.text-left - User.where(id: option[:voter_ids]).each do |user| =render 'base_mailer/avatar', user: user, size: 24 - if option[:voter_ids].length == 0 diff --git a/config/initializers/premailer_rails.rb b/config/initializers/premailer_rails.rb new file mode 100644 index 00000000000..e4dda262644 --- /dev/null +++ b/config/initializers/premailer_rails.rb @@ -0,0 +1 @@ +Premailer::Rails.config.merge!(css_to_attributes: false) \ No newline at end of file