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 %>
+
+ <%= 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 %>
-
- <%= 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