Merge pull request #5897 from consuldemocracy/replace_equalizer_with_flex

Use flex and grid layouts instead of data-equalizer
This commit is contained in:
Javi Martín
2025-08-28 14:40:53 +02:00
committed by GitHub
62 changed files with 948 additions and 814 deletions

View File

@@ -83,6 +83,7 @@ rules:
"@stylistic/indentation":
- 2
- ignore:
- param
- value
"@stylistic/media-feature-parentheses-space-inside": never
"@stylistic/no-eol-whitespace": true

View File

@@ -21,6 +21,7 @@
@import "account/**/*";
@import "budgets/**/*";
@import "comments/**/*";
@import "dashboard/**/*";
@import "debates/**/*";
@import "devise/**/*";
@import "documents/**/*";

View File

@@ -2,7 +2,6 @@
//
// 01. Dashboard global
// 02. Actions
// 03. Resources
// 04. Goals
// 05. Sidebar
// 06. Community
@@ -165,62 +164,6 @@
}
}
// 03. Resources
// -------------
.resource-card {
background: #d1f5eb;
border-radius: rem-calc(4);
margin-bottom: $line-height;
min-height: $line-height * 9;
padding: $line-height * 2 $line-height $line-height;
position: relative;
text-align: center;
&.alert {
background: #feeaeb;
&::before {
color: #fb9497;
content: "\74";
}
}
&::before {
border: 2px solid;
border-radius: rem-calc(40);
color: #00cb96;
content: "\6c";
font-family: "icons";
font-size: rem-calc(20);
height: rem-calc(36);
position: absolute;
right: 12px;
top: 12px;
width: rem-calc(36);
}
.label {
left: 0;
position: absolute;
top: 20px;
}
h4 {
margin-top: $line-height;
}
.resource-description {
min-height: $line-height * 4;
}
.button {
background: #00cb96;
color: #000;
font-weight: bold;
}
}
// 04. Goals
// ---------
@@ -429,28 +372,6 @@
padding: $line-height;
}
.poll-card {
background: #e7f3fd;
border-radius: rem-calc(4);
margin-bottom: $line-height;
min-height: $line-height * 9;
padding: $line-height;
position: relative;
text-align: center;
.button {
font-weight: bold;
}
button {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.community-poll {
border-bottom: 1px solid $border;
margin-bottom: $line-height;

View File

@@ -0,0 +1,22 @@
.dashboard-poll {
background: #e7f3fd;
border-radius: rem-calc(4);
display: flex;
flex-direction: column;
min-height: $line-height * 9;
padding: $line-height;
position: relative;
text-align: center;
.button {
font-weight: bold;
}
button {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}

View File

@@ -0,0 +1,4 @@
.dashboard-polls {
@include dynamic-grid;
margin-top: $line-height;
}

View File

@@ -0,0 +1,55 @@
.dashboard-resources {
.resources {
@include dynamic-grid;
.resource-card {
background: #d1f5eb;
border-radius: rem-calc(4);
display: flex;
flex-direction: column;
justify-content: space-between;
padding: $line-height * 2 $line-height $line-height;
position: relative;
text-align: center;
&.alert {
background: #feeaeb;
&::before {
color: #fb9497;
content: "\74";
}
}
&::before {
border: 2px solid;
border-radius: rem-calc(40);
color: #00cb96;
content: "\6c";
font-family: "icons";
font-size: rem-calc(20);
height: rem-calc(36);
position: absolute;
right: 12px;
top: 12px;
width: rem-calc(36);
}
.label {
left: 0;
position: absolute;
top: 20px;
}
h4 {
margin-top: $line-height;
}
.button {
background: #00cb96;
color: #000;
font-weight: bold;
}
}
}
}

View File

@@ -403,18 +403,10 @@ button,
vertical-align: top;
}
.align-middle {
vertical-align: middle;
}
.table {
display: table;
}
.table-cell {
display: table-cell;
}
.uppercase {
text-transform: uppercase;
}
@@ -1865,40 +1857,6 @@ table {
}
}
.following {
.follow-list {
list-style-type: circle;
padding: calc($line-height / 2);
li {
margin-bottom: calc($line-height / 2);
margin-left: $line-height;
}
}
h3 {
font-size: rem-calc(24);
margin-top: $line-height;
padding-left: rem-calc(30);
position: relative;
span {
left: 0;
position: absolute;
top: 2px;
}
}
.interests {
@include breakpoint(medium) {
border-left: 1px solid #ececec;
padding-left: $line-height;
}
}
}
// 19. Recommendations
// -------------------
@@ -2039,67 +1997,6 @@ table {
}
}
.recommended-index {
@include full-width-background;
@include full-width-border(bottom, 1px solid #eee);
@include full-width-border(top, 1px solid #fafafa);
background: #fafafa;
margin-bottom: $line-height;
margin-top: rem-calc(-25);
padding: $line-height 0 calc($line-height / 2);
@include breakpoint(medium) {
padding-top: 0;
}
h2 {
font-size: $small-font-size;
text-transform: uppercase;
}
h3 {
font-size: $base-font-size;
margin-bottom: 0;
}
a {
&:hover {
text-decoration: none;
}
}
.recommendation {
@include card;
background: $body-background;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
display: block;
margin-bottom: calc($line-height / 4);
padding: calc($line-height / 2);
z-index: 1;
&:hover:not(:focus-within) {
box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.15);
}
}
}
.hide-recommendations {
color: $text-light;
cursor: pointer;
font-size: $small-font-size;
line-height: inherit;
position: absolute;
right: 12px;
top: -18px;
z-index: 2;
&:focus,
&:hover {
@include anchor-color-hover;
}
}
// 20. Documents
// -------------

View File

@@ -32,6 +32,15 @@
}
}
@mixin dynamic-grid($min-column-width: 15rem,
$row-gap: $line-height,
$column-gap: rem-calc(map-get($grid-column-gutter, medium))) {
display: grid;
gap: $row-gap $column-gap;
grid-auto-rows: 1fr;
grid-template-columns: repeat(auto-fit, minmax($min-column-width, 1fr));
}
@mixin full-width-cover($adjust-margin: true, $adjust-padding: false) {
$global-padding: rem-calc(map-get($grid-column-gutter, medium)) * 0.5;
bottom: 0;

View File

@@ -1390,12 +1390,6 @@
}
}
.image-container {
background: #fafafa;
overflow: hidden;
position: relative;
}
.public .poll {
border: 1px solid $border;
margin-bottom: calc($line-height / 2);
@@ -1415,7 +1409,8 @@
// 09. Polls results and stats
// ---------------------------
.polls-results-stats {
.polls-results,
.polls-stats {
table {
table-layout: fixed;

View File

@@ -0,0 +1,55 @@
.poll .access-status {
border-bottom: 60px solid transparent;
border-top: 0;
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";
}
}
}

View File

@@ -2,69 +2,37 @@
&.with-image {
@include breakpoint(medium) {
display: flex;
padding: 0 calc($line-height / 2) 0 0;
}
.image-container img {
height: 100%;
max-width: none;
position: absolute;
> * {
flex-basis: 25%;
}
.poll-info {
flex-basis: 50%;
}
> a {
align-self: center;
}
> .poll-info,
> a {
margin-#{$global-left}: rem-calc(map-get($grid-column-gutter, medium));
}
}
}
.icon-poll-answer {
border-bottom: 60px solid transparent;
border-top: 0;
height: 0;
position: absolute;
right: 0;
top: 0;
width: 0;
.image-container {
background: #fafafa;
overflow: hidden;
position: relative;
&.cant-answer::after,
&.not-logged-in::after,
&.already-answer::after,
&.unverified::after {
font-family: "icons" !important;
left: 34px;
img {
height: 100%;
max-width: none;
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";
}
}
}

View File

@@ -0,0 +1,22 @@
.polls-results {
.polls-results-content {
margin-bottom: $line-height;
margin-top: $line-height;
@include breakpoint(medium) {
display: flex;
> :first-child {
flex-basis: 25%;
}
> :last-child {
flex-basis: 75%;
}
}
> * {
@include grid-column-gutter;
}
}
}

View File

@@ -0,0 +1,77 @@
.recommended-index {
@include full-width-background;
@include full-width-border(bottom, 1px solid #eee);
@include full-width-border(top, 1px solid #fafafa);
background: #fafafa;
margin-bottom: $line-height;
margin-top: rem-calc(-25);
padding: $line-height 0 calc($line-height / 2);
@include breakpoint(medium) {
padding-top: 0;
}
h2 {
font-size: $small-font-size;
text-transform: uppercase;
}
ul {
$row-gap: calc($line-height / 4);
@include dynamic-grid($row-gap: $row-gap);
@include grid-column-gutter;
font-weight: bold;
list-style: none;
margin: 0;
@include breakpoint(medium) {
+ * {
text-align: $global-right;
}
}
+ * {
@include grid-column-gutter;
margin-top: $row-gap;
}
}
a {
&:hover {
text-decoration: none;
}
}
.recommendation {
background: $body-background;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
display: block;
padding: calc($line-height / 2);
z-index: 1;
&:hover:not(:focus-within) {
box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.15);
}
}
.hide-recommendations {
color: $text-light;
cursor: pointer;
font-size: $small-font-size;
line-height: inherit;
position: absolute;
right: 12px;
top: 0;
z-index: 2;
@include breakpoint(medium) {
top: -18px;
}
&:focus,
&:hover {
@include anchor-color-hover;
}
}
}

View File

@@ -0,0 +1,40 @@
.users-following {
margin-top: $line-height;
@include breakpoint(medium) {
display: flex;
> .followables {
flex-basis: calc(100% * 2 / 3);
}
> .interests {
border-left: 1px solid #ececec;
flex-basis: calc(100% / 3);
padding-left: $line-height;
}
}
.follow-list {
list-style-type: circle;
padding: calc($line-height / 2);
li {
margin-bottom: calc($line-height / 2);
margin-left: $line-height;
}
}
h3 {
font-size: rem-calc(24);
margin-top: $line-height;
padding-left: rem-calc(30);
position: relative;
span {
left: 0;
position: absolute;
top: 2px;
}
}
}

View File

@@ -0,0 +1,23 @@
<div id="<%= dom_id(resource) %>"
class="resource-card <%= resource_card_class %>"
title="<%= resource_tooltip %>">
<h4><%= resource.title %></h4>
<% if is_new_action_since_last_login?(resource, new_actions_since_last_login) %>
<span class="label"><%= t("dashboard.progress.new_action") %></span>
<% end %>
<p class="resource-description"><%= resource.short_description %></p>
<% if resource.executed_for?(proposal) || (!resource.request_to_administrators && resource.active_for?(proposal)) %>
<%= link_to t("dashboard.resource.view_resource"),
new_request_proposal_dashboard_action_path(proposal, resource),
class: "button" %>
<% elsif resource.requested_for?(proposal) %>
<strong><%= t("dashboard.resource.resource_requested") %></strong>
<% elsif resource.active_for?(proposal) %>
<%= link_to t("dashboard.resource.request_resource"),
new_request_proposal_dashboard_action_path(proposal, resource),
class: "button" %>
<% else %>
<strong><%= resource_availability_label %></strong>
<% end %>
</div>

View File

@@ -0,0 +1,37 @@
class Dashboard::ActiveResourceComponent < ApplicationComponent
attr_reader :resource, :proposal, :new_actions_since_last_login
use_helpers :is_new_action_since_last_login?
def initialize(resource, proposal, new_actions_since_last_login)
@resource = resource
@proposal = proposal
@new_actions_since_last_login = new_actions_since_last_login
end
def resource_card_class
return "alert" unless resource.active_for?(proposal)
return "success" if resource.executed_for?(proposal)
"primary"
end
def resource_tooltip
return t("dashboard.resource.resource_locked") unless resource.active_for?(proposal)
return t("dashboard.resource.view_resource") if resource.executed_for?(proposal)
return t("dashboard.resource.resource_requested") if resource.requested_for?(proposal)
t("dashboard.resource.request_resource")
end
def resource_availability_label
label = []
label << t("dashboard.resource.required_days",
days: resource.day_offset) if resource.day_offset > 0
label << t("dashboard.resource.required_supports",
supports: number_with_delimiter(resource.required_supports,
delimiter: ".")) if resource.required_supports > 0
safe_join label, h(" #{t("dashboard.resource.and")})") + tag(:br)
end
end

View File

@@ -0,0 +1,6 @@
<div class="resource-card">
<h4><%= t("dashboard.menu.#{resource}") %></h4>
<p class="resource-description"><%= resource_description %></p>
<%= link_to t("dashboard.resource.view_resource"), resource_path, class: "button" %>
</div>

View File

@@ -0,0 +1,29 @@
class Dashboard::DefaultResourceComponent < ApplicationComponent
attr_reader :resource, :proposal
use_helpers :can?
def initialize(resource, proposal)
@resource = resource
@proposal = proposal
end
def render?
can?(:"manage_#{resource}", proposal)
end
def resource_description
if resource == "mailing"
Setting["proposals.email_short_title"]
else
Setting["proposals.#{resource}_short_title"]
end
end
def resource_path
if resource == "polls"
proposal_dashboard_polls_path(proposal)
else
send("new_proposal_dashboard_#{resource}_path", proposal)
end
end
end

View File

@@ -0,0 +1,34 @@
<div id="<%= dom_id(poll) %>" class="dashboard-poll">
<h4><%= link_to poll.title, proposal_poll_path(proposal, poll) %></h4>
<span class="small">
<%= l(poll.starts_at.to_date) %> - <%= l(poll.ends_at.to_date) %>
</span>
<p class="margin-top">
<strong><%= t("dashboard.polls.poll.responses", count: poll.answer_count) %></strong>
</p>
<div class="small-12 column small-centered margin-top">
<% if poll.starts_at.to_date >= Date.current %>
<%= link_to t("dashboard.polls.poll.edit_poll"),
edit_proposal_dashboard_poll_path(proposal, poll), class: "button hollow" %>
<% else %>
<%= link_to t("dashboard.polls.poll.view_results"),
results_proposal_poll_path(proposal, poll),
class: "button" %>
<% end %>
</div>
<%= form_for poll, remote: true,
data: { type: :json },
url: proposal_dashboard_poll_path(proposal, poll) do |f| %>
<%= f.check_box :results_enabled, class: "js-submit-on-change" %>
<% end %>
<p class="help-text"><%= t("dashboard.polls.poll.show_results_help") %></p>
<%= button_to t("dashboard.polls.poll.delete"),
proposal_dashboard_poll_path(proposal, poll),
method: :delete,
"data-confirm": t("dashboard.polls.poll.alert_notice"),
class: "delete" %>
</div>

View File

@@ -0,0 +1,13 @@
class Dashboard::PollComponent < ApplicationComponent
attr_reader :poll
def initialize(poll)
@poll = poll
end
private
def proposal
poll.related
end
end

View File

@@ -0,0 +1,5 @@
<div class="dashboard-polls">
<% polls.each do |poll| %>
<%= render Dashboard::PollComponent.new(poll) %>
<% end %>
</div>

View File

@@ -0,0 +1,11 @@
class Dashboard::PollsComponent < ApplicationComponent
attr_reader :polls
def initialize(polls)
@polls = polls
end
def render?
polls.any?
end
end

View File

@@ -0,0 +1,12 @@
<div class="dashboard-resources">
<h3 class="title"><%= t("dashboard.resources.available_resources") %></h3>
<div class="resources">
<% default_resources.each do |resource| %>
<%= render Dashboard::DefaultResourceComponent.new(resource, proposal) %>
<% end %>
<% active_resources.each do |resource| %>
<%= render Dashboard::ActiveResourceComponent.new(resource, proposal, new_actions_since_last_login) %>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,21 @@
class Dashboard::ResourcesComponent < ApplicationComponent
attr_reader :proposal, :new_actions_since_last_login
def initialize(proposal, new_actions_since_last_login = [])
@proposal = proposal
@new_actions_since_last_login = new_actions_since_last_login
end
private
def default_resources
%w[polls mailing poster]
end
def active_resources
@active_resources ||= Dashboard::Action.active
.resources
.by_proposal(proposal)
.order(required_supports: :asc, day_offset: :asc)
end
end

View File

@@ -0,0 +1,3 @@
<div class="access-status <%= html_class %>" title="<%= text %>">
<span class="show-for-sr"><%= text %></span>
</div>

View File

@@ -0,0 +1,36 @@
class Polls::AccessStatusComponent < ApplicationComponent
attr_reader :poll
use_helpers :cannot?, :current_user
def initialize(poll)
@poll = poll
end
def render?
attributes.present?
end
private
def text
attributes[:text]
end
def html_class
attributes[:class]
end
def attributes
if current_user
if current_user.unverified?
{ text: t("polls.index.unverified"), class: "unverified" }
elsif cannot?(:answer, poll)
{ text: t("polls.index.cant_answer"), class: "cant-answer" }
elsif !poll.votable_by?(current_user)
{ text: t("polls.index.already_answer"), class: "already-answer" }
end
else
{ text: t("polls.index.not_logged_in"), class: "not-logged-in" }
end
end
end

View File

@@ -1,56 +1,33 @@
<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>
<%= render Polls::AccessStatusComponent.new(poll) %>
<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 class="image-container">
<% if poll.image.present? %>
<%= image_tag poll.image.variant(:large), alt: poll.image.title.unicode_normalize %>
<% end %>
</div>
<div class="poll-info">
<% 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>
<% 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>

View File

@@ -1,6 +1,6 @@
class Polls::PollComponent < ApplicationComponent
attr_reader :poll
use_helpers :cannot?, :current_user, :link_to_poll
use_helpers :can?
def initialize(poll)
@poll = poll
@@ -11,4 +11,14 @@ class Polls::PollComponent < ApplicationComponent
def dates
t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date))
end
def link_to_poll(text, poll, options = {})
if can?(:results, poll)
link_to text, results_poll_path(id: poll.slug || poll.id), options
elsif can?(:stats, poll)
link_to text, stats_poll_path(id: poll.slug || poll.id), options
else
link_to text, poll_path(id: poll.slug || poll.id), options
end
end
end

View File

@@ -0,0 +1,22 @@
<% provide :title, poll.name %>
<div class="polls-results">
<%= render Polls::PollHeaderComponent.new(poll) %>
<%= render "poll_subnav" %>
<div class="polls-results-content">
<div>
<p><strong><%= t("polls.show.results.title") %></strong></p>
<ul class="menu vertical">
<%- poll.questions.each do |question| %>
<li><%= link_to question.title, "##{question.title.parameterize}" %></li>
<% end %>
</ul>
</div>
<div>
<%= render Polls::Results::QuestionComponent.with_collection(poll.questions) %>
</div>
</div>
</div>

View File

@@ -0,0 +1,7 @@
class Polls::ResultsComponent < ApplicationComponent
attr_reader :poll
def initialize(poll)
@poll = poll
end
end

View File

@@ -0,0 +1,30 @@
<div class="recommended-index">
<h2 class="show-for-sr"><%= t("shared.recommended_index.title") %></h2>
<div id="recommendations" data-toggler=".hide">
<%= button_to disable_recommendations_path, title: t("shared.recommended_index.hide"),
class: "hide-recommendations",
data: {
toggle: "recommendations",
confirm: t("#{namespace}.index.recommendations.disable")
},
method: :put do %>
<span class="icon-x"></span>
<span class="show-for-sr"><%= t("shared.recommended_index.hide") %></span>
<% end %>
<ul>
<% recommendations.each do |recommendation| %>
<li>
<%= link_to recommendation.title, polymorphic_path(recommendation), class: "recommendation" %>
</li>
<% end %>
</ul>
<div>
<%= link_to t("shared.recommended_index.see_more"),
current_path_with_query_params(order: "recommendations"),
class: "small" %>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
class Shared::RecommendedIndexComponent < ApplicationComponent
attr_reader :recommendations, :namespace
use_helpers :current_path_with_query_params
def initialize(recommendations, namespace:)
@recommendations = recommendations
@namespace = namespace
end
def render?
feature?("user.recommendations") && recommendations.present?
end
private
def disable_recommendations_path
if namespace == "debates"
recommendations_disable_debates_path
else
recommendations_disable_proposals_path
end
end
end

View File

@@ -1,5 +1,5 @@
<div class="row following margin-top" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-8 column" data-equalizer-watch>
<div class="users-following">
<div class="followables">
<ul class="menu simple clear">
<% follows.each do |followable_type, follows| %>
<li><%= link_to followable_type_title(followable_type), "##{followable_type_title(followable_type).parameterize.underscore}" %></li>
@@ -21,7 +21,7 @@
<% end %>
</div>
<div class="small-12 medium-4 column interests" data-equalizer-watch>
<div class="interests">
<%= render "interests", user: user %>
</div>
</div>

View File

@@ -0,0 +1,32 @@
class Users::FollowingComponent < ApplicationComponent
attr_reader :user, :follows
def initialize(user, follows:)
@user = user
@follows = follows
end
private
def followable_type_title(followable_type)
t("activerecord.models.#{followable_type.underscore}.other")
end
def followable_icon(followable)
{ proposals: "Proposal", budget: "Budget::Investment" }.invert[followable]
end
def render_follow(follow)
return if follow.followable.blank?
followable = follow.followable
partial = "#{followable_class_name(followable)}_follow"
locals = { followable_class_name(followable).to_sym => followable }
render partial, locals
end
def followable_class_name(followable)
followable.class.to_s.parameterize(separator: "_")
end
end

View File

@@ -16,7 +16,7 @@
</ul>
<% if current_filter == "follows" %>
<%= render "users/following", user: user, follows: follows.group_by(&:followable_type) %>
<%= render Users::FollowingComponent.new(user, follows: follows.group_by(&:followable_type)) %>
<% else %>
<%= render_user_partial current_filter %>
<% end %>

View File

@@ -1,5 +1,5 @@
class DashboardController < Dashboard::BaseController
helper_method :dashboard_action, :active_resources, :course
helper_method :dashboard_action, :course
before_action :set_done_and_pending_actions, only: [:recommended_actions, :progress]
before_action :authorize_dashboard, except: :publish
@@ -30,13 +30,6 @@ class DashboardController < Dashboard::BaseController
private
def active_resources
@active_resources ||= Dashboard::Action.active
.resources
.by_proposal(proposal)
.order(required_supports: :asc, day_offset: :asc)
end
def course
@course ||= Dashboard::Action.course_for(proposal)
end

View File

@@ -1,26 +1,4 @@
module FollowablesHelper
def followable_type_title(followable_type)
t("activerecord.models.#{followable_type.underscore}.other")
end
def followable_icon(followable)
{ proposals: "Proposal", budget: "Budget::Investment" }.invert[followable]
end
def render_follow(follow)
return if follow.followable.blank?
followable = follow.followable
partial = "#{followable_class_name(followable)}_follow"
locals = { followable_class_name(followable).to_sym => followable }
render partial, locals
end
def followable_class_name(followable)
followable.class.to_s.parameterize(separator: "_")
end
def find_or_build_follow(user, followable)
Follow.find_or_initialize_by(user: user, followable: followable)
end

View File

@@ -4,16 +4,6 @@ module PollsHelper
booth.name + location
end
def link_to_poll(text, poll, options = {})
if can?(:results, poll)
link_to text, results_poll_path(id: poll.slug || poll.id), options
elsif can?(:stats, poll)
link_to text, stats_poll_path(id: poll.slug || poll.id), options
else
link_to text, poll_path(id: poll.slug || poll.id), options
end
end
def results_menu?
controller_name == "polls" && action_name == "results"
end

View File

@@ -56,18 +56,6 @@ module ProposalsDashboardHelper
controller_name == "dashboard" && action_name == "new_request" && dashboard_action&.id == id
end
def resource_availability_label(resource)
label = []
label << t("dashboard.resource.required_days",
days: resource.day_offset) if resource.day_offset > 0
label << t("dashboard.resource.required_supports",
supports: number_with_delimiter(resource.required_supports,
delimiter: ".")) if resource.required_supports > 0
safe_join label, h(" #{t("dashboard.resource.and")})") + tag(:br)
end
def daily_selected_class
return nil if params[:group_by].blank?
@@ -86,21 +74,6 @@ module ProposalsDashboardHelper
"hollow"
end
def resource_card_class(resource, proposal)
return "alert" unless resource.active_for?(proposal)
return "success" if resource.executed_for?(proposal)
"primary"
end
def resource_tooltip(resource, proposal)
return t("dashboard.resource.resource_locked") unless resource.active_for?(proposal)
return t("dashboard.resource.view_resource") if resource.executed_for?(proposal)
return t("dashboard.resource.resource_requested") if resource.requested_for?(proposal)
t("dashboard.resource.request_resource")
end
def proposed_action_description(proposed_action)
sanitize proposed_action.description.truncate(200)
end

View File

@@ -73,6 +73,6 @@ module ProposalsHelper
end
def show_recommended_proposals?
params[:selected].blank? && feature?("user.recommendations") && @recommended_proposals.present?
params[:selected].blank?
end
end

View File

@@ -7,17 +7,6 @@ module WelcomeHelper
"display: none;" if index.positive?
end
def recommended_path(recommended)
case recommended.class.name
when "Debate"
debate_path(recommended)
when "Proposal"
proposal_path(recommended)
else
"#"
end
end
def render_recommendation_image(recommended)
image_path = calculate_image_path(recommended)
image_tag(image_path) if image_path.present?

View File

@@ -1,16 +0,0 @@
<% if can?(:manage_mailing, proposal) %>
<div class="small-12 medium-6 large-3 column end">
<div class="resource-card" data-equalizer-watch="resources">
<h4><%= t("dashboard.menu.mailing") %></h4>
<p class="resource-description">
<%= Setting["proposals.email_short_title"] %>
</p>
<div class="small-12 column small-centered margin-top">
<%= link_to t("dashboard.resource.view_resource"),
new_proposal_dashboard_mailing_path(proposal.to_param),
class: "button expanded" %>
</div>
</div>
</div>
<% end %>

View File

@@ -1,16 +0,0 @@
<% if can?(:manage_polls, proposal) %>
<div class="small-12 medium-6 large-3 column end">
<div class="resource-card" data-equalizer-watch="resources">
<h4><%= t("dashboard.menu.polls") %></h4>
<p class="resource-description">
<%= Setting["proposals.poll_short_title"] %>
</p>
<div class="small-12 column small-centered margin-top">
<%= link_to t("dashboard.resource.view_resource"),
proposal_dashboard_polls_path(proposal.to_param),
class: "button expanded" %>
</div>
</div>
</div>
<% end %>

View File

@@ -1,16 +0,0 @@
<% if can?(:manage_poster, proposal) %>
<div class="small-12 medium-6 large-3 column end">
<div class="resource-card" data-equalizer-watch="resources">
<h4><%= t("dashboard.menu.poster") %></h4>
<p class="resource-description">
<%= Setting["proposals.poster_short_title"] %>
</p>
<div class="small-12 column small-centered margin-top">
<%= link_to t("dashboard.resource.view_resource"),
new_proposal_dashboard_poster_path(proposal.to_param),
class: "button expanded" %>
</div>
</div>
</div>
<% end %>

View File

@@ -1,31 +0,0 @@
<div id="<%= dom_id(resource) %>" class="small-12 medium-6 large-3 column end">
<div class="resource-card <%= resource_card_class(resource, proposal) %>"
data-equalizer-watch="resources"
title="<%= resource_tooltip(resource, proposal) %>">
<h4><%= resource.title %></h4>
<% if is_new_action_since_last_login?(resource, @new_actions_since_last_login) %>
<span class="label"><%= t("dashboard.progress.new_action") %></span>
<% end %>
<p class="resource-description">
<%= resource.short_description %>
</p>
<div class="small-12 column small-centered margin-top">
<% if resource.executed_for?(proposal) || (!resource.request_to_administrators && resource.active_for?(proposal)) %>
<%= link_to t("dashboard.resource.view_resource"),
new_request_proposal_dashboard_action_path(proposal, resource),
class: "button expanded" %>
<% elsif resource.requested_for?(proposal) %>
<strong><%= t("dashboard.resource.resource_requested") %></strong>
<% elsif resource.active_for?(proposal) %>
<%= link_to t("dashboard.resource.request_resource"),
new_request_proposal_dashboard_action_path(proposal, resource),
class: "button expanded" %>
<% else %>
<strong>
<%= resource_availability_label(resource) %>
</strong>
<% end %>
</div>
</div>
</div>

View File

@@ -1,10 +0,0 @@
<div id="available-resources-section">
<h3 class="title"><%= t("dashboard.resources.available_resources") %></h3>
<div data-equalizer="resources" data-equalize-on="medium">
<%= render "poll_resource" %>
<%= render "mailing_resource" %>
<%= render "poster_resource" %>
<%= render partial: "resource", collection: active_resources %>
</div>
</div>

View File

@@ -1,36 +0,0 @@
<div id="<%= dom_id(poll) %>" class="small-12 medium-6 large-4 column end">
<div class="poll-card" data-equalizer-watch="poll-cards">
<h4><%= link_to poll.title, proposal_poll_path(proposal, poll) %></h4>
<span class="small">
<%= l(poll.starts_at.to_date) %> - <%= l(poll.ends_at.to_date) %>
</span>
<p class="margin-top">
<strong><%= t("dashboard.polls.poll.responses", count: poll.answer_count) %></strong>
</p>
<div class="small-12 column small-centered margin-top">
<% if poll.starts_at.to_date >= Date.current %>
<%= link_to t("dashboard.polls.poll.edit_poll"),
edit_proposal_dashboard_poll_path(proposal, poll), class: "button hollow" %>
<% else %>
<%= link_to t("dashboard.polls.poll.view_results"),
results_proposal_poll_path(proposal, poll),
class: "button" %>
<% end %>
</div>
<%= form_for poll, remote: true,
data: { type: :json },
url: proposal_dashboard_poll_path(proposal, poll) do |f| %>
<%= f.check_box :results_enabled, class: "js-submit-on-change" %>
<% end %>
<p class="help-text"><%= t("dashboard.polls.poll.show_results_help") %></p>
<%= button_to t("dashboard.polls.poll.delete"),
proposal_dashboard_poll_path(proposal, poll),
method: :delete,
"data-confirm": t("dashboard.polls.poll.alert_notice"),
class: "delete" %>
</div>
</div>

View File

@@ -3,11 +3,7 @@
<div class="small-12 medium-9 column">
<%= Setting["proposals.poll_description"] %>
<% if @polls.any? %>
<div class="row expanded margin-top" data-equalizer="poll-cards" data-equalize-on="medium">
<%= render @polls %>
</div>
<% end %>
<%= render Dashboard::PollsComponent.new(@polls) %>
</div>
<div class="small-12 medium-3 column">

View File

@@ -38,4 +38,4 @@
<%= render "summary_recommended_actions" %>
<% end %>
<%= render "resources" %>
<%= render Dashboard::ResourcesComponent.new(proposal, @new_actions_since_last_login) %>

View File

@@ -18,11 +18,7 @@
<%= render "shared/section_header", i18n_namespace: "debates.index.section_header", image: "debates" %>
<% end %>
<% if feature?("user.recommendations") && @recommended_debates.present? %>
<%= render "shared/recommended_index", recommended: @recommended_debates,
disable_recommendations_path: recommendations_disable_debates_path,
namespace: "debates" %>
<% end %>
<%= render Shared::RecommendedIndexComponent.new(@recommended_debates, namespace: "debates") %>
<div class="row">
<div id="debates" class="debates-list small-12 medium-9 column">

View File

@@ -1,22 +1 @@
<% provide :title, @poll.name %>
<div class="polls-results-stats">
<%= render Polls::PollHeaderComponent.new(@poll) %>
<%= render "poll_subnav" %>
<div class="row margin" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-3 column sidebar" data-equalizer-watch>
<p><strong><%= t("polls.show.results.title") %></strong></p>
<ul class="menu vertical">
<%- @poll.questions.each do |question| %>
<li><%= link_to question.title, "##{question.title.parameterize}" %></li>
<% end %>
</ul>
</div>
<div class="small-12 medium-9 column" data-equalizer-watch>
<%= render Polls::Results::QuestionComponent.with_collection(@poll.questions) %>
</div>
</div>
</div>
<%= render Polls::ResultsComponent.new(@poll) %>

View File

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

View File

@@ -25,9 +25,7 @@
<% end %>
<% if show_recommended_proposals? %>
<%= render "shared/recommended_index", recommended: @recommended_proposals,
disable_recommendations_path: recommendations_disable_proposals_path,
namespace: "proposals" %>
<%= render Shared::RecommendedIndexComponent.new(@recommended_proposals, namespace: "proposals") %>
<% end %>
<div class="row">

View File

@@ -1,34 +0,0 @@
<div class="recommended-index">
<div class="row relative" data-equalizer data-equalizer-on="medium">
<div class="small-12 column">
<h2 class="show-for-sr"><%= t("shared.recommended_index.title") %></h2>
</div>
<div id="recommendations" data-toggler=".hide">
<%= button_to disable_recommendations_path, title: t("shared.recommended_index.hide"),
class: "hide-recommendations",
data: {
toggle: "recommendations",
confirm: t("#{namespace}.index.recommendations.disable")
},
method: :put do %>
<span class="icon-x"></span>
<span class="show-for-sr"><%= t("shared.recommended_index.hide") %></span>
<% end %>
<% recommended.each_with_index do |recommended, index| %>
<div class="small-12 medium-6 large-4 column end">
<div class="recommendation" data-equalizer-watch>
<h3><%= link_to recommended.title, recommended_path(recommended) %></h3>
</div>
</div>
<% end %>
<div class="small-12 column">
<%= link_to t("shared.recommended_index.see_more"),
current_path_with_query_params(order: "recommendations"),
class: "float-right-medium small" %>
</div>
</div>
</div>
</div>

View File

@@ -13,7 +13,7 @@
<div class="card">
<%= render_recommendation_image(recommended) %>
<div class="card-section">
<%= link_to recommended_path(recommended) do %>
<%= link_to polymorphic_path(recommended) do %>
<h4 class="truncate-horizontal-text"><%= recommended.title %></h4>
<% end %>
<%= wysiwyg(recommended.description) %>

View File

@@ -0,0 +1,51 @@
require "rails_helper"
describe Dashboard::PollComponent do
include Rails.application.routes.url_helpers
let(:proposal) { create(:proposal, :draft) }
before { sign_in(proposal.author) }
describe "Poll card content" do
describe "actions visibility" do
it "shows results link for current polls" do
current = create(:poll, related: proposal)
render_inline Dashboard::PollComponent.new(current)
expect(page).not_to have_link "Edit survey"
expect(page).to have_link "View results", href: results_proposal_poll_path(proposal, current)
end
it "shows results link for expired polls" do
expired = create(:poll, :expired, related: proposal)
render_inline Dashboard::PollComponent.new(expired)
expect(page).not_to have_link "Edit survey"
expect(page).to have_link "View results", href: results_proposal_poll_path(proposal, expired)
end
it "shows edit link for upcoming polls" do
upcoming = create(:poll, related: proposal, starts_at: 1.week.from_now)
render_inline Dashboard::PollComponent.new(upcoming)
expect(page).to have_link "Edit survey", href: edit_proposal_dashboard_poll_path(proposal, upcoming)
expect(page).not_to have_link "View results"
end
end
it "renders poll title and dates" do
expired = create(:poll, :expired, related: proposal)
render_inline Dashboard::PollComponent.new(expired)
expect(page).to have_content I18n.l(expired.starts_at.to_date)
expect(page).to have_content I18n.l(expired.ends_at.to_date)
expect(page).to have_link expired.title
expect(page).to have_link expired.title, href: proposal_poll_path(proposal, expired)
end
end
end

View File

@@ -0,0 +1,9 @@
require "rails_helper"
describe Dashboard::PollsComponent do
it "is not rendered when there aren't any polls" do
render_inline Dashboard::PollsComponent.new(Poll.none)
expect(page).not_to be_rendered
end
end

View File

@@ -0,0 +1,131 @@
require "rails_helper"
describe Dashboard::ResourcesComponent do
let(:proposal) { create(:proposal, :draft) }
before { sign_in(proposal.author) }
describe "Available resources section" do
let!(:available) { create(:dashboard_action, :resource, :active, title: "Available!") }
let(:requested) { create(:dashboard_action, :resource, :admin_request, :active, title: "Requested!") }
let(:executed_action) do
create(
:dashboard_executed_action,
action: requested,
proposal: proposal,
executed_at: Time.current
)
end
let(:solved) { create(:dashboard_action, :resource, :admin_request, :active, title: "Solved!") }
let(:executed_solved_action) do
create(
:dashboard_executed_action,
action: solved,
proposal: proposal,
executed_at: Time.current
)
end
let!(:unavailable) do
create(
:dashboard_action,
:resource,
:active,
required_supports: proposal.votes_for.size + 1_000,
title: "Unavailable!"
)
end
before do
create(:dashboard_administrator_task, :pending, source: executed_action)
create(:dashboard_administrator_task, :done, source: executed_solved_action)
end
it "shows available resources for proposal drafts" do
render_inline Dashboard::ResourcesComponent.new(proposal)
expect(page).to have_content "Polls"
expect(page).to have_content "E-mail"
expect(page).to have_content "Poster"
expect(page).to have_content available.title
expect(page).to have_content unavailable.title
expect(page).to have_content requested.title
expect(page).to have_content solved.title
page.find(".resource-card", text: "Available!") do |dashboard_action_available|
expect(dashboard_action_available).to have_link "See resource"
end
page.find(".resource-card", text: "Requested!") do |dashboard_action_requested|
expect(dashboard_action_requested).to have_content "Resource already requested"
end
page.find(".resource-card", text: "Unavailable!") do |dashboard_action_unavailable|
expect(dashboard_action_unavailable).to have_content "1.000 supports required"
end
page.find(".resource-card", text: "Solved!") do |dashboard_action_solved|
expect(dashboard_action_solved).to have_link "See resource"
end
end
it "shows available resources for published proposals" do
proposal.update!(published_at: Date.current)
render_inline Dashboard::ResourcesComponent.new(proposal)
expect(page).to have_content "Polls"
expect(page).to have_content "E-mail"
expect(page).to have_content "Poster"
expect(page).to have_content available.title
expect(page).to have_content unavailable.title
expect(page).to have_content requested.title
expect(page).to have_content solved.title
page.find(".resource-card", text: "Available!") do |dashboard_action_available|
expect(dashboard_action_available).to have_link "See resource"
end
page.find(".resource-card", text: "Requested!") do |dashboard_action_requested|
expect(dashboard_action_requested).to have_content "Resource already requested"
end
page.find(".resource-card", text: "Unavailable!") do |dashboard_action_unavailable|
expect(dashboard_action_unavailable).to have_content "1.000 supports required"
end
page.find(".resource-card", text: "Solved!") do |dashboard_action_solved|
expect(dashboard_action_solved).to have_link "See resource"
end
end
it "does not show resources with published_proposal: true" do
available.update!(published_proposal: true)
unavailable.update!(published_proposal: true)
render_inline Dashboard::ResourcesComponent.new(proposal)
expect(page).to have_content "Polls"
expect(page).to have_content "E-mail"
expect(page).to have_content "Poster"
expect(page).not_to have_content available.title
expect(page).not_to have_content unavailable.title
end
end
describe "Tags for new actions" do
it "displays tag 'new' only when resource is detected like new action" do
create(:dashboard_action, :resource, :active, title: "Old!")
new_resource = create(:dashboard_action, :resource, :active, title: "Recent!")
new_actions_since_last_login = [new_resource.id]
render_inline Dashboard::ResourcesComponent.new(proposal, new_actions_since_last_login)
page.find(".resource-card", text: "Recent!") do |dashboard_action_new_resource|
expect(dashboard_action_new_resource).to have_content "New"
end
page.find(".resource-card", text: "Old!") do |dashboard_action_old_resource|
expect(dashboard_action_old_resource).not_to have_content "New"
end
end
end
end

View File

@@ -0,0 +1,48 @@
require "rails_helper"
describe Polls::AccessStatusComponent do
it "asks anonymous users to sign in" do
render_inline Polls::AccessStatusComponent.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::AccessStatusComponent.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::AccessStatusComponent.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::AccessStatusComponent.new(poll)
expect(page).to have_css ".already-answer", count: 1
expect(page).to have_content "You already have participated in this poll"
end
it "is not rendered when users can vote" do
sign_in(create(:user, :level_two))
render_inline Polls::AccessStatusComponent.new(create(:poll))
expect(page).not_to be_rendered
end
end

View File

@@ -3,45 +3,6 @@ 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")

View File

@@ -138,116 +138,6 @@ describe "Proposal's dashboard" do
expect(page).not_to have_content(action.title)
end
scenario "Dashboard progress show available resources for proposal draft" do
available = create(:dashboard_action, :resource, :active)
requested = create(:dashboard_action, :resource, :admin_request, :active)
executed_action = create(:dashboard_executed_action, action: requested,
proposal: proposal,
executed_at: Time.current)
_task = create(:dashboard_administrator_task, :pending, source: executed_action)
solved = create(:dashboard_action, :resource, :admin_request, :active)
executed_solved_action = create(:dashboard_executed_action, action: solved,
proposal: proposal,
executed_at: Time.current)
_solved_task = create(:dashboard_administrator_task, :done, source: executed_solved_action)
unavailable = create(:dashboard_action, :resource, :active,
required_supports: proposal.votes_for.size + 1_000)
visit progress_proposal_dashboard_path(proposal)
within "div#available-resources-section" do
expect(page).to have_content("Polls")
expect(page).to have_content("E-mail")
expect(page).to have_content("Poster")
expect(page).to have_content(available.title)
expect(page).to have_content(unavailable.title)
expect(page).to have_content(requested.title)
expect(page).to have_content(solved.title)
within "div#dashboard_action_#{available.id}" do
expect(page).to have_link "See resource"
end
within "div#dashboard_action_#{requested.id}" do
expect(page).to have_content("Resource already requested")
end
within "div#dashboard_action_#{unavailable.id}" do
expect(page).to have_content("1.000 supports required")
end
within "div#dashboard_action_#{solved.id}" do
expect(page).to have_link("See resource")
end
end
end
scenario "Dashboard progress show available resources for published proposal" do
proposal.update!(published_at: Date.current)
available = create(:dashboard_action, :resource, :active)
requested = create(:dashboard_action, :resource, :admin_request, :active)
executed_action = create(:dashboard_executed_action, action: requested,
proposal: proposal,
executed_at: Time.current)
_task = create(:dashboard_administrator_task, :pending, source: executed_action)
solved = create(:dashboard_action, :resource, :admin_request, :active)
executed_solved_action = create(:dashboard_executed_action, action: solved,
proposal: proposal,
executed_at: Time.current)
_solved_task = create(:dashboard_administrator_task, :done, source: executed_solved_action)
unavailable = create(:dashboard_action, :resource, :active,
required_supports: proposal.votes_for.size + 1_000)
visit progress_proposal_dashboard_path(proposal)
within "div#available-resources-section" do
expect(page).to have_content("Polls")
expect(page).to have_content("E-mail")
expect(page).to have_content("Poster")
expect(page).to have_content(available.title)
expect(page).to have_content(unavailable.title)
expect(page).to have_content(requested.title)
expect(page).to have_content(solved.title)
within "div#dashboard_action_#{available.id}" do
expect(page).to have_link "See resource"
end
within "div#dashboard_action_#{requested.id}" do
expect(page).to have_content("Resource already requested")
end
within "div#dashboard_action_#{unavailable.id}" do
expect(page).to have_content("1.000 supports required")
end
within "div#dashboard_action_#{solved.id}" do
expect(page).to have_link("See resource")
end
end
end
scenario "Dashboard progress dont show resources with published_proposal: true" do
available = create(:dashboard_action, :resource, :active, published_proposal: true)
unavailable = create(:dashboard_action, :resource, :active,
required_supports: proposal.votes_for.size + 1_000,
published_proposal: true)
visit progress_proposal_dashboard_path(proposal)
within "div#available-resources-section" do
expect(page).to have_content("Polls")
expect(page).to have_content("E-mail")
expect(page).to have_content("Poster")
expect(page).not_to have_content(available.title)
expect(page).not_to have_content(unavailable.title)
end
end
scenario "Dashboard has a link to resources on main menu" do
feature = create(:dashboard_action, :resource, :active)
@@ -480,29 +370,6 @@ describe "Proposal's dashboard" do
describe "detect_new_actions_after_last_login" do
before { proposal.author.update!(current_sign_in_at: 1.day.ago) }
scenario "Display tag 'new' on resouce when it is new for author since last login" do
resource = create(:dashboard_action, :resource, :active, day_offset: 0,
published_proposal: false)
visit progress_proposal_dashboard_path(proposal)
within "#dashboard_action_#{resource.id}" do
expect(page).to have_content("New")
end
end
scenario "Not display tag 'new' on resouce when there is not new resources since last login" do
resource = create(:dashboard_action, :resource, :active, day_offset: 0,
published_proposal: false)
proposal.author.update!(current_sign_in_at: Date.current)
visit progress_proposal_dashboard_path(proposal)
within "#dashboard_action_#{resource.id}" do
expect(page).not_to have_content("New")
end
end
scenario "Display tag 'new' on proposed_action when it is new for author since last login" do
proposed_action = create(:dashboard_action, :proposed_action, :active, day_offset: 0,
published_proposal: false)

View File

@@ -123,26 +123,6 @@ describe "Polls" do
expect(page).to have_content("Edit poll")
end
scenario "Edit poll is not allowed for current polls" do
poll = create(:poll, related: proposal)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).not_to have_content("Edit survey")
end
end
scenario "Edit poll is not allowed for expired polls" do
poll = create(:poll, :expired, related: proposal)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).not_to have_content("Edit survey")
end
end
scenario "Edit poll should allow to remove questions" do
poll = create(:poll, related: proposal, starts_at: 1.week.from_now)
create(:poll_question, poll: poll)
@@ -224,36 +204,6 @@ describe "Polls" do
expect(page).to have_content(poll.name)
end
scenario "View results not available for upcoming polls" do
poll = create(:poll, related: proposal, starts_at: 1.week.from_now)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).not_to have_content("View results")
end
end
scenario "View results available for current polls" do
poll = create(:poll, related: proposal)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).to have_content("View results")
end
end
scenario "View results available for expired polls" do
poll = create(:poll, :expired, related: proposal)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).to have_content("View results")
end
end
scenario "View results redirects to results in public zone" do
poll = create(:poll, :expired, related: proposal)
@@ -276,18 +226,4 @@ describe "Polls" do
expect(find_field("Show results")).not_to be_checked
end
scenario "Poll card" do
poll = create(:poll, :expired, related: proposal)
visit proposal_dashboard_polls_path(proposal)
within "div#poll_#{poll.id}" do
expect(page).to have_content(I18n.l(poll.starts_at.to_date))
expect(page).to have_content(I18n.l(poll.ends_at.to_date))
expect(page).to have_link(poll.title)
expect(page).to have_link(poll.title, href: proposal_poll_path(proposal, poll))
expect(page).to have_link("View results", href: results_proposal_poll_path(proposal, poll))
end
end
end