Merge pull request #4374 from consul/budget_phases
Change budget phases design
This commit is contained in:
@@ -74,6 +74,8 @@ $input-height: $line-height * 2;
|
||||
|
||||
$icon-width: $line-height * 2;
|
||||
|
||||
$off-screen-left: -1000rem;
|
||||
|
||||
$sdg-icon-min-width: 40px;
|
||||
|
||||
$sdg-colors: (
|
||||
|
||||
@@ -212,6 +212,10 @@ $table-header: #ecf1f6;
|
||||
|
||||
table {
|
||||
|
||||
caption {
|
||||
@include element-invisible;
|
||||
}
|
||||
|
||||
thead {
|
||||
|
||||
&,
|
||||
@@ -1160,38 +1164,6 @@ table {
|
||||
}
|
||||
}
|
||||
|
||||
.budget-phase-enabled {
|
||||
font-weight: bold;
|
||||
padding-left: rem-calc(20);
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
|
||||
&.enabled::before,
|
||||
&.disabled::before {
|
||||
font-family: "icons";
|
||||
left: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&.enabled {
|
||||
color: $check;
|
||||
|
||||
&::before {
|
||||
color: $check;
|
||||
content: "\6c";
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: #000;
|
||||
|
||||
&::before {
|
||||
color: #000;
|
||||
content: "\76";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.columns-selector {
|
||||
|
||||
[class^="icon-"] {
|
||||
|
||||
25
app/assets/stylesheets/admin/budget_phases/form.scss
Normal file
25
app/assets/stylesheets/admin/budget_phases/form.scss
Normal file
@@ -0,0 +1,25 @@
|
||||
.admin .budget-phases-form {
|
||||
|
||||
fieldset {
|
||||
margin-top: $line-height;
|
||||
|
||||
> * {
|
||||
@include grid-column;
|
||||
}
|
||||
|
||||
> .date-field {
|
||||
|
||||
@include breakpoint(medium) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
app/assets/stylesheets/admin/budget_phases/phases.scss
Normal file
27
app/assets/stylesheets/admin/budget_phases/phases.scss
Normal file
@@ -0,0 +1,27 @@
|
||||
.budget-phases-table {
|
||||
|
||||
.budget-phase-enabled {
|
||||
@include has-fa-icon(check, solid);
|
||||
color: $check;
|
||||
}
|
||||
|
||||
.budget-phase-disabled {
|
||||
@include has-fa-icon(times, solid);
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.budget-phase-enabled,
|
||||
.budget-phase-disabled {
|
||||
display: block;
|
||||
font-size: 1px;
|
||||
left: $off-screen-left;
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
font-size: $base-font-size;
|
||||
left: -1 * $off-screen-left;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,10 @@
|
||||
clear: both;
|
||||
margin-top: $line-height * 1.5;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
color: $admin-text;
|
||||
font-size: $small-font-size;
|
||||
|
||||
@@ -21,4 +21,10 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
td time:last-of-type::after,
|
||||
td small::before {
|
||||
content: "";
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
> :first-child {
|
||||
@include bottom-tooltip;
|
||||
left: -10000px;
|
||||
left: $off-screen-left;
|
||||
opacity: 0;
|
||||
transform: translateX(-50%);
|
||||
transition: opacity 0.3s, left 0s 0.3s;
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
&:not(:focus) > :first-child:hover {
|
||||
left: -10000px;
|
||||
left: $off-screen-left;
|
||||
}
|
||||
|
||||
&::before {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
@import "sticky_overrides";
|
||||
@import "tags";
|
||||
@import "admin/**/*";
|
||||
@import "budgets/*";
|
||||
@import "sdg/**/*";
|
||||
@import "sdg_management/*";
|
||||
@import "sdg_management/**/*";
|
||||
|
||||
187
app/assets/stylesheets/budgets/phases.scss
Normal file
187
app/assets/stylesheets/budgets/phases.scss
Normal file
@@ -0,0 +1,187 @@
|
||||
.budget-phases {
|
||||
background: $light;
|
||||
border-top: 2px solid $border;
|
||||
padding-bottom: $line-height * 2;
|
||||
|
||||
> * {
|
||||
@include grid-column-gutter;
|
||||
@include grid-row;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $base-font-size;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.phases-list {
|
||||
counter-reset: phases;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.phase-name::before {
|
||||
content: counter(phases);
|
||||
counter-increment: phases;
|
||||
display: block;
|
||||
font-size: rem-calc(36);
|
||||
font-weight: bold;
|
||||
margin-bottom: $line-height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
.phase-title {
|
||||
@include tabs-title;
|
||||
margin: $line-height / 6;
|
||||
margin-left: 0;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
@supports(clip-path: polygon(0 0, 50% 50%, 0% 100%)) {
|
||||
$triangle-width: 1em;
|
||||
$item-margin: rem-calc(3);
|
||||
|
||||
margin-left: calc(-1 * (#{$triangle-width} - #{$item-margin}));
|
||||
margin-right: 0;
|
||||
transform: translateX(calc(#{$triangle-width} - #{$item-margin}));
|
||||
|
||||
&,
|
||||
a {
|
||||
clip-path: polygon(calc(100% - #{$triangle-width}) 0, 100% 50%, calc(100% - #{$triangle-width}) 100%, 0 100%, #{$triangle-width} 50%, 0 0);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
&,
|
||||
a {
|
||||
clip-path: polygon(calc(100% - #{$triangle-width}) 0, 100% 50%, calc(100% - #{$triangle-width}) 100%, 0 100%, 0 0);
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom-left-radius: rem-calc(6);
|
||||
border-top-left-radius: rem-calc(6);
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&,
|
||||
a {
|
||||
clip-path: polygon(100% 0, 100% 100%, 0 100%, #{$triangle-width} 50%, 0 0);
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom-right-radius: rem-calc(6);
|
||||
border-top-right-radius: rem-calc(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
background: $white;
|
||||
color: $black;
|
||||
height: 100%;
|
||||
padding: $line-height $line-height * 1.5;
|
||||
|
||||
&:hover {
|
||||
background: #e6e6e6;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&[aria-selected="true"],
|
||||
&.is-active {
|
||||
background: $dark;
|
||||
color: $white;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
&[aria-selected="true"]::after,
|
||||
&.is-active::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.current-phase-tab a {
|
||||
background: $brand;
|
||||
color: $white;
|
||||
padding-top: $line-height / 2;
|
||||
|
||||
&:hover {
|
||||
background: $dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.current-phase-timeline {
|
||||
display: block;
|
||||
font-size: $small-font-size;
|
||||
font-weight: bold;
|
||||
margin-bottom: $line-height / 2;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.tabs,
|
||||
.tabs-content {
|
||||
background: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.tabs-panel {
|
||||
padding: 0;
|
||||
|
||||
h3 {
|
||||
font-size: rem-calc(36);
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-controls {
|
||||
display: flex;
|
||||
|
||||
.budget-prev-phase,
|
||||
.budget-next-phase,
|
||||
.budget-prev-phase-disabled,
|
||||
.budget-next-phase-disabled {
|
||||
background: $brand;
|
||||
border-radius: rem-calc(3);
|
||||
color: $white;
|
||||
display: flex;
|
||||
font-size: rem-calc(36);
|
||||
height: 1em * 4 / 3;
|
||||
width: 1em * 4 / 3;
|
||||
|
||||
&::before {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
span {
|
||||
@include element-invisible;
|
||||
}
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.budget-prev-phase-disabled,
|
||||
.budget-next-phase-disabled {
|
||||
background: none;
|
||||
color: #acb6b6;
|
||||
}
|
||||
|
||||
.budget-prev-phase,
|
||||
.budget-prev-phase-disabled {
|
||||
@include has-fa-icon(angle-left, solid);
|
||||
}
|
||||
|
||||
.budget-next-phase,
|
||||
.budget-next-phase-disabled {
|
||||
@include has-fa-icon(angle-right, solid);
|
||||
}
|
||||
}
|
||||
|
||||
.budget-phase {
|
||||
@include breakpoint(medium) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
app/assets/stylesheets/budgets/subheader.scss
Normal file
17
app/assets/stylesheets/budgets/subheader.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
.budget-subheader {
|
||||
@include grid-row;
|
||||
margin-bottom: $line-height;
|
||||
margin-top: $line-height;
|
||||
|
||||
.current-phase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-top: $line-height / 2;
|
||||
}
|
||||
|
||||
.callout {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
@@ -2155,7 +2155,7 @@ table {
|
||||
}
|
||||
}
|
||||
|
||||
+ .budget.expanded,
|
||||
+ .budget-header,
|
||||
+ .jumbo {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -628,10 +628,16 @@
|
||||
}
|
||||
|
||||
&.past-budgets {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 0;
|
||||
|
||||
.button ~ .button {
|
||||
margin-left: $line-height / 2;
|
||||
> :not(:first-child) {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-left: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1130,51 +1136,37 @@
|
||||
// 06. Budgets
|
||||
// -----------
|
||||
|
||||
.expanded {
|
||||
.budget-header {
|
||||
background: $budget;
|
||||
margin-top: -$line-height;
|
||||
padding-bottom: $line-height;
|
||||
padding-top: $line-height;
|
||||
|
||||
&.budget {
|
||||
background: $budget;
|
||||
margin-top: -$line-height;
|
||||
h1,
|
||||
h2,
|
||||
p,
|
||||
a,
|
||||
.back,
|
||||
.icon-angle-left,
|
||||
.description {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
p,
|
||||
a,
|
||||
.back,
|
||||
.icon-angle-left,
|
||||
.description {
|
||||
color: #fff;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.confirmed {
|
||||
font-size: rem-calc(24);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.callout {
|
||||
.info {
|
||||
background: #6a2a72;
|
||||
|
||||
&.primary a {
|
||||
color: $link;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
background: #fff;
|
||||
color: $budget;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.confirmed {
|
||||
font-size: rem-calc(24);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #6a2a72;
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1226,6 +1218,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.current-phase {
|
||||
color: $brand;
|
||||
}
|
||||
|
||||
.groups-and-headings {
|
||||
|
||||
.heading {
|
||||
@@ -1467,63 +1463,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.budget-timeline {
|
||||
border-left: 3px solid $budget;
|
||||
margin-left: $line-height / 2;
|
||||
padding: $line-height $line-height / 2;
|
||||
|
||||
h3,
|
||||
span,
|
||||
p {
|
||||
padding: 0 $line-height / 4;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $text-medium;
|
||||
display: block;
|
||||
font-size: $small-font-size;
|
||||
margin-bottom: $line-height / 2;
|
||||
}
|
||||
|
||||
.phase {
|
||||
position: relative;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: $line-height * 1.5;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: #fff;
|
||||
border: 4px solid $budget;
|
||||
border-radius: 100%;
|
||||
content: "";
|
||||
height: 16px;
|
||||
left: -22px;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
width: 16px;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
|
||||
h3 {
|
||||
background: $budget;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: $budget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.budgets-stats {
|
||||
|
||||
.header {
|
||||
|
||||
40
app/components/admin/budget_phases/phases_component.html.erb
Normal file
40
app/components/admin/budget_phases/phases_component.html.erb
Normal file
@@ -0,0 +1,40 @@
|
||||
<% if phases.present? %>
|
||||
<table class="budget-phases-table table-for-mobile">
|
||||
<caption><%= t("admin.budgets.edit.phases_caption") %></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.budgets.edit.phase") %></th>
|
||||
<th><%= t("admin.budgets.edit.duration") %></th>
|
||||
<th class="text-center"><%= t("admin.budgets.edit.enabled") %></th>
|
||||
<th><%= t("admin.budgets.edit.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<% phases.each do |phase| %>
|
||||
<tr id="<%= dom_id(phase) %>" class="phase">
|
||||
<td>
|
||||
<%= phase.name %>
|
||||
<% if phase.current? %>
|
||||
<span class="label success"><strong><%= t("admin.budgets.edit.active") %></strong></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if phase.starts_at.present? || phase.ends_at.present? %>
|
||||
<%= dates(phase) %>
|
||||
<% else %>
|
||||
<em><%= t("admin.budgets.edit.blank_dates") %></em>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<%= enabled_text(phase) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::TableActionsComponent.new(phase,
|
||||
actions: [:edit],
|
||||
edit_text: t("admin.budgets.edit.edit_phase")
|
||||
) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<% end %>
|
||||
25
app/components/admin/budget_phases/phases_component.rb
Normal file
25
app/components/admin/budget_phases/phases_component.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class Admin::BudgetPhases::PhasesComponent < ApplicationComponent
|
||||
attr_reader :budget
|
||||
|
||||
def initialize(budget)
|
||||
@budget = budget
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def phases
|
||||
budget.phases.order(:id)
|
||||
end
|
||||
|
||||
def dates(phase)
|
||||
Admin::Budgets::DurationComponent.new(phase).dates
|
||||
end
|
||||
|
||||
def enabled_text(phase)
|
||||
if phase.enabled?
|
||||
tag.span t("shared.yes"), class: "budget-phase-enabled"
|
||||
else
|
||||
tag.span t("shared.no"), class: "budget-phase-disabled"
|
||||
end
|
||||
end
|
||||
end
|
||||
29
app/components/admin/budgets/duration_component.rb
Normal file
29
app/components/admin/budgets/duration_component.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
class Admin::Budgets::DurationComponent < ApplicationComponent
|
||||
attr_reader :durable
|
||||
|
||||
def initialize(durable)
|
||||
@durable = durable
|
||||
end
|
||||
|
||||
def dates
|
||||
safe_join([formatted_start_date, "-", formatted_end_date], " ")
|
||||
end
|
||||
|
||||
def duration
|
||||
distance_of_time_in_words(durable.starts_at, durable.ends_at)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def formatted_start_date
|
||||
formatted_date(durable.starts_at) if durable.starts_at.present?
|
||||
end
|
||||
|
||||
def formatted_end_date
|
||||
formatted_date(durable.ends_at - 1.second) if durable.ends_at.present?
|
||||
end
|
||||
|
||||
def formatted_date(time)
|
||||
time_tag(time, format: :datetime)
|
||||
end
|
||||
end
|
||||
52
app/components/admin/budgets/index_component.html.erb
Normal file
52
app/components/admin/budgets/index_component.html.erb
Normal file
@@ -0,0 +1,52 @@
|
||||
<%= header do %>
|
||||
<%= link_to t("admin.budgets.index.new_link"), new_admin_budget_path %>
|
||||
<% end %>
|
||||
|
||||
<%= render Admin::Budgets::HelpComponent.new("budgets") %>
|
||||
<%= render "shared/filter_subnav", i18n_namespace: "admin.budgets.index" %>
|
||||
|
||||
<% if budgets.any? %>
|
||||
<h3><%= page_entries_info budgets %></h3>
|
||||
|
||||
<table class="budgets-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.budgets.index.table_name") %></th>
|
||||
<th><%= t("admin.budgets.index.table_phase") %></th>
|
||||
<th><%= t("admin.budgets.index.table_duration") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% budgets.each do |budget| %>
|
||||
<tr id="<%= dom_id(budget) %>" class="budget">
|
||||
<td class="<%= "budget-completed" if budget.finished? %>">
|
||||
<% if budget.finished? %>
|
||||
<span>
|
||||
<%= t("admin.budgets.index.table_completed") %>
|
||||
</span>
|
||||
<% end %>
|
||||
<strong><%= budget.name %></strong>
|
||||
</td>
|
||||
<td>
|
||||
<%= budget.current_phase.name %>
|
||||
<small><%= phase_progress_text(budget) %></small>
|
||||
</td>
|
||||
<td>
|
||||
<%= dates(budget) %>
|
||||
<%= duration(budget) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::Budgets::TableActionsComponent.new(budget) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate budgets %>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("admin.budgets.index.no_budgets") %>
|
||||
</div>
|
||||
<% end %>
|
||||
32
app/components/admin/budgets/index_component.rb
Normal file
32
app/components/admin/budgets/index_component.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
class Admin::Budgets::IndexComponent < ApplicationComponent
|
||||
include Header
|
||||
attr_reader :budgets
|
||||
|
||||
def initialize(budgets)
|
||||
@budgets = budgets
|
||||
end
|
||||
|
||||
def title
|
||||
t("admin.budgets.index.title")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def phase_progress_text(budget)
|
||||
t("admin.budgets.index.table_phase_progress",
|
||||
current_phase_number: current_enabled_phase_number(budget),
|
||||
total_phases: budget.phases.enabled.count)
|
||||
end
|
||||
|
||||
def current_enabled_phase_number(budget)
|
||||
budget.phases.enabled.order(:id).pluck(:kind).index(budget.phase) + 1
|
||||
end
|
||||
|
||||
def dates(budget)
|
||||
Admin::Budgets::DurationComponent.new(budget).dates
|
||||
end
|
||||
|
||||
def duration(budget)
|
||||
Admin::Budgets::DurationComponent.new(budget).duration
|
||||
end
|
||||
end
|
||||
53
app/components/budgets/phases_component.html.erb
Normal file
53
app/components/budgets/phases_component.html.erb
Normal file
@@ -0,0 +1,53 @@
|
||||
<section class="budget-phases">
|
||||
<header>
|
||||
<h2><%= t("budgets.index.all_phases") %></h2>
|
||||
</header>
|
||||
|
||||
<ul class="phases-list tabs" data-tabs id="budget_phases_tabs" data-deep-link="true">
|
||||
<% phases.each do |phase| %>
|
||||
<li class="phase-title tabs-title <%= "is-active current-phase-tab" if phase.current? %>">
|
||||
<a href="#<%= phase_dom_id(phase) %>">
|
||||
<% if phase.current? %>
|
||||
<span class="current-phase-timeline"><%= t("budgets.index.current_phase") %></span>
|
||||
<% end %>
|
||||
|
||||
<span class="phase-name"><%= phase.name %></span>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="budget_phases_tabs">
|
||||
<% phases.each do |phase| %>
|
||||
<div id="<%= phase_dom_id(phase) %>" class="tabs-panel <%= "is-active" if phase.current? %>">
|
||||
<div class="tabs-controls">
|
||||
<% if phase == phases.first %>
|
||||
<span class="budget-prev-phase-disabled"></span>
|
||||
<% else %>
|
||||
<a href="#<%= prev_phase_dom_id(phase) %>" title="<%= t("budgets.index.prev_phase") %>"
|
||||
data-turbolinks="false"
|
||||
class="budget-prev-phase">
|
||||
<span><%= t("budgets.index.prev_phase") %></span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if phase == phases.last %>
|
||||
<span class="budget-next-phase-disabled"></span>
|
||||
<% else %>
|
||||
<a href="#<%= next_phase_dom_id(phase) %>" title="<%= t("budgets.index.next_phase") %>"
|
||||
data-turbolinks="false"
|
||||
class="budget-next-phase">
|
||||
<span><%= t("budgets.index.next_phase") %></span>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="budget-phase">
|
||||
<h3><%= phase.name %></h3>
|
||||
<p><%= start_date(phase) %> - <%= end_date(phase) %></p>
|
||||
<%= auto_link_already_sanitized_html(wysiwyg(phase.description)) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
34
app/components/budgets/phases_component.rb
Normal file
34
app/components/budgets/phases_component.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
class Budgets::PhasesComponent < ApplicationComponent
|
||||
delegate :wysiwyg, :auto_link_already_sanitized_html, to: :helpers
|
||||
attr_reader :budget
|
||||
|
||||
def initialize(budget)
|
||||
@budget = budget
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def phases
|
||||
budget.published_phases
|
||||
end
|
||||
|
||||
def start_date(phase)
|
||||
time_tag(phase.starts_at.to_date, format: :long) if phase.starts_at.present?
|
||||
end
|
||||
|
||||
def end_date(phase)
|
||||
time_tag(phase.ends_at.to_date - 1.day, format: :long) if phase.ends_at.present?
|
||||
end
|
||||
|
||||
def phase_dom_id(phase)
|
||||
"#{phases.index(phase) + 1}-#{phase.name.parameterize}"
|
||||
end
|
||||
|
||||
def prev_phase_dom_id(phase)
|
||||
phase_dom_id(phases[phases.index(phase) - 1])
|
||||
end
|
||||
|
||||
def next_phase_dom_id(phase)
|
||||
phase_dom_id(phases[phases.index(phase) + 1])
|
||||
end
|
||||
end
|
||||
38
app/components/budgets/subheader_component.html.erb
Normal file
38
app/components/budgets/subheader_component.html.erb
Normal file
@@ -0,0 +1,38 @@
|
||||
<div class="budget-subheader">
|
||||
<div class="small-12 medium-8 column info">
|
||||
<span class="current-phase"><strong><%= t("budgets.index.current_phase") %></strong></span>
|
||||
<h2><%= budget.current_phase.name %></h2>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<% if budget.accepting? %>
|
||||
<% if current_user %>
|
||||
<% if current_user.level_two_or_three_verified? %>
|
||||
<div class="text-right">
|
||||
<%= link_to t("budgets.investments.index.sidebar.create"),
|
||||
new_budget_investment_path(budget),
|
||||
class: "button" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="callout warning">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.verified_only",
|
||||
verify: link_to_verify_account)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.not_logged_in",
|
||||
sign_in: link_to_signin, sign_up: link_to_signup)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if can?(:read_results, budget) %>
|
||||
<div class="text-right">
|
||||
<%= link_to t("budgets.show.see_results"),
|
||||
budget_results_path(budget, heading_id: budget.headings.first),
|
||||
class: "button expanded" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
8
app/components/budgets/subheader_component.rb
Normal file
8
app/components/budgets/subheader_component.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class Budgets::SubheaderComponent < ApplicationComponent
|
||||
delegate :current_user, :link_to_signin, :link_to_signup, :link_to_verify_account, :can?, to: :helpers
|
||||
attr_reader :budget
|
||||
|
||||
def initialize(budget)
|
||||
@budget = budget
|
||||
end
|
||||
end
|
||||
@@ -71,6 +71,14 @@ class Budget < ApplicationRecord
|
||||
phases.published.order(:id)
|
||||
end
|
||||
|
||||
def starts_at
|
||||
phases.published.first.starts_at
|
||||
end
|
||||
|
||||
def ends_at
|
||||
phases.published.last.ends_at
|
||||
end
|
||||
|
||||
def description
|
||||
description_for_phase(phase)
|
||||
end
|
||||
@@ -155,10 +163,6 @@ class Budget < ApplicationRecord
|
||||
heading_ids.include?(heading.id) ? heading.price : -1
|
||||
end
|
||||
|
||||
def translated_phase
|
||||
I18n.t "budgets.phase.#{phase}"
|
||||
end
|
||||
|
||||
def formatted_amount(amount)
|
||||
ActionController::Base.helpers.number_to_currency(amount,
|
||||
precision: 0,
|
||||
@@ -214,6 +218,7 @@ class Budget < ApplicationRecord
|
||||
Budget::Phase.create(
|
||||
budget: self,
|
||||
kind: phase,
|
||||
name: I18n.t("budgets.phase.#{phase}"),
|
||||
prev_phase: phases&.last,
|
||||
starts_at: phases&.last&.ends_at || Date.current,
|
||||
ends_at: (phases&.last&.ends_at || Date.current) + 1.month
|
||||
|
||||
@@ -3,9 +3,9 @@ class Budget
|
||||
PHASE_KINDS = %w[informing accepting reviewing selecting valuating publishing_prices balloting
|
||||
reviewing_ballots finished].freeze
|
||||
PUBLISHED_PRICES_PHASES = %w[publishing_prices balloting reviewing_ballots finished].freeze
|
||||
SUMMARY_MAX_LENGTH = 1000
|
||||
DESCRIPTION_MAX_LENGTH = 2000
|
||||
|
||||
translates :name, touch: true
|
||||
translates :summary, touch: true
|
||||
translates :description, touch: true
|
||||
include Globalizable
|
||||
@@ -15,7 +15,7 @@ class Budget
|
||||
belongs_to :next_phase, class_name: self.name, inverse_of: :prev_phase
|
||||
has_one :prev_phase, class_name: self.name, foreign_key: :next_phase_id, inverse_of: :next_phase
|
||||
|
||||
validates_translation :summary, length: { maximum: SUMMARY_MAX_LENGTH }
|
||||
validates_translation :name, presence: true
|
||||
validates_translation :description, length: { maximum: DESCRIPTION_MAX_LENGTH }
|
||||
validates :budget, presence: true
|
||||
validates :kind, presence: true, uniqueness: { scope: :budget }, inclusion: { in: ->(*) { PHASE_KINDS }}
|
||||
@@ -62,6 +62,10 @@ class Budget
|
||||
in_phase_or_later?("balloting")
|
||||
end
|
||||
|
||||
def current?
|
||||
budget.current_phase == self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def adjust_date_ranges
|
||||
@@ -77,7 +81,7 @@ class Budget
|
||||
if enabled? && starts_at.present? && prev_enabled_phase.present?
|
||||
prev_enabled_phase.assign_attributes(ends_at: starts_at)
|
||||
if prev_enabled_phase.invalid_dates_range?
|
||||
phase_name = I18n.t("budgets.phase.#{prev_enabled_phase.kind}")
|
||||
phase_name = prev_enabled_phase.name
|
||||
error = I18n.t("budgets.phases.errors.prev_phase_dates_invalid", phase_name: phase_name)
|
||||
errors.add(:starts_at, error)
|
||||
end
|
||||
@@ -88,7 +92,7 @@ class Budget
|
||||
if enabled? && ends_at.present? && next_enabled_phase.present?
|
||||
next_enabled_phase.assign_attributes(starts_at: ends_at)
|
||||
if next_enabled_phase.invalid_dates_range?
|
||||
phase_name = I18n.t("budgets.phase.#{next_enabled_phase.kind}")
|
||||
phase_name = next_enabled_phase.name
|
||||
error = I18n.t("budgets.phases.errors.next_phase_dates_invalid", phase_name: phase_name)
|
||||
errors.add(:ends_at, error)
|
||||
end
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
<%= render "shared/globalize_locales", resource: @phase %>
|
||||
|
||||
<%= translatable_form_for [:admin, @phase.budget, @phase] do |f| %>
|
||||
<%= translatable_form_for [:admin, @phase.budget, @phase], html: { class: "budget-phases-form" } do |f| %>
|
||||
|
||||
<%= render "shared/errors", resource: @phase %>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<fieldset>
|
||||
<legend aria-describedby="phase_duration_description">
|
||||
<%= t("admin.budget_phases.edit.duration") %>
|
||||
</legend>
|
||||
|
||||
<p class="help-text" id="phase_duration_description">
|
||||
<%= t("admin.budget_phases.edit.duration_description") %>
|
||||
</p>
|
||||
|
||||
<div class="date-field">
|
||||
<%= f.date_field :starts_at, id: "start_date" %>
|
||||
</div>
|
||||
<div class="small-12 medium-6 column">
|
||||
|
||||
<div class="date-field">
|
||||
<%= f.date_field :ends_at, id: "end_date" %>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="small-12 column margin">
|
||||
<%= f.check_box :enabled %>
|
||||
|
||||
<span class="help-text" id="phase-summary-help-text">
|
||||
<%= t("admin.budget_phases.edit.enabled_help_text") %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.translatable_fields do |translations_form| %>
|
||||
<div class="small-12 column">
|
||||
<%= translations_form.text_area :description,
|
||||
maxlength: Budget::Phase::DESCRIPTION_MAX_LENGTH,
|
||||
class: "html-area",
|
||||
hint: t("admin.budget_phases.edit.description_help_text") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= translations_form.text_area :summary,
|
||||
maxlength: Budget::Phase::SUMMARY_MAX_LENGTH,
|
||||
class: "html-area",
|
||||
hint: t("admin.budget_phases.edit.summary_help_text") %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 column margin-top">
|
||||
<%= f.check_box :enabled %>
|
||||
|
||||
<span class="help-text" id="phase-summary-help-text">
|
||||
<%= t("admin.budget_phases.edit.enabled_help_text") %>
|
||||
</span>
|
||||
<%= f.translatable_fields do |translations_form| %>
|
||||
<div class="small-12 column">
|
||||
<%= translations_form.text_field :name, hint: t("admin.budget_phases.edit.name_help_text") %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-4 large-3 column end margin-top">
|
||||
<%= f.submit t("admin.budget_phases.edit.save_changes"), class: "button success expanded" %>
|
||||
<div class="small-12 column">
|
||||
<%= translations_form.text_area :description,
|
||||
maxlength: Budget::Phase::DESCRIPTION_MAX_LENGTH,
|
||||
class: "html-area",
|
||||
hint: t("admin.budget_phases.edit.description_help_text") %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.submit t("admin.budget_phases.edit.save_changes"), class: "button success" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<%= back_link_to edit_admin_budget_path(@phase.budget) %>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<h2><%= t("admin.budgets.edit.title") %> - <%= t("budgets.phase.#{@phase.kind}") %></h2>
|
||||
</div>
|
||||
</div>
|
||||
<h2><%= t("admin.budgets.edit.title") %> - <%= @phase.name %></h2>
|
||||
|
||||
<%= render "/admin/budget_phases/form" %>
|
||||
|
||||
@@ -44,48 +44,7 @@
|
||||
</div>
|
||||
|
||||
<%= render Admin::Budgets::HelpComponent.new("budget_phases") %>
|
||||
|
||||
<% if @budget.phases.present? %>
|
||||
<table id="budget-phases-table" class="table-for-mobile">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.budgets.edit.phase") %></th>
|
||||
<th><%= t("admin.budgets.edit.dates") %></th>
|
||||
<th class="text-center"><%= t("admin.budgets.edit.enabled") %></th>
|
||||
<th><%= t("admin.budgets.edit.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<% @budget.phases.order(:id).each do |phase| %>
|
||||
<tr id="<%= dom_id(phase) %>" class="phase">
|
||||
<td>
|
||||
<%= t("budgets.phase.#{phase.kind}") %>
|
||||
<% if @budget.current_phase == phase %>
|
||||
<span class="label success"><strong><%= t("admin.budgets.edit.active") %></strong></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if phase.starts_at.present? || phase.ends_at.present? %>
|
||||
<%= l(phase.starts_at.to_date) if phase.starts_at.present? %>
|
||||
-
|
||||
<%= l(phase.ends_at.to_date) if phase.ends_at.present? %>
|
||||
<% else %>
|
||||
<em><%= t("admin.budgets.edit.blank_dates") %></em>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="budget-phase-enabled <%= phase.enabled? ? "enabled" : "disabled" %>"></span>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::TableActionsComponent.new(phase,
|
||||
actions: [:edit],
|
||||
edit_text: t("admin.budgets.edit.edit_phase")
|
||||
) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<% end %>
|
||||
<%= render Admin::BudgetPhases::PhasesComponent.new(@budget) %>
|
||||
</fieldset>
|
||||
|
||||
<% if @budget.persisted? %>
|
||||
|
||||
@@ -1,47 +1 @@
|
||||
<header>
|
||||
<h2><%= t("admin.budgets.index.title") %></h2>
|
||||
<%= link_to t("admin.budgets.index.new_link"), new_admin_budget_path %>
|
||||
</header>
|
||||
|
||||
<%= render Admin::Budgets::HelpComponent.new("budgets") %>
|
||||
<%= render "shared/filter_subnav", i18n_namespace: "admin.budgets.index" %>
|
||||
|
||||
<% if @budgets.any? %>
|
||||
<h3><%= page_entries_info @budgets %></h3>
|
||||
|
||||
<table class="budgets-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.budgets.index.table_name") %></th>
|
||||
<th><%= t("admin.budgets.index.table_phase") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @budgets.each do |budget| %>
|
||||
<tr id="<%= dom_id(budget) %>" class="budget">
|
||||
<td class="<%= "budget-completed" if budget.finished? %>">
|
||||
<% if budget.finished? %>
|
||||
<span>
|
||||
<%= t("admin.budgets.index.table_completed") %>
|
||||
</span>
|
||||
<% end %>
|
||||
<strong><%= budget.name %></strong>
|
||||
</td>
|
||||
<td class="small">
|
||||
<%= t("budgets.phase.#{budget.phase}") %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::Budgets::TableActionsComponent.new(budget) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @budgets %>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("admin.budgets.index.no_budgets") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render Admin::Budgets::IndexComponent.new(@budgets) %>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<h2><%= t("admin.budgets.new.title") %></h2>
|
||||
<%= back_link_to admin_budgets_path %>
|
||||
|
||||
<header>
|
||||
<h2><%= t("admin.budgets.new.title") %></h2>
|
||||
</header>
|
||||
|
||||
<%= render "/admin/budgets/form" %>
|
||||
|
||||
@@ -1,31 +1,19 @@
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 medium-9 column">
|
||||
<div class="small-12 column">
|
||||
<h2><%= t("budgets.index.finished_budgets") %></h2>
|
||||
|
||||
<div id="finished_budgets" class="budget-investments-list">
|
||||
<div id="finished_budgets">
|
||||
<% budgets.each do |budget| %>
|
||||
<div class="budget-investment clear">
|
||||
<div class="panel past-budgets">
|
||||
<div class="row" data-equalizer data-equalizer-on="medium">
|
||||
<div class="small-12 medium-6 column table" data-equalizer-watch>
|
||||
<div class="table-cell align-middle">
|
||||
<h3><%= budget.name %></h3>
|
||||
</div>
|
||||
</div>
|
||||
<h3><%= budget.name %></h3>
|
||||
|
||||
<div class="small-12 medium-6 column table" data-equalizer-watch>
|
||||
<div id="budget_<%= budget.id %>_results" class="table-cell align-middle">
|
||||
<% if can?(:read_results, budget) %>
|
||||
<%= link_to t("budgets.index.see_results"),
|
||||
budget_results_path(budget),
|
||||
class: "button" %>
|
||||
<% end %>
|
||||
<div id="budget_<%= budget.id %>_results">
|
||||
<% if can?(:read_results, budget) %>
|
||||
<%= link_to t("budgets.index.see_results"), budget_results_path(budget), class: "button" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t("budgets.index.milestones"),
|
||||
budget_executions_path(budget),
|
||||
class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
<%= link_to t("budgets.index.milestones"), budget_executions_path(budget), class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<ul class="no-bullet budget-timeline">
|
||||
<% current_budget.published_phases.each do |phase| %>
|
||||
<li class="phase <%= "is-active" if phase == current_budget.current_phase %>">
|
||||
<h3><%= t("budgets.phase.#{phase.kind}") %></h3>
|
||||
<span>
|
||||
<%= l(phase.starts_at.to_date, format: :long) if phase.starts_at.present? %>
|
||||
-
|
||||
<%= l(phase.ends_at.to_date - 1.day, format: :long) if phase.ends_at.present? %>
|
||||
</span>
|
||||
<p><%= auto_link_already_sanitized_html(wysiwyg(phase.summary)) %></p>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="expanded budget no-margin-top padding">
|
||||
<div class="budget-header">
|
||||
<div class="row">
|
||||
<%= back_link_to @ballot_referer %>
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<%= render "shared/canonical", href: budget_group_url(filter: @current_filter) %>
|
||||
<% end %>
|
||||
|
||||
<div class="expanded budget no-margin-top">
|
||||
<div class="budget-header">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column padding">
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= back_link_to budgets_path %>
|
||||
<h2><%= t("budgets.groups.show.title") %></h2>
|
||||
</div>
|
||||
|
||||
@@ -7,55 +7,23 @@
|
||||
<% end %>
|
||||
|
||||
<% if current_budget.present? %>
|
||||
<div id="budget_heading" class="expanded budget">
|
||||
<div class="row" data-equalizer data-equalizer-on="medium">
|
||||
<div class="small-12 medium-9 column padding" data-equalizer-watch>
|
||||
|
||||
<h1><%= current_budget.name %></h1>
|
||||
<div class="description">
|
||||
<%= auto_link_already_sanitized_html wysiwyg(current_budget.description) %>
|
||||
</div>
|
||||
<p>
|
||||
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
|
||||
</p>
|
||||
<div class="budget-header">
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<h1><%= current_budget.name %></h1>
|
||||
<div class="description">
|
||||
<%= auto_link_already_sanitized_html wysiwyg(current_budget.description) %>
|
||||
</div>
|
||||
<div class="small-12 medium-3 column info padding" data-equalizer-watch>
|
||||
<p>
|
||||
<strong><%= t("budgets.show.phase") %></strong>
|
||||
</p>
|
||||
<h2><%= t("budgets.phase.#{current_budget.phase}") %></h2>
|
||||
|
||||
<%= link_to t("budgets.index.section_header.all_phases"), "#all_phases" %>
|
||||
|
||||
<% if current_budget.accepting? %>
|
||||
<% if current_user %>
|
||||
<% if current_user.level_two_or_three_verified? %>
|
||||
<%= link_to t("budgets.investments.index.sidebar.create"),
|
||||
new_budget_investment_path(current_budget),
|
||||
class: "button margin-top expanded" %>
|
||||
<% else %>
|
||||
<div class="callout warning margin-top">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.verified_only",
|
||||
verify: link_to_verify_account)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.not_logged_in",
|
||||
sign_in: link_to_signin, sign_up: link_to_signup)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if can?(:read_results, current_budget) %>
|
||||
<%= link_to t("budgets.show.see_results"),
|
||||
budget_results_path(current_budget, heading_id: current_budget.headings.first),
|
||||
class: "button margin-top expanded" %>
|
||||
<% end %>
|
||||
<p>
|
||||
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render Budgets::SubheaderComponent.new(current_budget) %>
|
||||
<%= render Budgets::PhasesComponent.new(current_budget) %>
|
||||
|
||||
<div id="budget_info" class="budget-info">
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 column">
|
||||
@@ -111,11 +79,6 @@
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
<div id="all_phases">
|
||||
<h2><%= t("budgets.index.all_phases") %></h2>
|
||||
<%= render "phases", budget: current_budget %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,9 +87,9 @@
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="expanded budget no-margin-top margin-bottom">
|
||||
<div class="budget-header margin-bottom">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column padding">
|
||||
<div class="small-12 medium-9 column">
|
||||
<h1><%= t("budgets.index.title") %></h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,48 +2,20 @@
|
||||
<%= render "shared/canonical", href: budget_url(@budget, filter: @current_filter) %>
|
||||
<% end %>
|
||||
|
||||
<div class="expanded budget no-margin-top">
|
||||
<div class="row" data-equalizer data-equalizer-on="medium">
|
||||
<div class="small-12 medium-9 column padding" data-equalizer-watch>
|
||||
<div class="budget-header">
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<%= back_link_to budgets_path %>
|
||||
|
||||
<h1><%= @budget.name %></h1>
|
||||
|
||||
<%= auto_link_already_sanitized_html wysiwyg(@budget.description) %>
|
||||
</div>
|
||||
<div class="small-12 medium-3 column info padding" data-equalizer-watch>
|
||||
<p>
|
||||
<strong><%= t("budgets.show.phase") %></strong>
|
||||
</p>
|
||||
<h2><%= t("budgets.phase.#{@budget.phase}") %></h2>
|
||||
|
||||
<% if @budget.accepting? %>
|
||||
<% if current_user %>
|
||||
<% if current_user.level_two_or_three_verified? %>
|
||||
<%= link_to t("budgets.investments.index.sidebar.create"), new_budget_investment_path(@budget), class: "button margin-top expanded" %>
|
||||
<% else %>
|
||||
<div class="callout warning margin-top">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.verified_only",
|
||||
verify: link_to_verify_account)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= sanitize(t("budgets.investments.index.sidebar.not_logged_in",
|
||||
sign_in: link_to_signin, sign_up: link_to_signup)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if can?(:read_results, @budget) %>
|
||||
<%= link_to t("budgets.show.see_results"),
|
||||
budget_results_path(@budget),
|
||||
class: "button margin-top expanded" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render Budgets::SubheaderComponent.new(@budget) %>
|
||||
|
||||
<div class="row margin">
|
||||
<div class="small-12 medium-9 column">
|
||||
<% if @current_filter == "unfeasible" %>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<% @budgets.each do |budget| %>
|
||||
<tr id="<%= dom_id(budget) %>">
|
||||
<td><%= budget.name %></td>
|
||||
<td><%= budget.translated_phase %></td>
|
||||
<td><%= budget.current_phase.name %></td>
|
||||
<td align="right">
|
||||
<%= link_to t("management.budgets.create_new_investment"),
|
||||
new_management_budget_investment_path(budget),
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<tbody>
|
||||
<tr id="<%= dom_id(@budget) %>">
|
||||
<td><%= @budget.name %></td>
|
||||
<td><%= @budget.translated_phase %></td>
|
||||
<td><%= @budget.current_phase.name %></td>
|
||||
<td align="right">
|
||||
<%= link_to t("management.budgets.print_investments"),
|
||||
print_management_budget_investments_path(@budget) %>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<% @budgets.each do |budget| %>
|
||||
<tr id="<%= dom_id(budget) %>">
|
||||
<td><%= budget.name %></td>
|
||||
<td><%= budget.translated_phase %></td>
|
||||
<td><%= budget.current_phase.name %></td>
|
||||
<td align="right">
|
||||
<%= link_to t("management.budgets.support_investments"),
|
||||
management_budget_investments_path(budget),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<%= @budget.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= t("budgets.phase.#{@budget.phase}") %>
|
||||
<%= @budget.current_phase.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= @investments.count %>
|
||||
|
||||
@@ -230,6 +230,7 @@ en:
|
||||
ends_at: "End date"
|
||||
starts_at: "Start date"
|
||||
budget/phase/translation:
|
||||
name: "Name"
|
||||
description: "Description"
|
||||
summary: "Summary"
|
||||
comment:
|
||||
|
||||
@@ -76,8 +76,10 @@ en:
|
||||
help: "Participatory budgets allow citizens to propose and decide directly how to spend part of the budget, with monitoring and rigorous evaluation of proposals by the institution."
|
||||
budget_investments: Manage projects
|
||||
table_completed: Completed
|
||||
table_duration: "Duration"
|
||||
table_name: Name
|
||||
table_phase: Phase
|
||||
table_phase_progress: "(%{current_phase_number}/%{total_phases})"
|
||||
edit_groups: Edit headings groups
|
||||
edit_budget: Edit budget
|
||||
admin_ballots: Admin ballots
|
||||
@@ -94,7 +96,8 @@ en:
|
||||
publish: "Publish budget"
|
||||
delete: Delete budget
|
||||
phase: Phase
|
||||
dates: Dates
|
||||
phases_caption: "Phases"
|
||||
duration: "Duration"
|
||||
enabled: Enabled
|
||||
actions: Actions
|
||||
edit_phase: Edit phase
|
||||
@@ -173,9 +176,11 @@ en:
|
||||
help: "Headings are meant to divide the money of the participatory budget. Here you can add headings for this group and assign the amount of money that will be used for each heading."
|
||||
budget_phases:
|
||||
edit:
|
||||
summary_help_text: This text will inform the user about the phase. To show it even if the phase is not active, select the checkbox below
|
||||
description_help_text: This text will appear in the header when the phase is active
|
||||
duration: "Phase's duration"
|
||||
duration_description: "The period of time this phase will be active."
|
||||
enabled_help_text: This phase will be public in the budget's phases timeline, as well as active for any other purpose
|
||||
name_help_text: "This is the title of the phase users will read on the header whenever this phase is active."
|
||||
save_changes: Save changes
|
||||
index:
|
||||
help: "Participatory budgets have different phases. Here you can enable or disable phases and also customize each individual phase."
|
||||
|
||||
@@ -64,8 +64,10 @@ en:
|
||||
icon_alt: Participatory budgets icon
|
||||
title: Participatory budgets
|
||||
help: Help with participatory budgets
|
||||
all_phases: See all phases
|
||||
all_phases: Budget investment's phases
|
||||
all_phases: Participatory budgets phases
|
||||
next_phase: Next phase
|
||||
prev_phase: Previous phase
|
||||
current_phase: Current phase
|
||||
map: Budget investments' proposals located geographically
|
||||
investment_proyects: List of all investment projects
|
||||
unfeasible_investment_proyects: List of all unfeasible investment projects
|
||||
@@ -176,7 +178,6 @@ en:
|
||||
other: "You have selected <strong>%{count}</strong> projects out of <strong>%{limit}</strong>"
|
||||
show:
|
||||
group: Group
|
||||
phase: Actual phase
|
||||
unfeasible_title: Unfeasible investments
|
||||
unfeasible: See unfeasible investments
|
||||
unselected_title: Investments not selected for balloting phase
|
||||
|
||||
@@ -230,6 +230,7 @@ es:
|
||||
ends_at: "Fecha de fin"
|
||||
starts_at: "Fecha de inicio"
|
||||
budget/phase/translation:
|
||||
name: "Nombre"
|
||||
description: "Descripción"
|
||||
summary: "Resumen"
|
||||
comment:
|
||||
|
||||
@@ -76,8 +76,10 @@ es:
|
||||
help: "Los presupuestos participativos permiten que los ciudadanos propongan y decidan de manera directa cómo gastar parte del presupuesto, con un seguimiento y evaluación riguroso de las propuestas por parte de la institución."
|
||||
budget_investments: Gestionar proyectos de gasto
|
||||
table_completed: Completado
|
||||
table_duration: "Duración"
|
||||
table_name: Nombre
|
||||
table_phase: Fase
|
||||
table_phase_progress: "(%{current_phase_number}/%{total_phases})"
|
||||
edit_groups: Editar grupos de partidas
|
||||
edit_budget: Editar presupuesto
|
||||
admin_ballots: Gestionar urnas
|
||||
@@ -94,7 +96,8 @@ es:
|
||||
publish: "Publicar presupuesto"
|
||||
delete: Eliminar presupuesto
|
||||
phase: Fase
|
||||
dates: Fechas
|
||||
phases_caption: "Fases"
|
||||
duration: "Duración"
|
||||
enabled: Habilitada
|
||||
actions: Acciones
|
||||
edit_phase: Editar fase
|
||||
@@ -173,9 +176,11 @@ es:
|
||||
help: "Las partidas sirven para dividir el dinero del presupuesto participativo. Aquí puedes ir añadiendo partidas para cada grupo y establecer la cantidad de dinero que se gastará en cada partida."
|
||||
budget_phases:
|
||||
edit:
|
||||
summary_help_text: Este texto informará al usuario sobre la fase. Para mostrarlo aunque la fase no esté activa, marca la opción de más abajo.
|
||||
description_help_text: Este texto aparecerá en la cabecera cuando la fase esté activa
|
||||
duration: "Duración de la fase"
|
||||
duration_description: "El período de tiempo que esta fase estará activa."
|
||||
enabled_help_text: Esta fase será pública en el calendario de fases del presupuesto y estará activa para otros propósitos
|
||||
name_help_text: "Este es el título de la fase que los usuarios leerán en el encabezado cuando la fase esté activa."
|
||||
save_changes: Guardar cambios
|
||||
index:
|
||||
help: "Los presupuestos participativos tienen distintas fases. Aquí puedes habilitar o deshabilitar fases y también personalizar cada una de las fases."
|
||||
|
||||
@@ -64,8 +64,10 @@ es:
|
||||
icon_alt: Icono de Presupuestos participativos
|
||||
title: Presupuestos participativos
|
||||
help: Ayuda sobre presupuestos participativos
|
||||
all_phases: Ver todas las fases
|
||||
all_phases: Fases de los presupuestos participativos
|
||||
next_phase: Fase siguiente
|
||||
prev_phase: Fase anterior
|
||||
current_phase: Fase actual
|
||||
map: Proyectos localizables geográficamente
|
||||
investment_proyects: Ver lista completa de proyectos de gasto
|
||||
unfeasible_investment_proyects: Ver lista de proyectos de gasto inviables
|
||||
@@ -176,7 +178,6 @@ es:
|
||||
other: "Has seleccionado <strong>%{count}</strong> proyectos de <strong>%{limit}</strong>"
|
||||
show:
|
||||
group: Grupo
|
||||
phase: Fase actual
|
||||
unfeasible_title: Proyectos de gasto inviables
|
||||
unfeasible: Ver los proyectos inviables
|
||||
unselected_title: Proyectos no seleccionados para la votación final
|
||||
|
||||
@@ -43,6 +43,7 @@ section "Creating Budgets" do
|
||||
budget.phases.each do |phase|
|
||||
random_locales.map do |locale|
|
||||
Globalize.with_locale(locale) do
|
||||
phase.name = "Name for locale #{locale}"
|
||||
phase.description = "Description for locale #{locale}"
|
||||
phase.summary = "Summary for locale #{locale}"
|
||||
phase.save!
|
||||
|
||||
7
db/migrate/20200309100127_add_name_to_budget_phases.rb
Normal file
7
db/migrate/20200309100127_add_name_to_budget_phases.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class AddNameToBudgetPhases < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
change_table :budget_phase_translations do |t|
|
||||
t.string :name
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -286,6 +286,7 @@ ActiveRecord::Schema.define(version: 2021_01_23_100638) do
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "description"
|
||||
t.text "summary"
|
||||
t.string "name"
|
||||
t.index ["budget_phase_id"], name: "index_budget_phase_translations_on_budget_phase_id"
|
||||
t.index ["locale"], name: "index_budget_phase_translations_on_locale"
|
||||
end
|
||||
|
||||
@@ -29,4 +29,40 @@ namespace :budgets do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Copies the Budget::Phase summary into description"
|
||||
task phases_summary_to_description: :environment do
|
||||
ApplicationLogger.new.info "Adding budget phases summary to descriptions"
|
||||
|
||||
Budget::Phase::Translation.find_each do |translation|
|
||||
if translation.summary.present?
|
||||
translation.description << "<br>"
|
||||
translation.description << translation.summary
|
||||
translation.update!(summary: nil) if translation.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Add name to existing budget phases"
|
||||
task add_name_to_existing_phases: :environment do
|
||||
ApplicationLogger.new.info "Adding names to budgets phases"
|
||||
|
||||
Budget::Phase.find_each do |phase|
|
||||
if phase.translations.present?
|
||||
phase.translations.each do |translation|
|
||||
unless translation.name.present?
|
||||
if I18n.available_locales.include? translation.locale
|
||||
locale = translation.locale
|
||||
else
|
||||
locale = I18n.default_locale
|
||||
end
|
||||
|
||||
translation.update!(name: I18n.t("budgets.phase.#{phase.kind}", locale: locale))
|
||||
end
|
||||
end
|
||||
else
|
||||
phase.translations.create!(name: I18n.t("budgets.phase.#{phase.kind}"), locale: I18n.default_locale)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace :consul do
|
||||
task "execute_release_1.3.0_tasks": [
|
||||
"db:load_sdg",
|
||||
"db:calculate_tsv",
|
||||
"budgets:set_published"
|
||||
"budgets:set_published",
|
||||
"budgets:phases_summary_to_description",
|
||||
"budgets:add_name_to_existing_phases"
|
||||
]
|
||||
end
|
||||
|
||||
57
spec/components/admin/budgets/duration_component_spec.rb
Normal file
57
spec/components/admin/budgets/duration_component_spec.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Budgets::DurationComponent, type: :component do
|
||||
describe "#dates" do
|
||||
it "shows both dates when both are defined" do
|
||||
durable = double(
|
||||
starts_at: Time.zone.local(2015, 8, 1, 12, 0, 0),
|
||||
ends_at: Time.zone.local(2016, 9, 30, 16, 30, 00)
|
||||
)
|
||||
|
||||
dates = Admin::Budgets::DurationComponent.new(durable).dates
|
||||
|
||||
render dates
|
||||
|
||||
expect(page.text).to eq "2015-08-01 12:00:00 - 2016-09-30 16:29:59"
|
||||
expect(dates).to be_html_safe
|
||||
end
|
||||
|
||||
it "shows the start date when no end date is defined" do
|
||||
durable = double(starts_at: Time.zone.local(2015, 8, 1, 12, 0, 0), ends_at: nil)
|
||||
render Admin::Budgets::DurationComponent.new(durable).dates
|
||||
|
||||
expect(page.text).to eq "2015-08-01 12:00:00 - "
|
||||
end
|
||||
|
||||
it "shows the end date when no start date is defined" do
|
||||
durable = double(starts_at: nil, ends_at: Time.zone.local(2016, 9, 30, 16, 30, 00))
|
||||
|
||||
render Admin::Budgets::DurationComponent.new(durable).dates
|
||||
|
||||
expect(page.text).to eq "- 2016-09-30 16:29:59"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#duration" do
|
||||
it "describes the total duration in human language" do
|
||||
durable = double(
|
||||
starts_at: Time.zone.local(2015, 8, 1, 12, 0, 0),
|
||||
ends_at: Time.zone.local(2016, 9, 30, 16, 30, 00)
|
||||
)
|
||||
|
||||
render Admin::Budgets::DurationComponent.new(durable).duration
|
||||
|
||||
expect(page.text).to eq "about 1 year"
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :content
|
||||
|
||||
def render(content)
|
||||
@content = content
|
||||
end
|
||||
|
||||
def page
|
||||
Capybara::Node::Simple.new(content)
|
||||
end
|
||||
end
|
||||
@@ -1,70 +1,159 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Budget do
|
||||
let(:run_rake_task) do
|
||||
Rake::Task["budgets:set_published"].reenable
|
||||
Rake.application.invoke_task("budgets:set_published")
|
||||
describe "budget tasks" do
|
||||
describe "set_published" do
|
||||
let(:run_rake_task) do
|
||||
Rake::Task["budgets:set_published"].reenable
|
||||
Rake.application.invoke_task("budgets:set_published")
|
||||
end
|
||||
|
||||
it "does not change anything if the published attribute is set" do
|
||||
budget = create(:budget, published: false, phase: "accepting")
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be false
|
||||
end
|
||||
|
||||
it "publishes budgets which are not in draft mode" do
|
||||
budget = create(:budget, published: nil, phase: "accepting")
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be true
|
||||
end
|
||||
|
||||
it "changes the published attribute to false on drafting budgets" do
|
||||
stub_const("Budget::Phase::PHASE_KINDS", ["drafting"] + Budget::Phase::PHASE_KINDS)
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
stub_const("Budget::Phase::PHASE_KINDS", Budget::Phase::PHASE_KINDS - ["drafting"])
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
|
||||
expect(budget.published).to be false
|
||||
expect(budget.phase).to eq "informing"
|
||||
end
|
||||
|
||||
it "changes the phase to the first enabled phase" do
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
budget.phases.informing.update!(enabled: false)
|
||||
|
||||
expect(budget.phase).to eq "drafting"
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be false
|
||||
end
|
||||
|
||||
it "enables and select the informing phase if there are not any enabled phases" do
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
budget.phases.each { |phase| phase.update!(enabled: false) }
|
||||
|
||||
expect(budget.phase).to eq "drafting"
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
|
||||
expect(budget.phase).to eq "informing"
|
||||
expect(budget.phases.informing.enabled).to be true
|
||||
expect(budget.published).to be false
|
||||
end
|
||||
end
|
||||
|
||||
it "does not change anything if the published attribute is set" do
|
||||
budget = create(:budget, published: false, phase: "accepting")
|
||||
describe "phases_summary_to_description" do
|
||||
let(:run_rake_task) do
|
||||
Rake::Task["budgets:phases_summary_to_description"].reenable
|
||||
Rake.application.invoke_task("budgets:phases_summary_to_description")
|
||||
end
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
it "appends the content of summary to the content of description" do
|
||||
budget = create(:budget)
|
||||
budget_phase = budget.phases.informing
|
||||
budget_phase.update!(
|
||||
description_en: "English description",
|
||||
description_es: "Spanish description",
|
||||
description_fr: "French description",
|
||||
name_es: "Spanish name",
|
||||
name_fr: "French name",
|
||||
summary_en: "English summary",
|
||||
summary_fr: "French summary"
|
||||
)
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be false
|
||||
run_rake_task
|
||||
|
||||
budget_phase.reload
|
||||
expect(budget_phase.description_en).to eq "English description<br>English summary"
|
||||
expect(budget_phase.description_es).to eq "Spanish description"
|
||||
expect(budget_phase.description_fr).to eq "French description<br>French summary"
|
||||
expect(budget_phase.summary).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
it "publishes budgets which are not in draft mode" do
|
||||
budget = create(:budget, published: nil, phase: "accepting")
|
||||
describe "add_name_to_existing_phases" do
|
||||
let(:run_rake_task) do
|
||||
Rake::Task["budgets:add_name_to_existing_phases"].reenable
|
||||
Rake.application.invoke_task("budgets:add_name_to_existing_phases")
|
||||
end
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
it "adds the name to existing budget phases" do
|
||||
budget = create(:budget)
|
||||
informing_phase = budget.phases.informing
|
||||
accepting_phase = budget.phases.accepting
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be true
|
||||
end
|
||||
accepting_phase.update!(name_en: "Custom accepting", name_es: "Aceptando personalizado")
|
||||
informing_phase.translations.create!(locale: :es, name: "temp")
|
||||
informing_phase.translations.update_all(name: "")
|
||||
|
||||
it "changes the published attribute to false on drafting budgets" do
|
||||
stub_const("Budget::Phase::PHASE_KINDS", ["drafting"] + Budget::Phase::PHASE_KINDS)
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
stub_const("Budget::Phase::PHASE_KINDS", Budget::Phase::PHASE_KINDS - ["drafting"])
|
||||
expect(informing_phase.name_en).to eq ""
|
||||
expect(informing_phase.name_es).to eq ""
|
||||
expect(informing_phase.name_fr).to be nil
|
||||
expect(accepting_phase.name_en).to eq "Custom accepting"
|
||||
expect(accepting_phase.name_es).to eq "Aceptando personalizado"
|
||||
expect(accepting_phase.name_fr).to be nil
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
run_rake_task
|
||||
|
||||
expect(budget.published).to be false
|
||||
expect(budget.phase).to eq "informing"
|
||||
end
|
||||
expect(informing_phase.reload.name_en).to eq "Information"
|
||||
expect(informing_phase.reload.name_es).to eq "Información"
|
||||
expect(informing_phase.reload.name_fr).to be nil
|
||||
expect(accepting_phase.reload.name_en).to eq "Custom accepting"
|
||||
expect(accepting_phase.reload.name_es).to eq "Aceptando personalizado"
|
||||
expect(accepting_phase.reload.name_fr).to be nil
|
||||
end
|
||||
|
||||
it "changes the phase to the first enabled phase" do
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
budget.phases.informing.update!(enabled: false)
|
||||
it "adds the name in default locale to existing translations no longer available" do
|
||||
budget = create(:budget)
|
||||
informing_phase = budget.phases.informing
|
||||
obsolete_translation = informing_phase.translations.build(locale: :fiction)
|
||||
obsolete_translation.save!(validate: false)
|
||||
|
||||
expect(budget.phase).to eq "drafting"
|
||||
expect(obsolete_translation.reload.name).to be nil
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
run_rake_task
|
||||
|
||||
expect(budget.phase).to eq "accepting"
|
||||
expect(budget.published).to be false
|
||||
end
|
||||
expect(obsolete_translation.reload.name).to eq "Information"
|
||||
end
|
||||
|
||||
it "enables and select the informing phase if there are not any enabled phases" do
|
||||
budget = create(:budget, published: nil)
|
||||
budget.update_column(:phase, "drafting")
|
||||
budget.phases.each { |phase| phase.update!(enabled: false) }
|
||||
it "adds a default translation to phases with no translations" do
|
||||
budget = create(:budget)
|
||||
informing_phase = budget.phases.informing
|
||||
informing_phase.translations.destroy_all
|
||||
|
||||
expect(budget.phase).to eq "drafting"
|
||||
expect(informing_phase.reload.name).to be nil
|
||||
|
||||
run_rake_task
|
||||
budget.reload
|
||||
run_rake_task
|
||||
|
||||
expect(budget.phase).to eq "informing"
|
||||
expect(budget.phases.informing.enabled).to be true
|
||||
expect(budget.published).to be false
|
||||
expect(informing_phase.reload.name).to eq "Information"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,7 +9,6 @@ describe "Admin budget phases" do
|
||||
|
||||
fill_in "start_date", with: Date.current + 1.day
|
||||
fill_in "end_date", with: Date.current + 12.days
|
||||
fill_in_ckeditor "Summary", with: "New summary of the phase."
|
||||
fill_in_ckeditor "Description", with: "New description of the phase."
|
||||
uncheck "budget_phase_enabled"
|
||||
click_button "Save changes"
|
||||
@@ -19,9 +18,27 @@ describe "Admin budget phases" do
|
||||
|
||||
expect(budget.current_phase.starts_at.to_date).to eq((Date.current + 1.day).to_date)
|
||||
expect(budget.current_phase.ends_at.to_date).to eq((Date.current + 12.days).to_date)
|
||||
expect(budget.current_phase.summary).to include("New summary of the phase.")
|
||||
expect(budget.current_phase.description).to include("New description of the phase.")
|
||||
expect(budget.current_phase.enabled).to be(false)
|
||||
end
|
||||
|
||||
scenario "Show default phase name or custom if present" do
|
||||
visit edit_admin_budget_path(budget)
|
||||
|
||||
within_table "Phases" do
|
||||
expect(page).to have_content "Accepting projects"
|
||||
expect(page).not_to have_content "My phase custom name"
|
||||
|
||||
within("tr", text: "Accepting projects") { click_link "Edit phase" }
|
||||
end
|
||||
|
||||
fill_in "Name", with: "My phase custom name"
|
||||
click_button "Save changes"
|
||||
|
||||
within_table "Phases" do
|
||||
expect(page).to have_content "My phase custom name"
|
||||
expect(page).not_to have_content "Accepting projects"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,11 +41,11 @@ describe "Admin budgets", :admin do
|
||||
end
|
||||
|
||||
scenario "Displaying budgets" do
|
||||
budget = create(:budget)
|
||||
budget = create(:budget, :accepting)
|
||||
visit admin_budgets_path
|
||||
|
||||
expect(page).to have_content(budget.name)
|
||||
expect(page).to have_content(translated_phase_name(phase_kind: budget.phase))
|
||||
expect(page).to have_content budget.name
|
||||
expect(page).to have_content "Accepting projects"
|
||||
end
|
||||
|
||||
scenario "Filters by phase" do
|
||||
@@ -245,35 +245,53 @@ describe "Admin budgets", :admin do
|
||||
end
|
||||
|
||||
context "Edit" do
|
||||
let!(:budget) { create(:budget) }
|
||||
let(:budget) { create(:budget) }
|
||||
|
||||
scenario "Show phases table" do
|
||||
budget.update!(phase: "selecting")
|
||||
travel_to(Date.new(2015, 7, 15)) do
|
||||
budget.update!(phase: "selecting")
|
||||
budget.phases.valuating.update!(enabled: false)
|
||||
|
||||
visit admin_budgets_path
|
||||
click_link "Edit budget"
|
||||
visit edit_admin_budget_path(budget)
|
||||
|
||||
expect(page).to have_select("budget_phase", selected: "Selecting projects")
|
||||
expect(page).to have_select "Phase", selected: "Selecting projects"
|
||||
|
||||
within "#budget-phases-table" do
|
||||
Budget::Phase::PHASE_KINDS.each do |phase_kind|
|
||||
break if phase_kind == Budget::Phase::PHASE_KINDS.last
|
||||
expect(page).to have_table "Phases", with_cols: [
|
||||
[
|
||||
"Information",
|
||||
"Accepting projects",
|
||||
"Reviewing projects",
|
||||
"Selecting projects Active",
|
||||
"Valuating projects",
|
||||
"Publishing projects prices",
|
||||
"Voting projects",
|
||||
"Reviewing voting"
|
||||
],
|
||||
[
|
||||
"2015-07-15 00:00:00 - 2015-08-14 23:59:59",
|
||||
"2015-08-15 00:00:00 - 2015-09-14 23:59:59",
|
||||
"2015-09-15 00:00:00 - 2015-10-14 23:59:59",
|
||||
"2015-10-15 00:00:00 - 2015-11-14 23:59:59",
|
||||
"2015-11-15 00:00:00 - 2015-12-14 23:59:59",
|
||||
"2015-11-15 00:00:00 - 2016-01-14 23:59:59",
|
||||
"2016-01-15 00:00:00 - 2016-02-14 23:59:59",
|
||||
"2016-02-15 00:00:00 - 2016-03-14 23:59:59"
|
||||
],
|
||||
[
|
||||
"Yes",
|
||||
"Yes",
|
||||
"Yes",
|
||||
"Yes",
|
||||
"No",
|
||||
"Yes",
|
||||
"Yes",
|
||||
"Yes"
|
||||
]
|
||||
]
|
||||
|
||||
phase_index = Budget::Phase::PHASE_KINDS.index(phase_kind)
|
||||
next_phase_kind = Budget::Phase::PHASE_KINDS[phase_index + 1]
|
||||
next_phase_name = translated_phase_name(phase_kind: next_phase_kind)
|
||||
expect(translated_phase_name(phase_kind: phase_kind)).to appear_before(next_phase_name)
|
||||
end
|
||||
|
||||
budget.phases.each do |phase|
|
||||
edit_phase_link = edit_admin_budget_budget_phase_path(budget, phase)
|
||||
|
||||
within "#budget_phase_#{phase.id}" do
|
||||
expect(page).to have_content(translated_phase_name(phase_kind: phase.kind))
|
||||
expect(page).to have_content("#{phase.starts_at.to_date} - #{phase.ends_at.to_date}")
|
||||
expect(page).to have_css(".budget-phase-enabled.enabled")
|
||||
expect(page).to have_link("Edit phase", href: edit_phase_link)
|
||||
expect(page).to have_content("Active") if budget.current_phase == phase
|
||||
within_table "Phases" do
|
||||
within "tr", text: "Information" do
|
||||
expect(page).to have_link "Edit phase"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -402,7 +420,3 @@ describe "Admin budgets", :admin do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def translated_phase_name(phase_kind: kind)
|
||||
I18n.t("budgets.phase.#{phase_kind}")
|
||||
end
|
||||
|
||||
@@ -416,7 +416,7 @@ describe "Admin edit translatable records", :admin do
|
||||
let(:translatable) { create(:budget).phases.last }
|
||||
|
||||
scenario "Shows first available fallback" do
|
||||
translatable.update!({ description_fr: "Phase en Français", summary_fr: "Phase résumé" })
|
||||
translatable.update!({ name_fr: "Name en Français", description_fr: "Phase en Français" })
|
||||
|
||||
visit edit_admin_budget_budget_phase_path(translatable.budget, translatable)
|
||||
|
||||
@@ -428,8 +428,9 @@ describe "Admin edit translatable records", :admin do
|
||||
click_button "Save changes"
|
||||
|
||||
visit budgets_path
|
||||
click_link "Name en Français"
|
||||
|
||||
expect(page).to have_content "Phase résumé"
|
||||
expect(page).to have_content "Phase en Français"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -38,19 +38,21 @@ describe "Budgets" do
|
||||
|
||||
visit budgets_path
|
||||
|
||||
within("#budget_heading") do
|
||||
within(".budget-header") do
|
||||
expect(page).to have_content(budget.name)
|
||||
expect(page).to have_content(budget.description)
|
||||
expect(page).to have_content("Actual phase")
|
||||
expect(page).to have_content("Information")
|
||||
expect(page).to have_link("Help with participatory budgets")
|
||||
expect(page).to have_link("See all phases")
|
||||
end
|
||||
|
||||
within(".budget-subheader") do
|
||||
expect(page).to have_content "Current phase"
|
||||
expect(page).to have_content "Information"
|
||||
end
|
||||
|
||||
budget.update!(phase: "publishing_prices")
|
||||
visit budgets_path
|
||||
|
||||
within("#budget_heading") do
|
||||
within(".budget-subheader") do
|
||||
expect(page).to have_content("Publishing projects prices")
|
||||
end
|
||||
|
||||
@@ -208,63 +210,72 @@ describe "Budgets" do
|
||||
|
||||
phases.informing.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
|
||||
description: "Description of informing phase",
|
||||
summary: "<p>This is the summary for informing phase</p>")
|
||||
name: "Custom name for informing phase")
|
||||
|
||||
phases.accepting.update!(starts_at: "01-01-2018", ends_at: "10-01-2018", enabled: true,
|
||||
description: "Description of accepting phase",
|
||||
summary: "This is the summary for accepting phase")
|
||||
name: "Custom name for accepting phase")
|
||||
|
||||
phases.reviewing.update!(starts_at: "11-01-2018", ends_at: "20-01-2018", enabled: false,
|
||||
description: "Description of reviewing phase",
|
||||
summary: "This is the summary for reviewing phase")
|
||||
description: "Description of reviewing phase")
|
||||
|
||||
phases.selecting.update!(starts_at: "21-01-2018", ends_at: "01-02-2018", enabled: true,
|
||||
description: "Description of selecting phase",
|
||||
summary: "This is the summary for selecting phase")
|
||||
name: "Custom name for selecting phase")
|
||||
|
||||
phases.valuating.update!(starts_at: "10-02-2018", ends_at: "20-02-2018", enabled: false,
|
||||
description: "Description of valuating phase",
|
||||
summary: "This is the summary for valuating phase")
|
||||
description: "Description of valuating phase")
|
||||
|
||||
phases.publishing_prices.update!(starts_at: "21-02-2018", ends_at: "01-03-2018", enabled: false,
|
||||
description: "Description of publishing prices phase",
|
||||
summary: "This is the summary for publishing_prices phase")
|
||||
description: "Description of publishing prices phase")
|
||||
|
||||
phases.balloting.update!(starts_at: "02-03-2018", ends_at: "10-03-2018", enabled: true,
|
||||
description: "Description of balloting phase",
|
||||
summary: "This is the summary for balloting phase")
|
||||
description: "Description of balloting phase")
|
||||
|
||||
phases.reviewing_ballots.update!(starts_at: "11-03-2018", ends_at: "20-03-2018", enabled: false,
|
||||
description: "Description of reviewing ballots phase",
|
||||
summary: "This is the summary for reviewing_ballots phase")
|
||||
description: "Description of reviewing ballots phase")
|
||||
|
||||
phases.finished.update!(starts_at: "21-03-2018", ends_at: "30-03-2018", enabled: true,
|
||||
description: "Description of finished phase",
|
||||
summary: "This is the summary for finished phase")
|
||||
description: "Description of finished phase")
|
||||
|
||||
visit budgets_path
|
||||
|
||||
expect(page).not_to have_content "This is the summary for reviewing phase"
|
||||
expect(page).not_to have_content "Description of reviewing phase"
|
||||
expect(page).not_to have_content "January 11, 2018 - January 20, 2018"
|
||||
expect(page).not_to have_content "This is the summary for valuating phase"
|
||||
expect(page).not_to have_content "Description of valuating phase"
|
||||
expect(page).not_to have_content "February 10, 2018 - February 20, 2018"
|
||||
expect(page).not_to have_content "This is the summary for publishing_prices phase"
|
||||
expect(page).not_to have_content "Description of publishing_prices phase"
|
||||
expect(page).not_to have_content "February 21, 2018 - March 01, 2018"
|
||||
expect(page).not_to have_content "This is the summary for reviewing_ballots phase"
|
||||
expect(page).not_to have_content "Description of reviewing_ballots phase"
|
||||
expect(page).not_to have_content "March 11, 2018 - March 20, 2018"
|
||||
|
||||
expect(page).to have_content "This is the summary for informing phase"
|
||||
expect(page).to have_content "Description of informing phase"
|
||||
expect(page).to have_content "December 30, 2017 - December 31, 2017"
|
||||
expect(page).to have_content "This is the summary for accepting phase"
|
||||
expect(page).to have_content "Description of accepting phase"
|
||||
expect(page).to have_content "January 01, 2018 - January 20, 2018"
|
||||
expect(page).to have_content "This is the summary for selecting phase"
|
||||
expect(page).to have_content "Description of selecting phase"
|
||||
expect(page).to have_content "January 21, 2018 - March 01, 2018"
|
||||
expect(page).to have_content "This is the summary for balloting phase"
|
||||
expect(page).to have_content "Description of balloting phase"
|
||||
expect(page).to have_content "March 02, 2018 - March 20, 2018"
|
||||
expect(page).to have_content "This is the summary for finished phase"
|
||||
expect(page).to have_content "Description of finished phase"
|
||||
expect(page).to have_content "March 21, 2018 - March 29, 2018"
|
||||
|
||||
expect(page).to have_css(".phase.is-active", count: 1)
|
||||
expect(page).to have_css(".tabs-panel.is-active", count: 1)
|
||||
|
||||
within("#budget_phases_tabs") do
|
||||
expect(page).to have_link "Custom name for informing phase"
|
||||
expect(page).to have_link "Custom name for accepting phase"
|
||||
expect(page).to have_link "Custom name for selecting phase"
|
||||
expect(page).to have_link phases.balloting.name
|
||||
expect(page).to have_link "Current phase #{phases.finished.name}"
|
||||
end
|
||||
|
||||
click_link "Custom name for accepting phase"
|
||||
|
||||
within("#2-custom-name-for-accepting-phase") do
|
||||
expect(page).to have_link("Previous phase", href: "#1-custom-name-for-informing-phase")
|
||||
expect(page).to have_link("Next phase", href: "#3-custom-name-for-selecting-phase")
|
||||
end
|
||||
end
|
||||
|
||||
context "Index map" do
|
||||
|
||||
Reference in New Issue
Block a user