diff --git a/app/assets/javascripts/admin/budgets_wizard/creation_step.js b/app/assets/javascripts/admin/budgets_wizard/creation_step.js
new file mode 100644
index 000000000..fa1ffcebb
--- /dev/null
+++ b/app/assets/javascripts/admin/budgets_wizard/creation_step.js
@@ -0,0 +1,20 @@
+(function() {
+ "use strict";
+ App.AdminBudgetsWizardCreationStep = {
+ initialize: function() {
+ var element, add_button, cancel_button;
+
+ element = $(".admin .budget-creation-step");
+ add_button = element.find(".add");
+ cancel_button = element.find(".delete");
+
+ add_button.click(function() {
+ $(this).attr("aria-expanded", true).parent().find(":input:visible:first").focus();
+ });
+
+ cancel_button.click(function() {
+ add_button.attr("aria-expanded", false).focus();
+ });
+ }
+ };
+}).call(this);
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 774ea5c78..51a7a4d55 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -113,6 +113,7 @@
//= require columns_selector
//= require budget_edit_associations
//= require datepicker
+//= require_tree ./admin
//= require_tree ./sdg
//= require_tree ./sdg_management
@@ -166,6 +167,7 @@ var initialize_modules = function() {
if ($("#js-columns-selector").length) {
App.ColumnsSelector.initialize();
}
+ App.AdminBudgetsWizardCreationStep.initialize();
App.BudgetEditAssociations.initialize();
App.Datepicker.initialize();
App.SDGRelatedListSelector.initialize();
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 8aede0497..17e221cf7 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -258,6 +258,11 @@ $table-header: #ecf1f6;
[type="submit"] ~ a {
margin-left: $line-height / 2;
}
+
+ [type="checkbox"] {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
}
hr {
diff --git a/app/assets/stylesheets/admin/budget_groups/form.scss b/app/assets/stylesheets/admin/budget_groups/form.scss
new file mode 100644
index 000000000..a34dbaf8a
--- /dev/null
+++ b/app/assets/stylesheets/admin/budget_groups/form.scss
@@ -0,0 +1,3 @@
+.admin .budget-groups-form {
+ @include full-width-form;
+}
diff --git a/app/assets/stylesheets/admin/budget_headings/form.scss b/app/assets/stylesheets/admin/budget_headings/form.scss
new file mode 100644
index 000000000..430601bcc
--- /dev/null
+++ b/app/assets/stylesheets/admin/budget_headings/form.scss
@@ -0,0 +1,3 @@
+.admin .budget-headings-form {
+ @include full-width-form;
+}
diff --git a/app/assets/stylesheets/admin/budgets/form.scss b/app/assets/stylesheets/admin/budgets/form.scss
index 0fef7a2e6..9d0407030 100644
--- a/app/assets/stylesheets/admin/budgets/form.scss
+++ b/app/assets/stylesheets/admin/budgets/form.scss
@@ -1,4 +1,5 @@
.admin .budgets-form {
+ @include full-width-form;
> fieldset {
border-top: 4px solid $admin-border-color;
@@ -17,8 +18,4 @@
text-transform: uppercase;
}
}
-
- .globalize-languages {
- max-width: none;
- }
}
diff --git a/app/assets/stylesheets/admin/budgets_wizard/creation_step.scss b/app/assets/stylesheets/admin/budgets_wizard/creation_step.scss
new file mode 100644
index 000000000..e7e860508
--- /dev/null
+++ b/app/assets/stylesheets/admin/budgets_wizard/creation_step.scss
@@ -0,0 +1,50 @@
+.budget-creation-step {
+
+ .add {
+ @include has-fa-icon(plus-square, solid);
+ @include regular-button;
+
+ font-weight: bold;
+ padding-left: rem-calc(10);
+
+ &::before {
+ margin-right: rem-calc(12);
+ }
+
+ &[aria-expanded="false"] {
+ ~ :not(.next-step) {
+ display: none;
+ }
+ }
+
+ &[aria-expanded="true"] {
+ display: none;
+
+ ~ .next-step {
+ display: none;
+ }
+ }
+ }
+
+ .cancel {
+ display: block;
+ margin-bottom: $line-height;
+ }
+
+ .next-step {
+ @include regular-button;
+ }
+
+ a {
+ &.next-step {
+ @include button-style($success-color, auto, auto);
+ }
+ }
+
+ p {
+ &.next-step {
+ @include button-style($secondary-color, auto, auto);
+ @include button-disabled;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/admin/budgets_wizard/creation_timeline.scss b/app/assets/stylesheets/admin/budgets_wizard/creation_timeline.scss
new file mode 100644
index 000000000..67a79ef0c
--- /dev/null
+++ b/app/assets/stylesheets/admin/budgets_wizard/creation_timeline.scss
@@ -0,0 +1,34 @@
+.creation-timeline {
+ display: flex;
+ list-style-type: none;
+ margin: $line-height * 2 0;
+ position: relative;
+
+ li {
+ border-top: 4px solid $brand;
+ display: inline-block;
+ font-size: $small-font-size;
+ font-weight: bold;
+ padding: $line-height / 2 $line-height * 3 0;
+ text-transform: uppercase;
+
+ &::before {
+ background: $brand;
+ border-radius: 50%;
+ content: "";
+ height: 20px;
+ margin-left: $line-height / 2;
+ position: absolute;
+ top: -8px;
+ width: 20px;
+ }
+
+ &[aria-current] ~ * {
+ border-color: $admin-border-color;
+
+ &::before {
+ background: $admin-border-color;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss b/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss
new file mode 100644
index 000000000..e0c4109f3
--- /dev/null
+++ b/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss
@@ -0,0 +1,50 @@
+.budget-group-switcher {
+ margin-bottom: $line-height;
+
+ p {
+ margin-bottom: 0;
+ }
+
+ > .menu > li {
+
+ > button {
+ align-items: center;
+ border: $admin-border;
+ border-radius: $button-radius;
+ display: inline-flex;
+ padding: rem-calc(11) rem-calc(16);
+
+ &:active {
+ color: inherit;
+ }
+
+ &::after {
+ @include css-triangle($dropdownmenu-arrow-size, currentcolor, down);
+ margin-left: 0.2em;
+ }
+ }
+ }
+
+ .menu.is-dropdown-submenu {
+ margin: 0;
+ min-width: 100%;
+ padding: 0;
+
+ li {
+ margin-bottom: 0;
+ }
+
+ a {
+ cursor: default;
+ padding: rem-calc(11) rem-calc(16);
+ width: 100%;
+
+ &:focus,
+ &:hover {
+ @include brand-background;
+ text-decoration: none;
+ outline: none;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/mixins/buttons.scss b/app/assets/stylesheets/mixins/buttons.scss
index 9e6fea4a1..5ef6a960d 100644
--- a/app/assets/stylesheets/mixins/buttons.scss
+++ b/app/assets/stylesheets/mixins/buttons.scss
@@ -1,4 +1,4 @@
-%button {
+@mixin base-button {
font-size: $base-font-size;
&:focus,
@@ -7,16 +7,20 @@
}
}
+%button {
+ @include base-button;
+}
+
@mixin regular-button($color: $brand) {
@include button($background: $color);
@include inverted-selection;
- @extend %button;
+ @include base-button;
}
@mixin hollow-button($color: $link) {
@include button($style: hollow, $background: $color);
@include normal-selection;
- @extend %button;
+ @include base-button;
margin-bottom: 0;
}
diff --git a/app/assets/stylesheets/mixins/layouts.scss b/app/assets/stylesheets/mixins/layouts.scss
index ee5422be9..38f53974e 100644
--- a/app/assets/stylesheets/mixins/layouts.scss
+++ b/app/assets/stylesheets/mixins/layouts.scss
@@ -21,3 +21,9 @@
margin-top: 0;
}
}
+
+@mixin full-width-form {
+ .globalize-languages {
+ max-width: none;
+ }
+}
diff --git a/app/components/admin/budget_groups/groups_component.html.erb b/app/components/admin/budget_groups/groups_component.html.erb
new file mode 100644
index 000000000..2b8f1d596
--- /dev/null
+++ b/app/components/admin/budget_groups/groups_component.html.erb
@@ -0,0 +1,33 @@
+<% if groups.any? %>
+
<%= t("admin.budget_groups.amount", count: groups.count) %>
+
+
+
+ | <%= t("admin.budget_groups.name") %> |
+ <%= Budget::Group.human_attribute_name(:max_votable_headings) %> |
+ <%= t("admin.budget_groups.headings_name") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+
+ <% groups.each do |group| %>
+
+ | <%= group.name %> |
+ <%= group.max_votable_headings %> |
+ <%= group.headings.count %> |
+
+ <%= render Admin::TableActionsComponent.new(group) do |actions| %>
+ <%= actions.link_to t("admin.budget_groups.headings_manage"),
+ headings_path(actions, group),
+ class: "headings-link" %>
+ <% end %>
+ |
+
+ <% end %>
+
+
+<% else %>
+
+ <%= t("admin.budget_groups.no_groups") %>
+
+<% end %>
diff --git a/app/components/admin/budget_groups/groups_component.rb b/app/components/admin/budget_groups/groups_component.rb
new file mode 100644
index 000000000..51bf60649
--- /dev/null
+++ b/app/components/admin/budget_groups/groups_component.rb
@@ -0,0 +1,17 @@
+class Admin::BudgetGroups::GroupsComponent < ApplicationComponent
+ attr_reader :groups
+
+ def initialize(groups)
+ @groups = groups
+ end
+
+ private
+
+ def budget
+ @budget ||= groups.first.budget
+ end
+
+ def headings_path(table_actions_component, group)
+ send("#{table_actions_component.namespace}_budget_group_headings_path", group.budget, group)
+ end
+end
diff --git a/app/components/admin/budget_headings/headings_component.html.erb b/app/components/admin/budget_headings/headings_component.html.erb
new file mode 100644
index 000000000..9e32dcbe5
--- /dev/null
+++ b/app/components/admin/budget_headings/headings_component.html.erb
@@ -0,0 +1,39 @@
+<% if headings.any? %>
+ <%= t("admin.budget_headings.amount", count: headings.count) %>
+
+
+
+ | <%= Budget::Heading.human_attribute_name(:name) %> |
+ <%= Budget::Heading.human_attribute_name(:price) %> |
+ <% if budget.approval_voting? %>
+ <%= Budget::Heading.human_attribute_name(:max_ballot_lines) %> |
+ <% end %>
+ <%= Budget::Heading.human_attribute_name(:population) %> |
+ <%= Budget::Heading.human_attribute_name(:allow_custom_content) %> |
+ <%= t("admin.actions.actions") %> |
+
+
+
+ <% headings.each do |heading| %>
+
+ | <%= heading.name %> |
+ <%= budget.formatted_heading_price(heading) %> |
+ <% if budget.approval_voting? %>
+ <%= heading.max_ballot_lines %> |
+ <% end %>
+ <%= heading.population %> |
+
+ <%= heading.allow_custom_content ? t("admin.shared.true_value") : t("admin.shared.false_value") %>
+ |
+
+ <%= render Admin::TableActionsComponent.new(heading) %>
+ |
+
+ <% end %>
+
+
+<% else %>
+
+ <%= t("admin.budget_headings.no_headings") %>
+
+<% end %>
diff --git a/app/components/admin/budget_headings/headings_component.rb b/app/components/admin/budget_headings/headings_component.rb
new file mode 100644
index 000000000..3b6594f23
--- /dev/null
+++ b/app/components/admin/budget_headings/headings_component.rb
@@ -0,0 +1,17 @@
+class Admin::BudgetHeadings::HeadingsComponent < ApplicationComponent
+ attr_reader :headings
+
+ def initialize(headings)
+ @headings = headings
+ end
+
+ private
+
+ def group
+ @group ||= headings.first.group
+ end
+
+ def budget
+ @budget ||= headings.first.budget
+ end
+end
diff --git a/app/components/admin/budget_phases/form_component.html.erb b/app/components/admin/budget_phases/form_component.html.erb
new file mode 100644
index 000000000..78f10c235
--- /dev/null
+++ b/app/components/admin/budget_phases/form_component.html.erb
@@ -0,0 +1,49 @@
+<%= render "shared/globalize_locales", resource: phase %>
+
+<%= translatable_form_for [namespace, phase.budget, phase], html: { class: "budget-phases-form" } do |f| %>
+
+ <%= render "shared/errors", resource: phase %>
+
+
+
+
+ <%= f.check_box :enabled %>
+
+
+ <%= t("admin.budget_phases.edit.enabled_help_text") %>
+
+
+
+ <%= f.translatable_fields do |translations_form| %>
+
+ <%= translations_form.text_field :name, hint: t("admin.budget_phases.edit.name_help_text") %>
+
+
+
+ <%= translations_form.text_area :description,
+ maxlength: Budget::Phase::DESCRIPTION_MAX_LENGTH,
+ class: "html-area",
+ hint: t("admin.budget_phases.edit.description_help_text") %>
+
+ <% end %>
+
+
+ <%= f.submit t("admin.budget_phases.edit.save_changes"), class: "button success" %>
+
+<% end %>
diff --git a/app/components/admin/budget_phases/form_component.rb b/app/components/admin/budget_phases/form_component.rb
new file mode 100644
index 000000000..49c6cf36c
--- /dev/null
+++ b/app/components/admin/budget_phases/form_component.rb
@@ -0,0 +1,11 @@
+class Admin::BudgetPhases::FormComponent < ApplicationComponent
+ include TranslatableFormHelper
+ include GlobalizeHelper
+ include Admin::Namespace
+
+ attr_reader :phase
+
+ def initialize(phase)
+ @phase = phase
+ end
+end
diff --git a/app/components/admin/budget_phases/phases_component.html.erb b/app/components/admin/budget_phases/phases_component.html.erb
index 6f663578c..787508634 100644
--- a/app/components/admin/budget_phases/phases_component.html.erb
+++ b/app/components/admin/budget_phases/phases_component.html.erb
@@ -26,7 +26,7 @@
<% end %>
- <%= enabled_text(phase) %>
+ <%= enabled_cell(phase) %>
|
<%= render Admin::TableActionsComponent.new(phase,
diff --git a/app/components/admin/budget_phases/phases_component.rb b/app/components/admin/budget_phases/phases_component.rb
index b27958f18..25a2d0280 100644
--- a/app/components/admin/budget_phases/phases_component.rb
+++ b/app/components/admin/budget_phases/phases_component.rb
@@ -1,8 +1,9 @@
class Admin::BudgetPhases::PhasesComponent < ApplicationComponent
- attr_reader :budget
+ attr_reader :budget, :form
- def initialize(budget)
+ def initialize(budget, form: nil)
@budget = budget
+ @form = form
end
private
@@ -15,6 +16,20 @@ class Admin::BudgetPhases::PhasesComponent < ApplicationComponent
Admin::Budgets::DurationComponent.new(phase).dates
end
+ def enabled_cell(phase)
+ if form
+ form.fields_for :phases, phase do |phase_fields|
+ phase_fields.check_box :enabled,
+ label: false,
+ aria: {
+ label: t("admin.budgets.edit.enable_phase", phase: phase.name)
+ }
+ end
+ else
+ enabled_text(phase)
+ end
+ end
+
def enabled_text(phase)
if phase.enabled?
tag.span t("shared.yes"), class: "budget-phase-enabled"
diff --git a/app/views/admin/budgets/_form.html.erb b/app/components/admin/budgets/form_component.html.erb
similarity index 56%
rename from app/views/admin/budgets/_form.html.erb
rename to app/components/admin/budgets/form_component.html.erb
index 295f1234a..57a3f8d44 100644
--- a/app/views/admin/budgets/_form.html.erb
+++ b/app/components/admin/budgets/form_component.html.erb
@@ -1,8 +1,8 @@
-<%= translatable_form_for [:admin, @budget], html: { class: "budgets-form" } do |f| %>
+<%= translatable_form_for [namespace, budget], html: { class: "budgets-form" } do |f| %>
|