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..539abe84c
--- /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 $admin-border-color;
+ display: inline-block;
+ font-size: $small-font-size;
+ font-weight: bold;
+ padding: $line-height / 2 $line-height * 3 0;
+ text-transform: uppercase;
+
+ &::before {
+ background: $admin-border-color;
+ border-radius: 50%;
+ content: "";
+ height: 20px;
+ margin-left: $line-height / 2;
+ position: absolute;
+ top: -8px;
+ width: 20px;
+ }
+
+ &[aria-current] {
+ border-color: $brand;
+
+ &::before {
+ background: $brand;
+ }
+ }
+ }
+}
diff --git a/app/components/admin/budgets/form_component.html.erb b/app/components/admin/budgets/form_component.html.erb
index 3391bc6f7..64159594f 100644
--- a/app/components/admin/budgets/form_component.html.erb
+++ b/app/components/admin/budgets/form_component.html.erb
@@ -1,4 +1,4 @@
-<%= translatable_form_for [:admin, budget], html: { class: "budgets-form" } do |f| %>
+<%= translatable_form_for [namespace, budget], html: { class: "budgets-form" } do |f| %>
-
-
<% if budget.persisted? %>
+
+
<%= render "admin/shared/show_results_fields", form: f %>
<% end %>
diff --git a/app/components/admin/budgets/form_component.rb b/app/components/admin/budgets/form_component.rb
index 93752cefc..cb6c3344a 100644
--- a/app/components/admin/budgets/form_component.rb
+++ b/app/components/admin/budgets/form_component.rb
@@ -12,6 +12,14 @@ class Admin::Budgets::FormComponent < ApplicationComponent
@budget = budget
end
+ def namespace
+ if controller.class.name.starts_with?("Admin::BudgetsWizard")
+ :admin_budgets_wizard
+ else
+ helpers.namespace.to_sym
+ end
+ end
+
def voting_styles_select_options
Budget::VOTING_STYLES.map do |style|
[Budget.human_attribute_name("voting_style_#{style}"), style]
diff --git a/app/components/admin/budgets/index_component.html.erb b/app/components/admin/budgets/index_component.html.erb
index feb881352..35e6fce7f 100644
--- a/app/components/admin/budgets/index_component.html.erb
+++ b/app/components/admin/budgets/index_component.html.erb
@@ -1,5 +1,5 @@
<%= header do %>
- <%= link_to t("admin.budgets.index.new_link"), new_admin_budget_path %>
+ <%= link_to t("admin.budgets.index.new_link"), new_admin_budgets_wizard_budget_path %>
<% end %>
<%= render Admin::Budgets::HelpComponent.new("budgets") %>
diff --git a/app/components/admin/budgets_wizard/budgets/new_component.html.erb b/app/components/admin/budgets_wizard/budgets/new_component.html.erb
new file mode 100644
index 000000000..e2e227928
--- /dev/null
+++ b/app/components/admin/budgets_wizard/budgets/new_component.html.erb
@@ -0,0 +1,6 @@
+<%= back_link_to admin_budgets_path %>
+
+<%= header %>
+
+<%= render Admin::BudgetsWizard::CreationTimelineComponent.new %>
+<%= render Admin::Budgets::FormComponent.new(budget) %>
diff --git a/app/components/admin/budgets_wizard/budgets/new_component.rb b/app/components/admin/budgets_wizard/budgets/new_component.rb
new file mode 100644
index 000000000..09502de89
--- /dev/null
+++ b/app/components/admin/budgets_wizard/budgets/new_component.rb
@@ -0,0 +1,12 @@
+class Admin::BudgetsWizard::Budgets::NewComponent < ApplicationComponent
+ include Header
+ attr_reader :budget
+
+ def initialize(budget)
+ @budget = budget
+ end
+
+ def title
+ t("admin.budgets.new.title")
+ end
+end
diff --git a/app/components/admin/budgets_wizard/creation_timeline_component.html.erb b/app/components/admin/budgets_wizard/creation_timeline_component.html.erb
new file mode 100644
index 000000000..3a566c277
--- /dev/null
+++ b/app/components/admin/budgets_wizard/creation_timeline_component.html.erb
@@ -0,0 +1,5 @@
+
+ -
+ <%= t("admin.budgets_wizard.creation_timeline.budget") %>
+
+
diff --git a/app/components/admin/budgets_wizard/creation_timeline_component.rb b/app/components/admin/budgets_wizard/creation_timeline_component.rb
new file mode 100644
index 000000000..47e5a4d2a
--- /dev/null
+++ b/app/components/admin/budgets_wizard/creation_timeline_component.rb
@@ -0,0 +1,2 @@
+class Admin::BudgetsWizard::CreationTimelineComponent < ApplicationComponent
+end
diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb
index a35396342..572d55fc1 100644
--- a/app/controllers/admin/budgets_controller.rb
+++ b/app/controllers/admin/budgets_controller.rb
@@ -6,7 +6,7 @@ class Admin::BudgetsController < Admin::BaseController
has_filters %w[all open finished], only: :index
- before_action :load_budget, except: [:index, :new, :create]
+ before_action :load_budget, except: [:index]
load_and_authorize_resource
def index
@@ -17,9 +17,6 @@ class Admin::BudgetsController < Admin::BaseController
render :edit
end
- def new
- end
-
def edit
end
@@ -46,15 +43,6 @@ class Admin::BudgetsController < Admin::BaseController
end
end
- def create
- @budget = Budget.new(budget_params.merge(published: false))
- if @budget.save
- redirect_to edit_admin_budget_path(@budget), notice: t("admin.budgets.create.notice")
- else
- render :new
- end
- end
-
def destroy
if @budget.investments.any?
redirect_to admin_budgets_path, alert: t("admin.budgets.destroy.unable_notice")
diff --git a/app/controllers/admin/budgets_wizard/budgets_controller.rb b/app/controllers/admin/budgets_wizard/budgets_controller.rb
new file mode 100644
index 000000000..1efb41379
--- /dev/null
+++ b/app/controllers/admin/budgets_wizard/budgets_controller.rb
@@ -0,0 +1,32 @@
+class Admin::BudgetsWizard::BudgetsController < Admin::BaseController
+ include Translatable
+ include FeatureFlags
+ feature_flag :budgets
+
+ load_and_authorize_resource
+
+ def new
+ end
+
+ def create
+ @budget.published = false
+
+ if @budget.save
+ redirect_to edit_admin_budget_path(@budget), notice: t("admin.budgets.create.notice")
+ else
+ render :new
+ end
+ end
+
+ private
+
+ def budget_params
+ params.require(:budget).permit(*allowed_params)
+ end
+
+ def allowed_params
+ valid_attributes = [:currency_symbol, :voting_style, administrator_ids: [], valuator_ids: []]
+
+ valid_attributes + [translation_params(Budget)]
+ end
+end
diff --git a/app/views/admin/budgets/new.html.erb b/app/views/admin/budgets/new.html.erb
deleted file mode 100644
index 90d802424..000000000
--- a/app/views/admin/budgets/new.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-<%= back_link_to admin_budgets_path %>
-
-
- <%= t("admin.budgets.new.title") %>
-
-
-<%= render Admin::Budgets::FormComponent.new(@budget) %>
diff --git a/app/views/admin/budgets_wizard/budgets/new.html.erb b/app/views/admin/budgets_wizard/budgets/new.html.erb
new file mode 100644
index 000000000..6ebfd4521
--- /dev/null
+++ b/app/views/admin/budgets_wizard/budgets/new.html.erb
@@ -0,0 +1 @@
+<%= render Admin::BudgetsWizard::Budgets::NewComponent.new(@budget) %>
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index e0f3f20ca..4f459b453 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -284,6 +284,9 @@ en:
tags_placeholder: "Write the tags you want separated by commas (,)"
undefined: Undefined
search_unfeasible: Search unfeasible
+ budgets_wizard:
+ creation_timeline:
+ budget: Budget
milestones:
index:
table_id: "ID"
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index 3e6db5a74..89cd99119 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -284,6 +284,9 @@ es:
tags_placeholder: "Escribe las etiquetas que desees separadas por comas (,)"
undefined: Sin definir
search_unfeasible: Buscar inviables
+ budgets_wizard:
+ creation_timeline:
+ budget: Presupuesto
milestones:
index:
table_id: "ID"
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 21712e04a..23cd9867a 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -51,7 +51,7 @@ namespace :admin do
end
end
- resources :budgets do
+ resources :budgets, except: [:create, :new] do
member do
patch :publish
put :calculate_winners
@@ -72,6 +72,10 @@ namespace :admin do
resources :budget_phases, only: [:edit, :update]
end
+ namespace :budgets_wizard do
+ resources :budgets, only: [:create, :new]
+ end
+
resources :milestone_statuses, only: [:index, :new, :create, :update, :edit, :destroy]
resources :signature_sheets, only: [:index, :new, :create, :show]
diff --git a/spec/system/admin/budgets_spec.rb b/spec/system/admin/budgets_spec.rb
index e6a5ab6a4..50f8c3de8 100644
--- a/spec/system/admin/budgets_spec.rb
+++ b/spec/system/admin/budgets_spec.rb
@@ -84,88 +84,6 @@ describe "Admin budgets", :admin do
end
end
- context "New" do
- scenario "Create budget - Knapsack voting (default)" do
- visit admin_budgets_path
- click_link "Create new budget"
-
- fill_in "Name", with: "M30 - Summer campaign"
- select "Accepting projects", from: "budget[phase]"
-
- click_button "Create Budget"
-
- expect(page).to have_content "New participatory budget created successfully!"
- expect(page).to have_field "Name", with: "M30 - Summer campaign"
- expect(page).to have_select "Final voting style", selected: "Knapsack"
- end
-
- scenario "Create budget - Approval voting" do
- admin = Administrator.first
-
- visit admin_budgets_path
- click_link "Create new budget"
-
- fill_in "Name", with: "M30 - Summer campaign"
- select "Accepting projects", from: "budget[phase]"
- select "Approval", from: "Final voting style"
- click_button "Create Budget"
-
- expect(page).to have_content "New participatory budget created successfully!"
- expect(page).to have_field "Name", with: "M30 - Summer campaign"
- expect(page).to have_select "Final voting style", selected: "Approval"
-
- click_link "Select administrators"
-
- expect(page).to have_field admin.name
- end
-
- scenario "Name is mandatory" do
- visit new_admin_budget_path
- click_button "Create Budget"
-
- expect(page).not_to have_content "New participatory budget created successfully!"
- expect(page).to have_css(".is-invalid-label", text: "Name")
- end
-
- scenario "Name should be unique" do
- create(:budget, name: "Existing Name")
-
- visit new_admin_budget_path
- fill_in "Name", with: "Existing Name"
- click_button "Create Budget"
-
- expect(page).not_to have_content "New participatory budget created successfully!"
- expect(page).to have_css(".is-invalid-label", text: "Name")
- expect(page).to have_css("small.form-error", text: "has already been taken")
- end
-
- scenario "Do not show results and stats settings on new budget" do
- visit new_admin_budget_path
-
- expect(page).not_to have_content "Show results and stats"
- expect(page).not_to have_field "Show results"
- expect(page).not_to have_field "Show stats"
- expect(page).not_to have_field "Show advanced stats"
- end
- end
-
- context "Create" do
- scenario "A new budget is always created in draft mode" do
- visit admin_budgets_path
- click_link "Create new budget"
-
- fill_in "Name", with: "M30 - Summer campaign"
- select "Accepting projects", from: "budget[phase]"
-
- click_button "Create Budget"
-
- expect(page).to have_content "New participatory budget created successfully!"
- expect(page).to have_content "This participatory budget is in draft mode"
- expect(page).to have_link "Preview budget"
- expect(page).to have_link "Publish budget"
- end
- end
-
context "Publish" do
let(:budget) { create(:budget, :drafting) }
diff --git a/spec/system/admin/budgets_wizard/budgets_spec.rb b/spec/system/admin/budgets_wizard/budgets_spec.rb
new file mode 100644
index 000000000..13cb9a75d
--- /dev/null
+++ b/spec/system/admin/budgets_wizard/budgets_spec.rb
@@ -0,0 +1,82 @@
+require "rails_helper"
+
+describe "Budgets wizard, first step", :admin do
+ describe "New" do
+ scenario "Create budget - Knapsack voting (default)" do
+ visit admin_budgets_path
+ click_link "Create new budget"
+
+ fill_in "Name", with: "M30 - Summer campaign"
+ click_button "Create Budget"
+
+ expect(page).to have_content "New participatory budget created successfully!"
+ expect(page).to have_field "Name", with: "M30 - Summer campaign"
+ expect(page).to have_select "Final voting style", selected: "Knapsack"
+ end
+
+ scenario "Create budget - Approval voting" do
+ admin = Administrator.first
+
+ visit admin_budgets_path
+ click_link "Create new budget"
+
+ fill_in "Name", with: "M30 - Summer campaign"
+ select "Approval", from: "Final voting style"
+ click_button "Create Budget"
+
+ expect(page).to have_content "New participatory budget created successfully!"
+ expect(page).to have_field "Name", with: "M30 - Summer campaign"
+ expect(page).to have_select "Final voting style", selected: "Approval"
+
+ click_link "Select administrators"
+
+ expect(page).to have_field admin.name
+ end
+
+ scenario "Submit the form with errors" do
+ visit new_admin_budgets_wizard_budget_path
+ click_button "Create Budget"
+
+ expect(page).not_to have_content "New participatory budget created successfully!"
+ expect(page).to have_css ".is-invalid-label", text: "Name"
+ expect(page).to have_css ".creation-timeline"
+ end
+
+ scenario "Name should be unique" do
+ create(:budget, name: "Existing Name")
+
+ visit new_admin_budgets_wizard_budget_path
+ fill_in "Name", with: "Existing Name"
+ click_button "Create Budget"
+
+ expect(page).not_to have_content "New participatory budget created successfully!"
+ expect(page).to have_css(".is-invalid-label", text: "Name")
+ expect(page).to have_css("small.form-error", text: "has already been taken")
+ end
+
+ scenario "Do not show results and stats settings on new budget" do
+ visit new_admin_budgets_wizard_budget_path
+
+ expect(page).not_to have_content "Show results and stats"
+ expect(page).not_to have_field "Show results"
+ expect(page).not_to have_field "Show stats"
+ expect(page).not_to have_field "Show advanced stats"
+ end
+ end
+
+ describe "Create" do
+ scenario "A new budget is always created in draft mode" do
+ visit admin_budgets_path
+ click_link "Create new budget"
+
+ fill_in "Name", with: "M30 - Summer campaign"
+
+ click_button "Create Budget"
+
+ expect(page).to have_content "New participatory budget created successfully!"
+ expect(page).to have_content "This participatory budget is in draft mode"
+ expect(page).to have_link "Preview budget"
+ expect(page).to have_link "Publish budget"
+ end
+ end
+end