From 2b03e3ebc41e2531fcf7316d21e5889cfb12a70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 03:35:02 +0200 Subject: [PATCH 01/10] Remove unused CSS to display poll status icons This code isn't used since commit 5fdbc7b8a. --- app/assets/stylesheets/participation.scss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 364bac7cc..b3127f0c3 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1547,7 +1547,6 @@ top: 0; width: 0; - &.can-answer::after, &.cant-answer::after, &.not-logged-in::after, &.already-answer::after, @@ -1558,15 +1557,6 @@ top: 5px; } - &.can-answer { - border-right: 60px solid $info-bg; - - &::after { - color: $color-info; - content: "\6c"; - } - } - &.cant-answer { border-right: 60px solid $alert-bg; From 765ab758dc3b12406219c999d7ec5dd6f99d10a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 03:46:04 +0200 Subject: [PATCH 02/10] Extract component to render a poll in the poll index This is consistent with the way we've got partials to render debates, proposals and legislation processes on their index pages. Note that, while adding the tests for the status icon, we're keeping one system test because it also tests the process of voting. We're adding a new, similar component test, where the voter is created in the database, so all possible statuses are tested in the component. --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/participation.scss | 88 -------------------- app/assets/stylesheets/polls/poll.scss | 86 +++++++++++++++++++ app/components/polls/poll_component.html.erb | 66 +++++++++++++++ app/components/polls/poll_component.rb | 18 ++++ app/helpers/polls_helper.rb | 8 -- app/views/polls/_poll_group.html.erb | 67 +-------------- spec/components/polls/poll_component_spec.rb | 73 ++++++++++++++++ spec/system/polls/polls_spec.rb | 60 ------------- 9 files changed, 245 insertions(+), 222 deletions(-) create mode 100644 app/assets/stylesheets/polls/poll.scss create mode 100644 app/components/polls/poll_component.html.erb create mode 100644 app/components/polls/poll_component.rb create mode 100644 spec/components/polls/poll_component_spec.rb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ae376c155..d97ec39f1 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -47,6 +47,7 @@ @import "layout/**/*"; @import "machine_learning/**/*"; @import "moderation/**/*"; +@import "polls/**/*"; @import "proposals/**/*"; @import "relationable/**/*"; @import "sdg/**/*"; diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index b3127f0c3..83c53f89a 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1515,100 +1515,12 @@ position: relative; } -.poll { - - &.with-image { - - @include breakpoint(medium) { - padding: 0 calc(#{$line-height} / 2) 0 0; - } - - .image-container img { - height: 100%; - max-width: none; - position: absolute; - } - } -} - .poll, .poll-question { border: 1px solid $border; margin-bottom: calc(#{$line-height} / 2); padding: calc(#{$line-height} / 2); position: relative; - - .icon-poll-answer { - border-top: 0; - border-bottom: 60px solid transparent; - height: 0; - position: absolute; - right: 0; - top: 0; - width: 0; - - &.cant-answer::after, - &.not-logged-in::after, - &.already-answer::after, - &.unverified::after { - font-family: "icons" !important; - left: 34px; - position: absolute; - top: 5px; - } - - &.cant-answer { - border-right: 60px solid $alert-bg; - - &::after { - color: $color-alert; - content: "\74"; - } - } - - &.not-logged-in { - border-right: 60px solid $info-bg; - - &::after { - color: $color-info; - content: "\6f"; - } - } - - &.unverified { - border-right: 60px solid $warning-bg; - - &::after { - color: $color-warning; - content: "\6f"; - } - } - - &.already-answer { - border-right: 60px solid $success-bg; - - &::after { - color: $color-success; - content: "\59"; - } - } - } - - .dates { - color: $text-medium; - font-size: $small-font-size; - margin-bottom: calc(#{$line-height} / 2); - } - - h4 { - font-size: rem-calc(30); - line-height: $line-height * 1.5; - - a { - color: inherit; - display: inline-block; - } - } } .questions-callout { diff --git a/app/assets/stylesheets/polls/poll.scss b/app/assets/stylesheets/polls/poll.scss new file mode 100644 index 000000000..501ec968d --- /dev/null +++ b/app/assets/stylesheets/polls/poll.scss @@ -0,0 +1,86 @@ +.poll { + &.with-image { + + @include breakpoint(medium) { + padding: 0 calc(#{$line-height} / 2) 0 0; + } + + .image-container img { + height: 100%; + max-width: none; + position: absolute; + } + } + + .icon-poll-answer { + border-top: 0; + border-bottom: 60px solid transparent; + height: 0; + position: absolute; + right: 0; + top: 0; + width: 0; + + &.cant-answer::after, + &.not-logged-in::after, + &.already-answer::after, + &.unverified::after { + font-family: "icons" !important; + left: 34px; + position: absolute; + top: 5px; + } + + &.cant-answer { + border-right: 60px solid $alert-bg; + + &::after { + color: $color-alert; + content: "\74"; + } + } + + &.not-logged-in { + border-right: 60px solid $info-bg; + + &::after { + color: $color-info; + content: "\6f"; + } + } + + &.unverified { + border-right: 60px solid $warning-bg; + + &::after { + color: $color-warning; + content: "\6f"; + } + } + + &.already-answer { + border-right: 60px solid $success-bg; + + &::after { + color: $color-success; + content: "\59"; + } + } + } + + .dates { + color: $text-medium; + font-size: $small-font-size; + margin-bottom: calc(#{$line-height} / 2); + } + + h4 { + font-size: rem-calc(30); + line-height: $line-height * 1.5; + + a { + color: inherit; + display: inline-block; + } + } +} diff --git a/app/components/polls/poll_component.html.erb b/app/components/polls/poll_component.html.erb new file mode 100644 index 000000000..6e52866ce --- /dev/null +++ b/app/components/polls/poll_component.html.erb @@ -0,0 +1,66 @@ +
+ <% if !user_signed_in? %> +
"> + <%= t("polls.index.not_logged_in") %> +
+ <% elsif user_signed_in? %> + <% if current_user.unverified? %> +
"> + <%= t("polls.index.unverified") %> +
+ <% elsif cannot?(:answer, poll) %> +
"> + <%= t("polls.index.cant_answer") %> +
+ <% elsif !poll.votable_by?(current_user) %> +
"> + <%= t("polls.index.already_answer") %> +
+ <% end %> + <% end %> +
+
+
+ <% if poll.image.present? %> + <%= image_tag poll.image.variant(:large), alt: poll.image.title.unicode_normalize %> + <% end %> +
+
+
+
+ <% if poll.questions.one? %> +

<%= link_to_poll poll.questions.first.title, poll %>

+ <%= dates %> + <% else %> +

<%= link_to_poll poll.name, poll %>

+ <%= dates %> + +
    + <% poll.questions.sort_for_list.each do |question| %> +
  • <%= question.title %>
  • + <% end %> +
+ <% end %> + <% if poll.geozones.any? %> +

+ <%= t("polls.index.geozone_info") %> +

+ <% end %> +
    + <% poll.geozones.each do |g| %> +
  • <%= g.name %>
  • + <% end %> +
+ <%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %> +
+
+
+ <% if poll.expired? %> + <%= link_to_poll t("polls.index.participate_button_expired"), poll, class: "button hollow expanded" %> + <% else %> + <%= link_to_poll t("polls.index.participate_button"), poll, class: "button hollow expanded" %> + <% end %> +
+
+
+
diff --git a/app/components/polls/poll_component.rb b/app/components/polls/poll_component.rb new file mode 100644 index 000000000..45aae8da8 --- /dev/null +++ b/app/components/polls/poll_component.rb @@ -0,0 +1,18 @@ +class Polls::PollComponent < ApplicationComponent + attr_reader :poll + use_helpers :cannot?, :user_signed_in?, :current_user, :link_to_poll + + def initialize(poll) + @poll = poll + end + + private + + def dates + if poll.starts_at.blank? || poll.ends_at.blank? + I18n.t("polls.no_dates") + else + I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) + end + end +end diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb index 21ae9208e..b6cadd423 100644 --- a/app/helpers/polls_helper.rb +++ b/app/helpers/polls_helper.rb @@ -1,12 +1,4 @@ module PollsHelper - def poll_dates(poll) - if poll.starts_at.blank? || poll.ends_at.blank? - I18n.t("polls.no_dates") - else - I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) - end - end - def booth_name_with_location(booth) location = booth.location.blank? ? "" : " (#{booth.location})" booth.name + location diff --git a/app/views/polls/_poll_group.html.erb b/app/views/polls/_poll_group.html.erb index 9798527b9..167edb831 100644 --- a/app/views/polls/_poll_group.html.erb +++ b/app/views/polls/_poll_group.html.erb @@ -1,68 +1,3 @@ <% poll_group.each do |poll| %> -
- <% if !user_signed_in? %> -
"> - <%= t("polls.index.not_logged_in") %> -
- <% elsif user_signed_in? %> - <% if current_user.unverified? %> -
"> - <%= t("polls.index.unverified") %> -
- <% elsif cannot?(:answer, poll) %> -
"> - <%= t("polls.index.cant_answer") %> -
- <% elsif !poll.votable_by?(current_user) %> -
"> - <%= t("polls.index.already_answer") %> -
- <% end %> - <% end %> -
-
-
- <% if poll.image.present? %> - <%= image_tag poll.image.variant(:large), alt: poll.image.title.unicode_normalize %> - <% end %> -
-
-
-
- <% if poll.questions.one? %> -

<%= link_to_poll poll.questions.first.title, poll %>

- <%= poll_dates(poll) %> - <% else %> -

<%= link_to_poll poll.name, poll %>

- <%= poll_dates(poll) %> - -
    - <% poll.questions.sort_for_list.each do |question| %> -
  • <%= question.title %>
  • - <% end %> -
- <% end %> - <% if poll.geozones.any? %> -

- <%= t("polls.index.geozone_info") %> -

- <% end %> -
    - <% poll.geozones.each do |g| %> -
  • <%= g.name %>
  • - <% end %> -
- <%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %> -
-
-
- <% if poll.expired? %> - <%= link_to_poll t("polls.index.participate_button_expired"), poll, class: "button hollow expanded" %> - <% else %> - <%= link_to_poll t("polls.index.participate_button"), poll, class: "button hollow expanded" %> - <% end %> -
-
-
-
+ <%= render Polls::PollComponent.new(poll) %> <% end %> diff --git a/spec/components/polls/poll_component_spec.rb b/spec/components/polls/poll_component_spec.rb new file mode 100644 index 000000000..ca4ea271e --- /dev/null +++ b/spec/components/polls/poll_component_spec.rb @@ -0,0 +1,73 @@ +require "rails_helper" + +describe Polls::PollComponent do + include Rails.application.routes.url_helpers + + describe "status message" do + it "asks anonymous users to sign in" do + render_inline Polls::PollComponent.new(create(:poll)) + + expect(page).to have_css ".not-logged-in", count: 1 + expect(page).to have_content "You must sign in or sign up to participate" + end + + it "asks unverified users to verify their account" do + sign_in(create(:user)) + + render_inline Polls::PollComponent.new(create(:poll)) + + expect(page).to have_css ".unverified", count: 1 + expect(page).to have_content "You must verify your account to participate" + end + + it "tell users from different geozones that the poll isn't available" do + sign_in(create(:user, :level_two)) + + render_inline Polls::PollComponent.new(create(:poll, geozone_restricted: true)) + + expect(page).to have_css ".cant-answer", count: 1 + expect(page).to have_content "This poll is not available on your geozone" + end + + it "informs users when they've already participated" do + user = create(:user, :level_two) + poll = create(:poll) + create(:poll_voter, user: user, poll: poll) + + sign_in(user) + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_css ".already-answer", count: 1 + expect(page).to have_content "You already have participated in this poll" + end + end + + it "shows a link to poll stats if enabled" do + poll = create(:poll, :expired, name: "Poll with stats", stats_enabled: true) + + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_link "Poll with stats", href: stats_poll_path(poll.slug) + expect(page).to have_link "Poll ended", href: stats_poll_path(poll.slug) + end + + it "shows a link to poll results if enabled" do + poll = create(:poll, :expired, name: "Poll with results", stats_enabled: true, results_enabled: true) + + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_link "Poll with results", href: results_poll_path(poll.slug) + expect(page).to have_link "Poll ended", href: results_poll_path(poll.slug) + end + + it "shows SDG tags when that feature is enabled" do + Setting["feature.sdg"] = true + Setting["sdg.process.polls"] = true + poll = create(:poll, sdg_goals: [SDG::Goal[1]], sdg_targets: [SDG::Target["1.1"]]) + + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_css "img[alt='1. No Poverty']" + expect(page).to have_content "target 1.1" + end +end diff --git a/spec/system/polls/polls_spec.rb b/spec/system/polls/polls_spec.rb index 19dad5252..c8b286c9a 100644 --- a/spec/system/polls/polls_spec.rb +++ b/spec/system/polls/polls_spec.rb @@ -87,36 +87,6 @@ describe "Polls" do expect(page).not_to have_link("Expired") end - scenario "Displays a message asking anonymous users to sign in" do - create_list(:poll, 3) - - visit polls_path - - expect(page).to have_css(".not-logged-in", count: 3) - expect(page).to have_content("You must sign in or sign up to participate") - end - - scenario "Displays a message asking unverified users to verify their account" do - create_list(:poll, 3) - user = create(:user) - login_as(user) - - visit polls_path - - expect(page).to have_css(".unverified", count: 3) - expect(page).to have_content("You must verify your account to participate") - end - - scenario "Geozone poll" do - create(:poll, geozone_restricted: true) - - login_as(create(:user, :level_two)) - visit polls_path - - expect(page).to have_css(".cant-answer", count: 1) - expect(page).to have_content("This poll is not available on your geozone") - end - scenario "Already participated in a poll" do poll_with_question = create(:poll) question = create(:poll_question, :yes_no, poll: poll_with_question) @@ -133,36 +103,6 @@ describe "Polls" do expect(page).to have_css(".already-answer", count: 1) expect(page).to have_content("You already have participated in this poll") end - - scenario "Poll title and button link to stats if enabled" do - poll = create(:poll, :expired, name: "Poll with stats", stats_enabled: true) - - visit polls_path(filter: "expired") - - expect(page).to have_link("Poll with stats", href: stats_poll_path(poll.slug)) - expect(page).to have_link("Poll ended", href: stats_poll_path(poll.slug)) - end - - scenario "Poll title and button link to results if enabled" do - poll = create(:poll, :expired, name: "Poll with results", stats_enabled: true, results_enabled: true) - - visit polls_path(filter: "expired") - - expect(page).to have_link("Poll with results", href: results_poll_path(poll.slug)) - expect(page).to have_link("Poll ended", href: results_poll_path(poll.slug)) - end - - scenario "Shows SDG tags when feature is enabled" do - Setting["feature.sdg"] = true - Setting["sdg.process.polls"] = true - - create(:poll, sdg_goals: [SDG::Goal[1]], sdg_targets: [SDG::Target["1.1"]]) - - visit polls_path - - expect(page).to have_css "img[alt='1. No Poverty']" - expect(page).to have_content "target 1.1" - end end context "Show" do From 08ca9208192be14acffbd24fb1fcca8497c0fb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 18:06:09 +0200 Subject: [PATCH 03/10] Simplify conditions to render poll status icons We were using a redundant `elsif` instead of an `else`. We were also using a negative condition in the main `if`, which made the code a bit harder to read. Since we usually use `current_user` instead of `user_signed_in?`, we're also changing that for consistency.Extract component to render the status of a poll --- app/components/polls/poll_component.html.erb | 10 +++++----- app/components/polls/poll_component.rb | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/components/polls/poll_component.html.erb b/app/components/polls/poll_component.html.erb index 6e52866ce..9852c1b30 100644 --- a/app/components/polls/poll_component.html.erb +++ b/app/components/polls/poll_component.html.erb @@ -1,9 +1,5 @@
- <% if !user_signed_in? %> -
"> - <%= t("polls.index.not_logged_in") %> -
- <% elsif user_signed_in? %> + <% if current_user %> <% if current_user.unverified? %>
"> <%= t("polls.index.unverified") %> @@ -17,6 +13,10 @@ <%= t("polls.index.already_answer") %>
<% end %> + <% else %> +
"> + <%= t("polls.index.not_logged_in") %> +
<% end %>
diff --git a/app/components/polls/poll_component.rb b/app/components/polls/poll_component.rb index 45aae8da8..ed0374b53 100644 --- a/app/components/polls/poll_component.rb +++ b/app/components/polls/poll_component.rb @@ -1,6 +1,6 @@ class Polls::PollComponent < ApplicationComponent attr_reader :poll - use_helpers :cannot?, :user_signed_in?, :current_user, :link_to_poll + use_helpers :cannot?, :current_user, :link_to_poll def initialize(poll) @poll = poll From 7b3b41386e0531fbd0afc2e2c0df8a453bfcd889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 04:04:22 +0200 Subject: [PATCH 04/10] Fix styles for poll dates We accidentally introduced a typo in commit f497227e3 which caused the dates to be rendered outside the element where the dates styles are applied. --- app/components/polls/poll_component.html.erb | 5 ++--- spec/components/polls/poll_component_spec.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/components/polls/poll_component.html.erb b/app/components/polls/poll_component.html.erb index 9852c1b30..24594fc7e 100644 --- a/app/components/polls/poll_component.html.erb +++ b/app/components/polls/poll_component.html.erb @@ -27,13 +27,12 @@
-
<% if poll.questions.one? %>

<%= link_to_poll poll.questions.first.title, poll %>

- <%= dates %> +
<%= dates %>
<% else %>

<%= link_to_poll poll.name, poll %>

- <%= dates %> +
<%= dates %>
    <% poll.questions.sort_for_list.each do |question| %> diff --git a/spec/components/polls/poll_component_spec.rb b/spec/components/polls/poll_component_spec.rb index ca4ea271e..154b8419e 100644 --- a/spec/components/polls/poll_component_spec.rb +++ b/spec/components/polls/poll_component_spec.rb @@ -42,6 +42,14 @@ describe Polls::PollComponent do end end + it "renders the dates inside an HTML tag" do + poll = create(:poll, starts_at: "2015-07-15", ends_at: "2015-07-22") + + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_css ".dates", exact_text: "From 2015-07-15 to 2015-07-22" + end + it "shows a link to poll stats if enabled" do poll = create(:poll, :expired, name: "Poll with stats", stats_enabled: true) From 438fe7bd25192b7432b74af4ddee1a779e101edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 18:09:00 +0200 Subject: [PATCH 05/10] Fix inner borders in polls administration tables The rows in these tables were using the styles from the `.poll` selector, and the `position: relative` property defined there caused the inner borders to disappear in some browsers (like Firefox). So we're adding the `public` class to the selector; this way, it doesn't affect elements in the admin section. Even though it's only necessary to add the `.public` prefix to the `.poll` selector in one place in order to fix this issue, we're doing it everywhere for consistency. --- app/assets/stylesheets/participation.scss | 2 +- app/assets/stylesheets/polls/poll.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 83c53f89a..bc5148df7 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1515,7 +1515,7 @@ position: relative; } -.poll, +.public .poll, .poll-question { border: 1px solid $border; margin-bottom: calc(#{$line-height} / 2); diff --git a/app/assets/stylesheets/polls/poll.scss b/app/assets/stylesheets/polls/poll.scss index 501ec968d..2770eb703 100644 --- a/app/assets/stylesheets/polls/poll.scss +++ b/app/assets/stylesheets/polls/poll.scss @@ -1,4 +1,4 @@ -.poll { +.public .poll { &.with-image { @include breakpoint(medium) { From d9662164b8076f2cb8310a389540faa38c232bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 19:23:11 +0200 Subject: [PATCH 06/10] Remove unused code to display polls with no dates When this code was added, in commit 1a20a3ce4, we had no validation rules checking the presence of the start and end dates of a poll. Now we do, so we don't have to check this condition in the view. --- app/components/polls/poll_component.rb | 6 +----- config/locales/en/general.yml | 1 - config/locales/es/general.yml | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/components/polls/poll_component.rb b/app/components/polls/poll_component.rb index ed0374b53..92a7b64b4 100644 --- a/app/components/polls/poll_component.rb +++ b/app/components/polls/poll_component.rb @@ -9,10 +9,6 @@ class Polls::PollComponent < ApplicationComponent private def dates - if poll.starts_at.blank? || poll.ends_at.blank? - I18n.t("polls.no_dates") - else - I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) - end + I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) end end diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index da77b6942..bb57d29d4 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -569,7 +569,6 @@ en: share: "And if you also do me the great favor of sharing my proposal with your friends, family and contacts, it would be perfect!" polls: all: "All" - no_dates: "no date assigned" dates: "From %{open_at} to %{closed_at}" final_date: "Final recounts/Results" index: diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 1ae7aa62f..bb91f8d66 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -569,7 +569,6 @@ es: share: "Y si además, me haces el gran favor de compartir mi propuesta con tus amigos, familiares y contactos ¡sería perfecto!" polls: all: "Todas" - no_dates: "sin fecha asignada" dates: "Desde el %{open_at} hasta el %{closed_at}" final_date: "Recuento final/Resultados" index: From bb574db1ea21fc9bf03e836d5a5bb4003e16bbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 22 Apr 2024 19:19:47 +0200 Subject: [PATCH 07/10] Allow customizing the text to display poll dates Since we were using `I18n.t`, our monkey-patch of the `t` helper wasn't being applied. --- app/components/polls/poll_component.rb | 2 +- spec/components/polls/poll_component_spec.rb | 21 ++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/components/polls/poll_component.rb b/app/components/polls/poll_component.rb index 92a7b64b4..a1cda60ea 100644 --- a/app/components/polls/poll_component.rb +++ b/app/components/polls/poll_component.rb @@ -9,6 +9,6 @@ class Polls::PollComponent < ApplicationComponent private def dates - I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) + t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date)) end end diff --git a/spec/components/polls/poll_component_spec.rb b/spec/components/polls/poll_component_spec.rb index 154b8419e..9cd5ea50a 100644 --- a/spec/components/polls/poll_component_spec.rb +++ b/spec/components/polls/poll_component_spec.rb @@ -42,12 +42,25 @@ describe Polls::PollComponent do end end - it "renders the dates inside an HTML tag" do - poll = create(:poll, starts_at: "2015-07-15", ends_at: "2015-07-22") + describe "dates" do + it "renders the dates inside an HTML tag" do + poll = create(:poll, starts_at: "2015-07-15", ends_at: "2015-07-22") - render_inline Polls::PollComponent.new(poll) + render_inline Polls::PollComponent.new(poll) - expect(page).to have_css ".dates", exact_text: "From 2015-07-15 to 2015-07-22" + expect(page).to have_css ".dates", exact_text: "From 2015-07-15 to 2015-07-22" + end + + it "allows customizing the text to display dates" do + poll = create(:poll, starts_at: "2015-07-15", ends_at: "2015-07-22") + create(:i18n_content, key: "polls.dates", value: "Starts someday and finishes who-knows-when") + + render_inline Polls::PollComponent.new(poll) + + expect(page).to have_css ".dates", exact_text: "Starts someday and finishes who-knows-when" + expect(page).not_to have_content "2015-07-15" + expect(page).not_to have_content "2015-07-22" + end end it "shows a link to poll stats if enabled" do From 5dc98929fc0bbdca998903fe13eadcdc9d0dd825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 7 Jun 2024 21:03:20 +0200 Subject: [PATCH 08/10] Move poll header partial to a component This way it'll be easier to write tests for it when we change it. --- .../polls/poll_header_component.html.erb} | 22 +++++++++---------- app/components/polls/poll_header_component.rb | 8 +++++++ app/views/polls/results.html.erb | 2 +- app/views/polls/show.html.erb | 2 +- app/views/polls/stats.html.erb | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) rename app/{views/polls/_poll_header.html.erb => components/polls/poll_header_component.html.erb} (50%) create mode 100644 app/components/polls/poll_header_component.rb diff --git a/app/views/polls/_poll_header.html.erb b/app/components/polls/poll_header_component.html.erb similarity index 50% rename from app/views/polls/_poll_header.html.erb rename to app/components/polls/poll_header_component.html.erb index 73cd608db..c4b2e6cad 100644 --- a/app/views/polls/_poll_header.html.erb +++ b/app/components/polls/poll_header_component.html.erb @@ -1,33 +1,33 @@
    - <% if @poll.related.nil? %> + <% if poll.related.nil? %> <%= back_link_to polls_path, t("polls.show.back") %> <% else %> - <%= link_to t("polls.poll_header.back_to_proposal"), [@poll.related] %> + <%= link_to t("polls.poll_header.back_to_proposal"), [poll.related] %> <% end %> -

    <%= @poll.name %>

    +

    <%= poll.name %>

    - <%= auto_link_already_sanitized_html simple_format(@poll.summary) %> + <%= auto_link_already_sanitized_html simple_format(poll.summary) %> - <% if @poll.geozones.any? %> + <% if poll.geozones.any? %>
      - <% @poll.geozones.each do |g| %> + <% poll.geozones.each do |g| %>
    • <%= g.name %>
    • <% end %>
    <% end %> - <%= render SDG::TagListComponent.new(@poll, linkable: false) %> + <%= render SDG::TagListComponent.new(poll, linkable: false) %>
    diff --git a/app/components/polls/poll_header_component.rb b/app/components/polls/poll_header_component.rb new file mode 100644 index 000000000..a4da1befe --- /dev/null +++ b/app/components/polls/poll_header_component.rb @@ -0,0 +1,8 @@ +class Polls::PollHeaderComponent < ApplicationComponent + attr_reader :poll + use_helpers :auto_link_already_sanitized_html + + def initialize(poll) + @poll = poll + end +end diff --git a/app/views/polls/results.html.erb b/app/views/polls/results.html.erb index 940be9e8a..8f6cddd44 100644 --- a/app/views/polls/results.html.erb +++ b/app/views/polls/results.html.erb @@ -1,7 +1,7 @@ <% provide :title, @poll.name %>
    - <%= render "poll_header" %> + <%= render Polls::PollHeaderComponent.new(@poll) %> <%= render "poll_subnav" %> diff --git a/app/views/polls/show.html.erb b/app/views/polls/show.html.erb index 3d9d88494..0ccbeaad1 100644 --- a/app/views/polls/show.html.erb +++ b/app/views/polls/show.html.erb @@ -10,7 +10,7 @@ <% end %>
    - <%= render "poll_header" %> + <%= render Polls::PollHeaderComponent.new(@poll) %> <%= render "poll_subnav" %> diff --git a/app/views/polls/stats.html.erb b/app/views/polls/stats.html.erb index dcc45836d..b99052f48 100644 --- a/app/views/polls/stats.html.erb +++ b/app/views/polls/stats.html.erb @@ -1,7 +1,7 @@ <% provide :title, @poll.name %>
    - <%= render "poll_header" %> + <%= render Polls::PollHeaderComponent.new(@poll) %> <%= render "poll_subnav" %> From ae026f0f6f34fb8cc657f466258632b1705c79e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 7 Jun 2024 21:23:42 +0200 Subject: [PATCH 09/10] Fix text providing geozone info The text wasn't gramatically correct in English, since it had the verb before the subject. Since I'm not a native English speaker, I'm not sure about the correct way to mention the Census part. I'm using "residents in" since it sounds OK to me, but I might be wrong. --- config/locales/en/general.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index bb57d29d4..50d61d52e 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -580,7 +580,7 @@ en: participate_button_expired: "Poll ended" no_geozone_restricted: "All city" geozone_restricted: "Districts" - geozone_info: "Can participate people in the Census of: " + geozone_info: "Only residents in the following areas can participate: " already_answer: "You already have participated in this poll" not_logged_in: "You must sign in or sign up to participate" unverified: "You must verify your account to participate" From eef9f584100b5e9f1d9d9dfdd74e0e5c94e66f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 7 Jun 2024 16:16:59 +0200 Subject: [PATCH 10/10] Extract component to render poll geozones This way we remove a bit of duplication. These changes also affect the way geozones are rendered in a couple of minor ways, making them more consistent: * No empty list of geozones is rendered when there are no geozones (before these changes, an empty list was rendered in the index action but not in the show action) * The text clarifying the geozone restriction is always shown (before these changes, it was shown in the index action but not in the show action) We've added tests for these cases. --- .../polls/geozones_component.html.erb | 9 +++++++++ app/components/polls/geozones_component.rb | 11 +++++++++++ app/components/polls/poll_component.html.erb | 11 +---------- .../polls/poll_header_component.html.erb | 8 +------- spec/components/polls/poll_component_spec.rb | 14 ++++++++++++++ .../polls/poll_header_component_spec.rb | 17 +++++++++++++++++ 6 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 app/components/polls/geozones_component.html.erb create mode 100644 app/components/polls/geozones_component.rb create mode 100644 spec/components/polls/poll_header_component_spec.rb diff --git a/app/components/polls/geozones_component.html.erb b/app/components/polls/geozones_component.html.erb new file mode 100644 index 000000000..09785642b --- /dev/null +++ b/app/components/polls/geozones_component.html.erb @@ -0,0 +1,9 @@ +

    + <%= t("polls.index.geozone_info") %> +

    + +
      + <% poll.geozones.each do |geozone| %> +
    • <%= geozone.name %>
    • + <% end %> +
    diff --git a/app/components/polls/geozones_component.rb b/app/components/polls/geozones_component.rb new file mode 100644 index 000000000..75e982c0b --- /dev/null +++ b/app/components/polls/geozones_component.rb @@ -0,0 +1,11 @@ +class Polls::GeozonesComponent < ApplicationComponent + attr_reader :poll + + def initialize(poll) + @poll = poll + end + + def render? + poll.geozones.any? + end +end diff --git a/app/components/polls/poll_component.html.erb b/app/components/polls/poll_component.html.erb index 24594fc7e..110bef076 100644 --- a/app/components/polls/poll_component.html.erb +++ b/app/components/polls/poll_component.html.erb @@ -40,16 +40,7 @@ <% end %>
<% end %> - <% if poll.geozones.any? %> -

- <%= t("polls.index.geozone_info") %> -

- <% end %> -
    - <% poll.geozones.each do |g| %> -
  • <%= g.name %>
  • - <% end %> -
+ <%= render Polls::GeozonesComponent.new(poll) %> <%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %>
diff --git a/app/components/polls/poll_header_component.html.erb b/app/components/polls/poll_header_component.html.erb index c4b2e6cad..6058b9bcf 100644 --- a/app/components/polls/poll_header_component.html.erb +++ b/app/components/polls/poll_header_component.html.erb @@ -11,13 +11,7 @@ <%= auto_link_already_sanitized_html simple_format(poll.summary) %> - <% if poll.geozones.any? %> -
    - <% poll.geozones.each do |g| %> -
  • <%= g.name %>
  • - <% end %> -
- <% end %> + <%= render Polls::GeozonesComponent.new(poll) %> <%= render SDG::TagListComponent.new(poll, linkable: false) %>
diff --git a/spec/components/polls/poll_component_spec.rb b/spec/components/polls/poll_component_spec.rb index 9cd5ea50a..a12041ff8 100644 --- a/spec/components/polls/poll_component_spec.rb +++ b/spec/components/polls/poll_component_spec.rb @@ -63,6 +63,20 @@ describe Polls::PollComponent do end end + describe "geozones" do + it "renders a list of geozones when the poll is geozone-restricted" do + render_inline Polls::PollComponent.new(create(:poll, geozone_restricted_to: [create(:geozone)])) + + expect(page).to have_css ".tags" + end + + it "does not render a list of geozones when the poll isn't geozone-restricted" do + render_inline Polls::PollComponent.new(create(:poll)) + + expect(page).not_to have_css ".tags" + end + end + it "shows a link to poll stats if enabled" do poll = create(:poll, :expired, name: "Poll with stats", stats_enabled: true) diff --git a/spec/components/polls/poll_header_component_spec.rb b/spec/components/polls/poll_header_component_spec.rb new file mode 100644 index 000000000..6062a62ec --- /dev/null +++ b/spec/components/polls/poll_header_component_spec.rb @@ -0,0 +1,17 @@ +require "rails_helper" + +describe Polls::PollHeaderComponent do + describe "geozones" do + it "shows a text when the poll is geozone-restricted" do + render_inline Polls::PollHeaderComponent.new(create(:poll, geozone_restricted_to: [create(:geozone)])) + + expect(page).to have_content "Only residents in the following areas can participate" + end + + it "does not show the text when the poll isn't geozone-restricted" do + render_inline Polls::PollHeaderComponent.new(create(:poll)) + + expect(page).not_to have_content "Only residents in the following areas can participate" + end + end +end