diff --git a/app/assets/stylesheets/_consul_settings.scss b/app/assets/stylesheets/_consul_settings.scss
index 736433875..2124fa115 100644
--- a/app/assets/stylesheets/_consul_settings.scss
+++ b/app/assets/stylesheets/_consul_settings.scss
@@ -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: (
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index c620a3751..e96a34cfd 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -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-"] {
diff --git a/app/assets/stylesheets/admin/budget_phases/form.scss b/app/assets/stylesheets/admin/budget_phases/form.scss
new file mode 100644
index 000000000..8e9be056f
--- /dev/null
+++ b/app/assets/stylesheets/admin/budget_phases/form.scss
@@ -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;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/admin/budget_phases/phases.scss b/app/assets/stylesheets/admin/budget_phases/phases.scss
new file mode 100644
index 000000000..ca0269f23
--- /dev/null
+++ b/app/assets/stylesheets/admin/budget_phases/phases.scss
@@ -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;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/admin/budgets/form.scss b/app/assets/stylesheets/admin/budgets/form.scss
index a5ae94ea4..0fef7a2e6 100644
--- a/app/assets/stylesheets/admin/budgets/form.scss
+++ b/app/assets/stylesheets/admin/budgets/form.scss
@@ -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;
diff --git a/app/assets/stylesheets/admin/budgets/index.scss b/app/assets/stylesheets/admin/budgets/index.scss
index 183439343..1ce224b76 100644
--- a/app/assets/stylesheets/admin/budgets/index.scss
+++ b/app/assets/stylesheets/admin/budgets/index.scss
@@ -21,4 +21,10 @@
text-transform: uppercase;
}
}
+
+ td time:last-of-type::after,
+ td small::before {
+ content: "";
+ display: block;
+ }
}
diff --git a/app/assets/stylesheets/admin/table_actions.scss b/app/assets/stylesheets/admin/table_actions.scss
index 51f1a5ee5..b217105ba 100644
--- a/app/assets/stylesheets/admin/table_actions.scss
+++ b/app/assets/stylesheets/admin/table_actions.scss
@@ -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 {
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 149facb82..6ce3e2ede 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -32,6 +32,7 @@
@import "sticky_overrides";
@import "tags";
@import "admin/**/*";
+@import "budgets/*";
@import "sdg/**/*";
@import "sdg_management/*";
@import "sdg_management/**/*";
diff --git a/app/assets/stylesheets/budgets/phases.scss b/app/assets/stylesheets/budgets/phases.scss
new file mode 100644
index 000000000..6796c9ba7
--- /dev/null
+++ b/app/assets/stylesheets/budgets/phases.scss
@@ -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%;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/budgets/subheader.scss b/app/assets/stylesheets/budgets/subheader.scss
new file mode 100644
index 000000000..ba51bd3bc
--- /dev/null
+++ b/app/assets/stylesheets/budgets/subheader.scss
@@ -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;
+ }
+}
diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss
index 7e17cb531..944463b96 100644
--- a/app/assets/stylesheets/layout.scss
+++ b/app/assets/stylesheets/layout.scss
@@ -2155,7 +2155,7 @@ table {
}
}
- + .budget.expanded,
+ + .budget-header,
+ .jumbo {
margin-top: 0;
}
diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index 4a3669547..764d4592c 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -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 {
diff --git a/app/components/admin/budget_phases/phases_component.html.erb b/app/components/admin/budget_phases/phases_component.html.erb
new file mode 100644
index 000000000..6f663578c
--- /dev/null
+++ b/app/components/admin/budget_phases/phases_component.html.erb
@@ -0,0 +1,40 @@
+<% if phases.present? %>
+
+ <%= t("admin.budgets.edit.phases_caption") %>
+
+
+ | <%= t("admin.budgets.edit.phase") %> |
+ <%= t("admin.budgets.edit.duration") %> |
+ <%= t("admin.budgets.edit.enabled") %> |
+ <%= t("admin.budgets.edit.actions") %> |
+
+
+
+ <% phases.each do |phase| %>
+
+ |
+ <%= phase.name %>
+ <% if phase.current? %>
+ <%= t("admin.budgets.edit.active") %>
+ <% end %>
+ |
+
+ <% if phase.starts_at.present? || phase.ends_at.present? %>
+ <%= dates(phase) %>
+ <% else %>
+ <%= t("admin.budgets.edit.blank_dates") %>
+ <% end %>
+ |
+
+ <%= enabled_text(phase) %>
+ |
+
+ <%= render Admin::TableActionsComponent.new(phase,
+ actions: [:edit],
+ edit_text: t("admin.budgets.edit.edit_phase")
+ ) %>
+ |
+
+ <% end %>
+
+<% end %>
diff --git a/app/components/admin/budget_phases/phases_component.rb b/app/components/admin/budget_phases/phases_component.rb
new file mode 100644
index 000000000..b27958f18
--- /dev/null
+++ b/app/components/admin/budget_phases/phases_component.rb
@@ -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
diff --git a/app/components/admin/budgets/duration_component.rb b/app/components/admin/budgets/duration_component.rb
new file mode 100644
index 000000000..8af1a3ad0
--- /dev/null
+++ b/app/components/admin/budgets/duration_component.rb
@@ -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
diff --git a/app/components/admin/budgets/index_component.html.erb b/app/components/admin/budgets/index_component.html.erb
new file mode 100644
index 000000000..c371205f4
--- /dev/null
+++ b/app/components/admin/budgets/index_component.html.erb
@@ -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? %>
+ <%= page_entries_info budgets %>
+
+
+
+
+ | <%= t("admin.budgets.index.table_name") %> |
+ <%= t("admin.budgets.index.table_phase") %> |
+ <%= t("admin.budgets.index.table_duration") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+
+ <% budgets.each do |budget| %>
+
+ | ">
+ <% if budget.finished? %>
+
+ <%= t("admin.budgets.index.table_completed") %>
+
+ <% end %>
+ <%= budget.name %>
+ |
+
+ <%= budget.current_phase.name %>
+ <%= phase_progress_text(budget) %>
+ |
+
+ <%= dates(budget) %>
+ <%= duration(budget) %>
+ |
+
+ <%= render Admin::Budgets::TableActionsComponent.new(budget) %>
+ |
+
+ <% end %>
+
+
+
+ <%= paginate budgets %>
+<% else %>
+
+ <%= t("admin.budgets.index.no_budgets") %>
+
+<% end %>
diff --git a/app/components/admin/budgets/index_component.rb b/app/components/admin/budgets/index_component.rb
new file mode 100644
index 000000000..7523207da
--- /dev/null
+++ b/app/components/admin/budgets/index_component.rb
@@ -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
diff --git a/app/components/budgets/phases_component.html.erb b/app/components/budgets/phases_component.html.erb
new file mode 100644
index 000000000..d678181cf
--- /dev/null
+++ b/app/components/budgets/phases_component.html.erb
@@ -0,0 +1,53 @@
+
+
+ <%= t("budgets.index.all_phases") %>
+
+
+
+
+
+ <% phases.each do |phase| %>
+
">
+
+
+
+
<%= phase.name %>
+
<%= start_date(phase) %> - <%= end_date(phase) %>
+ <%= auto_link_already_sanitized_html(wysiwyg(phase.description)) %>
+
+
+ <% end %>
+
+
diff --git a/app/components/budgets/phases_component.rb b/app/components/budgets/phases_component.rb
new file mode 100644
index 000000000..ee23c7070
--- /dev/null
+++ b/app/components/budgets/phases_component.rb
@@ -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
diff --git a/app/components/budgets/subheader_component.html.erb b/app/components/budgets/subheader_component.html.erb
new file mode 100644
index 000000000..6e97da27a
--- /dev/null
+++ b/app/components/budgets/subheader_component.html.erb
@@ -0,0 +1,38 @@
+
diff --git a/app/components/budgets/subheader_component.rb b/app/components/budgets/subheader_component.rb
new file mode 100644
index 000000000..7d301d4ac
--- /dev/null
+++ b/app/components/budgets/subheader_component.rb
@@ -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
diff --git a/app/models/budget.rb b/app/models/budget.rb
index b36535278..d6034c896 100644
--- a/app/models/budget.rb
+++ b/app/models/budget.rb
@@ -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
diff --git a/app/models/budget/phase.rb b/app/models/budget/phase.rb
index d8b59207f..4bc277b77 100644
--- a/app/models/budget/phase.rb
+++ b/app/models/budget/phase.rb
@@ -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
diff --git a/app/views/admin/budget_phases/_form.html.erb b/app/views/admin/budget_phases/_form.html.erb
index 609261344..f54f2aad6 100644
--- a/app/views/admin/budget_phases/_form.html.erb
+++ b/app/views/admin/budget_phases/_form.html.erb
@@ -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 %>
-
-
+