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| %>
<%= t("admin.budgets.edit.info.budget_settings") %> <%= render "shared/globalize_locales", resource: budget %> @@ -37,17 +37,16 @@ <%= render "/admin/budgets/association", assignable_type: "valuators", assignables: valuators, form: f %>
-
- <%= t("admin.budgets.edit.info.phases_settings") %> -
- <%= f.select :phase, phases_select_options %> -
- - <%= render Admin::Budgets::HelpComponent.new("budget_phases") %> - <%= render Admin::BudgetPhases::PhasesComponent.new(budget) %> -
- <% if budget.persisted? %> +
+ <%= t("admin.budgets.edit.info.phases_settings") %> +
+ <%= f.select :phase, phases_select_options %> +
+ + <%= render Admin::BudgetPhases::PhasesComponent.new(budget) %> +
+ <%= 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 @@ +
    +
  1. + <%= t("admin.budgets_wizard.creation_timeline.budget") %> +
  2. +
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