Merge pull request #5499 from consuldemocracy/fix_poll_styles

Fix styles for polls table and polls dates
This commit is contained in:
Javi Martín
2024-06-10 18:42:35 +02:00
committed by GitHub
20 changed files with 343 additions and 272 deletions

View File

@@ -47,6 +47,7 @@
@import "layout/**/*";
@import "machine_learning/**/*";
@import "moderation/**/*";
@import "polls/**/*";
@import "proposals/**/*";
@import "relationable/**/*";
@import "sdg/**/*";

View File

@@ -1515,110 +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,
.public .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;
&.can-answer::after,
&.cant-answer::after,
&.not-logged-in::after,
&.already-answer::after,
&.unverified::after {
font-family: "icons" !important;
left: 34px;
position: absolute;
top: 5px;
}
&.can-answer {
border-right: 60px solid $info-bg;
&::after {
color: $color-info;
content: "\6c";
}
}
&.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 {

View File

@@ -0,0 +1,86 @@
.public .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;
}
}
}

View File

@@ -0,0 +1,9 @@
<p>
<small><%= t("polls.index.geozone_info") %></small>
</p>
<ul class="tags">
<% poll.geozones.each do |geozone| %>
<li><span><%= geozone.name %></span></li>
<% end %>
</ul>

View File

@@ -0,0 +1,11 @@
class Polls::GeozonesComponent < ApplicationComponent
attr_reader :poll
def initialize(poll)
@poll = poll
end
def render?
poll.geozones.any?
end
end

View File

@@ -0,0 +1,56 @@
<div class="poll with-image">
<% if current_user %>
<% if current_user.unverified? %>
<div class="icon-poll-answer unverified" title="<%= t("polls.index.unverified") %>">
<span class="show-for-sr"><%= t("polls.index.unverified") %></span>
</div>
<% elsif cannot?(:answer, poll) %>
<div class="icon-poll-answer cant-answer" title="<%= t("polls.index.cant_answer") %>">
<span class="show-for-sr"><%= t("polls.index.cant_answer") %></span>
</div>
<% elsif !poll.votable_by?(current_user) %>
<div class="icon-poll-answer already-answer" title="<%= t("polls.index.already_answer") %>">
<span class="show-for-sr"><%= t("polls.index.already_answer") %></span>
</div>
<% end %>
<% else %>
<div class="icon-poll-answer not-logged-in" title="<%= t("polls.index.not_logged_in") %>">
<span class="show-for-sr"><%= t("polls.index.not_logged_in") %></span>
</div>
<% end %>
<div class="row" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-3 column">
<div class="image-container" data-equalizer-watch>
<% if poll.image.present? %>
<%= image_tag poll.image.variant(:large), alt: poll.image.title.unicode_normalize %>
<% end %>
</div>
</div>
<div class="small-12 medium-6 column" data-equalizer-watch>
<% if poll.questions.one? %>
<h4><%= link_to_poll poll.questions.first.title, poll %></h4>
<div class="dates"><%= dates %></div>
<% else %>
<h4><%= link_to_poll poll.name, poll %></h4>
<div class="dates"><%= dates %></div>
<ul class="margin-top">
<% poll.questions.sort_for_list.each do |question| %>
<li><%= question.title %></li>
<% end %>
</ul>
<% end %>
<%= render Polls::GeozonesComponent.new(poll) %>
<%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %>
</div>
<div class="small-12 medium-3 column table" data-equalizer-watch>
<div class="table-cell align-middle">
<% 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 %>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,14 @@
class Polls::PollComponent < ApplicationComponent
attr_reader :poll
use_helpers :cannot?, :current_user, :link_to_poll
def initialize(poll)
@poll = poll
end
private
def dates
t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date))
end
end

View File

@@ -0,0 +1,27 @@
<div class="expanded no-margin-top polls-show-header">
<div class="row">
<div class="small-12 medium-9 column padding">
<% 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] %>
<% end %>
<h1><%= poll.name %></h1>
<%= auto_link_already_sanitized_html simple_format(poll.summary) %>
<%= render Polls::GeozonesComponent.new(poll) %>
<%= render SDG::TagListComponent.new(poll, linkable: false) %>
</div>
<aside class="small-12 medium-3 column margin-top">
<%= render "shared/social_share",
share_title: t("shared.share"),
title: poll.name,
url: poll_url(poll),
description: poll.name,
mobile: poll.name %>
</aside>
</div>
</div>

