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