View File

@@ -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

View File

@@ -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

View File

@@ -1,68 +1,3 @@
<% poll_group.each do |poll| %>
<div class="poll with-image">
<% if !user_signed_in? %>
<div class="icon-poll-answer not-logged-in" title="<%= t("polls.index.not_logged_in") %>">
<span class="show-for-sr"><%= t("polls.index.not_logged_in") %></span>
</div>
<% elsif user_signed_in? %>
<% if current_user.unverified? %>
<div class="icon-poll-answer unverified" title="<%= t("polls.index.unverified") %>">
<span class="show-for-sr"><%= t("polls.index.unverified") %></span>
</div>
<% elsif cannot?(:answer, poll) %>
<div class="icon-poll-answer cant-answer" title="<%= t("polls.index.cant_answer") %>">
<span class="show-for-sr"><%= t("polls.index.cant_answer") %></span>
</div>
<% elsif !poll.votable_by?(current_user) %>
<div class="icon-poll-answer already-answer" title="<%= t("polls.index.already_answer") %>">
<span class="show-for-sr"><%= t("polls.index.already_answer") %></span>
</div>
<% end %>
<% end %>
<div class="row" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-3 column">
<div class="image-container" data-equalizer-watch>
<% if poll.image.present? %>
<%= image_tag poll.image.variant(:large), alt: poll.image.title.unicode_normalize %>
<% end %>
</div>
</div>
<div class="small-12 medium-6 column" data-equalizer-watch>
<div class="dates"></div>
<% if poll.questions.one? %>
<h4><%= link_to_poll poll.questions.first.title, poll %></h4>
<%= poll_dates(poll) %>
<% else %>
<h4><%= link_to_poll poll.name, poll %></h4>
<%= poll_dates(poll) %>
<ul class="margin-top">
<% poll.questions.sort_for_list.each do |question| %>
<li><%= question.title %></li>
<% end %>
</ul>
<% end %>
<% if poll.geozones.any? %>
<p>
<small><%= t("polls.index.geozone_info") %></small>
</p>
<% end %>
<ul class="tags">
<% poll.geozones.each do |g| %>
<li><span><%= g.name %></span></li>
<% end %>
</ul>
<%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %>
</div>
<div class="small-12 medium-3 column table" data-equalizer-watch>
<div class="table-cell align-middle">
<% 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 %>
</div>
</div>
</div>
</div>
<%= render Polls::PollComponent.new(poll) %>
<% end %>

View File

@@ -1,33 +0,0 @@
<div class="expanded no-margin-top polls-show-header">
<div class="row">
<div class="small-12 medium-9 column padding">
<% 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] %>
<% end %>
<h1><%= @poll.name %></h1>
<%= auto_link_already_sanitized_html simple_format(@poll.summary) %>
<% if @poll.geozones.any? %>
<ul class="margin-top tags">
<% @poll.geozones.each do |g| %>
<li><span><%= g.name %></span></li>
<% end %>
</ul>
<% end %>
<%= render SDG::TagListComponent.new(@poll, linkable: false) %>
</div>
<aside class="small-12 medium-3 column margin-top">
<%= render "shared/social_share",
share_title: t("shared.share"),
title: @poll.name,
url: poll_url(@poll),
description: @poll.name,
mobile: @poll.name %>
</aside>
</div>
</div>

View File

@@ -1,7 +1,7 @@
<% provide :title, @poll.name %>
<div class="polls-results-stats">
<%= render "poll_header" %>
<%= render Polls::PollHeaderComponent.new(@poll) %>
<%= render "poll_subnav" %>

View File

@@ -10,7 +10,7 @@
<% end %>
<div class="polls-show">
<%= render "poll_header" %>
<%= render Polls::PollHeaderComponent.new(@poll) %>
<%= render "poll_subnav" %>

View File

@@ -1,7 +1,7 @@
<% provide :title, @poll.name %>
<div class="participation-stats polls-results-stats">
<%= render "poll_header" %>
<%= render Polls::PollHeaderComponent.new(@poll) %>
<%= render "poll_subnav" %>

View File

@@ -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:
@@ -581,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"

View File

@@ -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:

View File

@@ -0,0 +1,108 @@
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
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)
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
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)
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

View File

@@ -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

View File

@@ -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